A Case for Asynchronous Non Blocking JDBC — Part One
Background
This is a three part series
- Part One — This page
- Part Two — Click on the link
- Part Three — Early 2021 Update
Blocking code is the bane of modern software.
Blocking code needs more resources in terms of CPU cycles and Memory usage, which in turn increases cost to run the code.
Sections on this page
- We will try and understand non blocking calls
- We will try and understand the importance of event based systems and how they could assist in making non blocking calls
Section 1 :Blocking/Asynchronous/Asynchronous-Non-Blocking Calls
Aspects used in the diagrams for this section
- Java is our the language of choice
- We are using Java threads in our code
- Write Methods are Green(Asynchronous) and Red(Synchronous)
- Blue Methods are simple Java methods which do not block
Blocking Call
Logical Diagram
Explanation
The below are our logical steps
- The Save method calls a Write method
- The Write method does a blocking call — say a write to disk
- The Thread now blocks till the write to disk is completed
- The Thread resumes after the blocking call returns
- It then calls the Notify method
Asynchronous Call
Logical Diagram
Explanation
The below are our logical steps
- The Save method calls a Write method which Wraps a Asynchronous call
- The Write Wrap method uses an Executor which spawns a new thread for writing to disk — see Appendix-1
- The new Thread now blocks till the write to disk is completed
- The Main Thread which did the save does not block and can perform other processes
- The new thread returns when the blocking call is completed and it calls the Notify Method
Asynchronous Non Blocking Call
Logical Diagram
Explanation
The below are our logical steps
- The Save method calls a Write method which uses Java NIO
- The Non Blocking call does not block the main Thread see Appendix-2
- The Non Blocking Write method now blocks till the write to disk is completed
- The Main Thread which did the save does not block and can perform other processes
- The non blocking method returns when the non-blocking call is completed and it calls the Notify Method
Conclusion
Blocking Call
- Blocking call should not be needed in today’s world.
- If we absolutely need a blocking call, we need clear justifications for the same.
- For example, as of today, a JDBC call to an JDBC database is a blocking call.
- Having said that a new JDC SQL2 package is being worked on, See Appendix-3
Asynchronous Call
- Making a Blocking call Asynchronous, by spawning a new Thread is a great way of not blocking the main thread
- It can help if the blocking call, now wrapped in a new Thread, is short lived
- However if the blocking call is not short lived, we could soon get into a Thread starvation issue in the JVM, See Appendix-4
- In the old world of monoliths, where say we have a lot of CPU and RAM resources, we could get into the issue after a certain time of running an application. Not Good to see the application hanging suddenly.
- In our new world, of microservices this problem may get worse depending on our deployment model.
- This is due to the fact that we have many small Java services. Each service has a clear responsibility and is deployed to, say a Kubernetes POD.
- Each POD generally has limited RAM and CPU resources per POD, See Appendix-5
- Hence this is not a good solution and in my view, we must avoid blocking calls as far as possible.
Non Blocking Call
- As seen a non blocking call does not block any threads in the system
- Java NIO has been out since JDK1.4 and works well
- There are many ways in Java to write non blocking code, See Appendix-6
- Asynchronous code may needs a bit of getting used to as it may not be strictly sequential.
Remote Procedure Calls vs Messaging/Events Service calls
Aspects used in the diagrams for this section
- A Service does one Job
- This is not a coding language specific section, applies to all languages
Direct Remote Procedure call
Logical Diagram RPC two Services
Explanation
- As seen above Service One does an RPC(Remote Procedure call) to Service Two
- Service Two does some processing sends a response back to Service One
- By its very nature, this is a synchronous call
- Hence Service One waits for a response
- This could be based on low level sockets with a custom protocol or it could be HTTP/REST as a protocol, or some other protocol
- It is assumed, Service One and Service Two are tightly coupled and must understand each other
Logical Diagram RPC two Services timeout
Explanation
- As seen, in the use case of no Response must be coded in Service One
- It could be due to Service Two is down, Service Two had an unexpected error or there is a network issue
Logical Diagram RPC many Services
Explanation
- What if there were other services which also needed data from our Service One
- When there are RPC based calls between many services, now our Service One has more work to do, as it has to deal with Synchronous requests and timeouts for each service interface it calls
Conclusion — RPC
- The problem here is tight coupling between the Services
- It lends itself to be used in a synchronous fashion as it is in essence a blocking call.
- Not saying it will be always a blocking call in our code. However it is easy to see why it could be easily thought of as a blocking call and thus coded in a synchronous fashion.
Queue based Events
Logical Diagram
Explanation
- As seen above Service “Publishes” a message on Queue X.
- Any services interested in that message “Subscribe” to the messages from Queue X
- Service Four “Publishes” a message on Queue Y, based on the message from Queue X.
- Service One is interested in that message and hence “Subscribes” to messages in Queue Y
Conclusion — Messaging
- There is no tight coupling between the Services
- Each service fires a message to a queue can can get on with other work it has to perform
- It lends itself to be used in a asynchronous fashion as it is in essence a non-blocking call.
- Not saying it will be always a non-blocking call in our code. However it is easy to see why it could be easily thought of as a non-blocking call and thus coded in a asynchronous fashion.
- There are many other advantages due to decoupling of service calls, some of them being, services can be developed independently, tested independently, when the services are running, they can now react to each others messaging and hence building a Reactive System is easier. See Appendix-7
Erlang Events
Erlang is a great highly concurrent language from Ericsson.
Please do read up on concurrency in Erlang. See Appendix-8 . The first bits of the page are a great way to know how Events are at the core of the Erlang way of doing things.
If you are a bit braver you could even try and code the whole tutorial :-)
Akka Actors and Events
Akka is very much inspired from Erlang. It runs on the JVM and supports Scala and Java.
See Appendix-9 . It is a bit longish, however worth the time invest to watch and understand a Message(event) based Actor system.
Next Steps
We will read up on JDBC and see why making it non-blocking might help.
Appendices
Appendix-1 — Java Executors
Appendix-2 — Java NIO
Appendix-3 — JDBC SQL2
Appendix-4 — Thread Starvation
Appendix-5 — Java Microservices on Kubernetes
Appendix-6 — Java Non-Blocking Algorithms
Appendix-7 — Martin Fowler Event Driven Systems
Appendix-8 — Erlang Actors
Appendix-9 — Akka Actor and Events