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
netty: change default transport to Epoll if available, otherwise using Nio #5581
Conversation
…current default Nio
i am not sure why gradle spotless plugin starts to complain about gradle build file. one of the gradle file had indentation issue due to using tab. resolved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline, let's detect when users fail to specify all of channelType/worker/boss and issue a warning and fallback to using nio. In the future we will throw in build() when that happens.
Class | ||
.forName("io.netty.channel.epoll.EpollServerSocketChannel") | ||
.asSubclass(ServerChannel.class); | ||
logger.log(Level.FINE, "Using EpollServerSocketChannel"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this log? It seems a bit weird in this context.
logger.log(Level.FINE, "Epoll is not available", getEpollUnavailabilityCause()); | ||
} | ||
return available; | ||
} catch (Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ClassNotFound should probably be special-cased, since that is quite normal (although it would still be fair to log it at FINE). Otherwise this exception should be logged, probably at WARNING.
logger.log( | ||
Level.WARNING, | ||
"Both EventLoopGroup and ChannelType should be provided, otherwise client may not start " | ||
+ "depends on the gRPC default value."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sentence is broken between "start" and "depends".
Include in the message that we are falling back to Nio for compatibility, and that this will cause an exception in the future.
+ "depends on the gRPC default value."); | ||
|
||
if (eventLoopGroup == null) { | ||
eventLoopGroup = SharedResourceHolder.get(Utils.NIO_WORKER_EVENT_LOOP_GROUP); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be mutating the builder. That can cause quite a bit of confusion if build()
is called twice. For example, the way this code is, the second call to build() would not acquire a reference to the event loop and so it may be shut down while still in use.
|
||
if (eventLoopGroup == null) { | ||
eventLoopGroup = SharedResourceHolder.get(Utils.NIO_WORKER_EVENT_LOOP_GROUP); | ||
logger.log(Level.FINE, String.format("Using fall back EventLoopGroup %s", eventLoopGroup)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will always call String.format(), even if not logging at FINE level. That should be avoided. Ditto next log.
@@ -108,17 +107,17 @@ | |||
long maxConnectionIdleInNanos, | |||
long maxConnectionAgeInNanos, long maxConnectionAgeGraceInNanos, | |||
boolean permitKeepAliveWithoutCalls, long permitKeepAliveTimeInNanos, | |||
InternalChannelz channelz) { | |||
InternalChannelz channelz, boolean usingSharedBossGroup, boolean usingSharedWorkerGroup) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having these bools passed in this deep can be sort of annoying. You may consider passing in ObjectPools instead. That way this code wouldn't need any conditionals and some of the handling elsewhere looks like it would improve.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. it looks much simpler
Suggestion: Why not just have a fixed runtime dependency on
An additional minor benefit would be to remove the need for reflection. Also, there is no harm in this being there if they are running on non linux-x84_64 platforms. In fact as questioned a while back, using the os selector for this in the build seems incorrect - the build env in general is arbitrary in relation to the runtime platform. |
@njhill, hmm... We were thinking most users should be using I agree that it may make sense to depend on native-epoll for the Java classes. And I didn't realize the native transport was so small. Although we may also want kqueue support. It seems both of them depend on netty-unix-common, which is fairly small. There's no "uber" jar for it though. It looks like the linux/osx versions of netty-unix-common isn't for normal use, because it only contains a Hmm... I'm not sure how Maven/Gradle handle mixing dependencies with different classifiers. I think I'm favoring this current more conservative approach for the moment. We've seen small performance gains from epoll; we're mainly doing this for better socket option support when available, like TCP_USER_TIMEOUT. Once we see the world doesn't fall over, we might make it a stronger dependency; and go through the effort of making sure Maven/Gradle will behave in a useful way. |
@creamsoup, labeling this PR as "all" seems misleading. There's literally a single line that isn't in the The PR should also include some sort of description as to why it is being made. |
@creamsoup, @njhill brought up a good point about auto-detection logic. We don't want any auto-detection logic for our epoll dependency from grpc-netty-shaded. We can probably just always use the "linux-x86_64" classifier; see the main build.gradle. |
@ejona86 So I think it wouldn't cause problems to similarly depend on kqueue in addition to epoll (no problem having diff classifiers for diff artifacts), though I would expect it's rarer for performance to be such a concern in macos contexts. |
@njhill, My bringing up of Kqueue is that it is another "useless dependency" for certain people. It's also small, though. Such small unnecessary dependencies could potentially add up, but they do seem minor compared to the rest of the netty artifacts (gosh it is big). |
@ejona86 apologies, you are right. But yes doesn't seem they are used at runtime. |
@njhill, I may not have made it clear: I'm really happy you pointed out that the epoll jars were small. Although we'll use reflection for the moment and we need to do some more research into Maven/Guava behavior, I will likely try to swap us to a strong dependency in the future to avoid the reflection. |
Motivation:
To support TCP_USER_TIMEOUT(proposal). Nio doesn't support TCP_USER_TIMEOUT while Epoll and KQueue supports TCP_USER_TIME. Since most users/servers are using linux based system, adding Epoll is necessary. KQueue maybe supported later, but not in this PR.
To make it backward compatible, for cases when channelType or eventLoop is mixed in with default and user provided object(s). We will fallback to Nio when not all the values (channelType, eventLoop) are provided. Which should be same as current behavior. In later version (possibly 1.22.0) will throw exception since this is error prone.