-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Non blocking server impl and recommended usage of Server.directExecutor() #5185
Comments
If you are really sure there is no blocking in your app code, and you know it your app handlers finish up quickly, directExecutor is okay. Let me cast doubt on your certainty:
The thing is, unless you can prove (typically because your application code is trivial) there is no blocking, it probably is. It probably has some blocking that you aren't aware of, and can lead to starvation. Note that I am using the concurrency definition of blocking, rather than the colloquial meaning, which is less well defined. This is why we say it's dangerous. Unless you have prior knowledge it isn't safe. In the best case, one thread just stalls the others from making progressm increasing latency. In the worst case, it deadlocks. |
I think to an even better point, even if I could prove my certainty it doesnt mean that consumers of my library are going to be diligent enough to ensure they dont block as well. My current implementation dispatches the actual service method invocation to a separate executor Thanks @carl-mastrangelo for all your input! |
SG @marcoferrer . One other note for future readers: class loading always involves locks, and has bitten me more than once. It's surreptitious because it's invisible in the source code, but all over the place in the JVM. |
What version of gRPC are you using?
1.15.1
Ive been building a non blocking implementation for kotlin coroutines on top of grpc-java. Similar to the
reactive-grpc
project. (marcoferrer/kroto-plus#16 & Kotlin/kotlinx.coroutines#360)Im having a hard time finding the preferred / best practices for configuring a non blocking server.
When configuring the executor for the server, some sources point to using a
directExecutor
while others recommend using aForkJoinPool
. Based on related discussions, it seems the former has the possibility of being unsafe?I ran a benchmark on a coroutine base port of the existing benchmark service.
The results were in favor of using directExecutor over a forkJoinPool, but if directExecutor is considered unsafe Id rather live with decreased QPS. Another reason why Im looking for clarification is because Id like be able to outline the recommended configurations in my projects documentation.
QPS Benchmarks
Unary Test Args:
Server Executor: ForkJoinPool(parallelism = 4)
Server Executor: directExecutor()
Client Executor: directExecutor() & Server Executor: directExecutor()
Streaming Test Args:
Server Executor: ForkJoinPool(parallelism = 4)
Server Executor: directExecutor()
Client Executor: directExecutor() & Server Executor: directExecutor()
The text was updated successfully, but these errors were encountered: