Question

Lately I've started learning about reactive, event-driven, non-blocking Java frameworks and there is one that caught my eye - vert.x.

I guess the same question may apply to akka (Play framework) 'cause their philosophy or one of the goals is the same - and that is reducing thread number and therefore highering scalability of an application.

vert.x suggests that number of threads it consumes is ~equivalent to the number of CPU cores but it also bares in mind that sometimes you have to do a blocking operation so it encourages a developer to perform a blocking operation on a seperate working thread (worker vertical in terms of vert.x).

And that's where we come to my question:

  • if I'm supposed to perform blocking IO operations on a new separate thread that means that every user that does a blocking operation has a new thread and therefore number of threads again becomes equal to the number of users as in a classical blocking thread model?

A real example would be a JDBC query - if 1000 concurrent users query a SQL database via JDBC every user spawns it's own worker thread for that blocking operation. From my point of view there's no thread sparing, improved scalability or RAM sparing compared to classical blocking thread model. I must be missing something... Or not? Thank's in advance for all the answers.

Was it helpful?

Solution

There is no sense to spawn 1000 concurrent threads queryng an SQL database - just because typical database cannot bear so many simultaneous connections, typical number is 10-15. The solution is to organize a special thread pool, where each thread has an open connection and serves tasks which access database. Tasks are submitted to a common blocking queue, and working threads read from that queue in a loop. Tasks are instances of

interface DBRunnable {
  public void run(Connection conn);
}

working threads pass their connection to the tasks:

public void run() {
  Connection conn = DriverManager.getConnection(...);
  while (true) {
     DBRunnable task=queue.take();
     task.run(conn);
  }
}

OTHER TIPS

vert.x suggest in terms of running threads on a machine and not in terms of users.

What they are saying is that if you have 16 CPU cores available and have 16 ready-to-work threads, then if you run a blocking operation on 1 of them, only 15 threads remain working at most and thus only 15 of your CPU cores are actually working. 1 of your cores is just waiting!

So to prevent having one idle core, they advice you to create one more thread and give it the blocking task so you still have 16 threads working on your 16 CPU cores.

The number of blocking threads is not really important (as long as it is not too large...) since they actually do not consume much of your CPU power.

It is different from usual blocking model because you isolated the blocking operations that do not require much resources on your side. What is left is sharing the remaining event-driven operations among the working threads you have.

As said before you should use a connection pool, however if you're interested in database access rather than specifically JDBC you could look at async db drivers such as:

These drivers rely on netty so all its IO operations are non blocking, which means you don't need to have worker thread pools. Less threads means less context switching at the OS level which brings better performance.

Sadly there aren't many of these drivers around (I'm only aware for MySQL and PostgreSQL) so if you're forced to work with other RDBMS you might be out of luck.

As others have suggested, please look into the async drivers for mysql and postgres, both which have a client specially made for vert.x. These 2 databases cover most use cases for a RDMS.

Another non-blocking option is MongoDB, which has a tailored non-blocking vert.x client. Works great, but ofcourse not SQL.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top