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
Epoll consuming lot more CPU than Nio #11695
Comments
More information needed. |
@hyperxpro I have added some code. Please let me know if anything specific info would help. |
@praveen97uma eg |
@franz1981 Yes, The ramp up to 27K connections is same for both NIO and EPOLL. The graph I shared are in steady state after the ramp up with nothing being written to the connections, except the websocket ping/pongs every 5 sec, which again happens for both the transports. |
It would worth to capture some profiling using https://github.com/jvm-profiling-tools/async-profiler
And share the flamegraphs (
if you don't suppose to block on the event loop, why not using 8 worker threads (or less?) |
@franz1981 @hyperxpro Here are the files. Profiled for 30s. https://raw.githubusercontent.com/praveen97uma/experiments/main/epoll.html Screenshots of the same files if convenient. |
there are an insane amount of samples on epollWait0 due to timerset. Another thing: I won't suggest to set affinity with netty threads > number of cores...is a BAD idea :)
|
Also, try this: |
Good point, it could be that wakeup is spuriously happening (each time, so not so "spuriously") or that there are scheduled tasks that cause epoll to awake and go asleep continuosly |
@franz1981 @hyperxpro Thank you both for the help . So, I am doing the following changes and will keep you guys posted.
|
@franz1981 I made the changes. The CPU has dropped to 40% but, IMO, it is still high. |
It's still too much time... |
I have scheduled tasks which run at every 200ms to consume messages from a buffer queue for that connection and push to the client. This is scheduled on the channel's event executor itself. That is the cause of all this I guess then. @franz1981 |
yeah, probably rescheduling it is a bit more costy with epoll, or it could be due to the hypervised env you run the app, according to the flamegraphs it doesn't seem a bare metal server no? Maybe I'm wrong :) |
Are you running the program on Shared-CPU VM or Bare Metal? |
Its not a bare metal but Azure's VM. These are virtual CPUs. |
@praveen97uma can you upload the flame graph so we can navigate in it ? It seems it spend quite some time on |
@normanmaurer It looks to me that due to the too tight period of the scheduled tasks (for that virtual env) epoll always find some new scheduled task to rearm, causing that method to be called too much. if (curDeadlineNanos == prevDeadlineNanos) {
// No timer activity needed
strategy = epollWaitNoTimerChange();
} else {
// Timerfd needs to be re-armed or disarmed
prevDeadlineNanos = curDeadlineNanos;
strategy = epollWait(curDeadlineNanos);
} on |
@normanmaurer Here is the flame graph(updated). https://raw.githubusercontent.com/praveen97uma/experiments/main/epoll.html |
@normanmaurer @franz1981 @hyperxpro Guys, so ByteBuf.duplicate() creates a new UnpooledDuplicatedByteBuf(). Is it possible to let netty create a Pooled version of the bytebuf? This particular call is causing the highest allocations in my profiling. |
@praveen97uma if you use the |
@praveen97uma also can you explain why and how you schedule so many tasks ? |
@normanmaurer We had to batch push messages over the connection every 200ms. These msgs are merged in a specific structure to reduce bytes on the wire. I have a buffer queue for every connection and tasks are scheduled for every connection on the eventloops that do this batching and flush over the connection. Is this entirely wrong approach and is there a better way to do this in some other way in netty? Had read about FlushConsolidationHandler but not sure if there is a hook that I can use to do the merging I want to do before flushing. I am using PolledByteBufAllocator.
ServerPublishOperation is a ByteBufHolder. Channel's alloc is passed to the above function. |
I see... If you switch to |
If you keep track of your connections (ideally just the ones with messages), you could have a single task scheduled, that go over all current connections and process their batches. |
+1 .. may be not a single task but a single task per eventloop so that you do not have to jump the eventloop for flushing the connection. |
I wonder if the time used by |
Only using |
Let me put this on my todo list... |
@praveen97uma I think this should improve things: #12145 |
…uts are scheduled Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
…uts are scheduled Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
…uts are scheduled(#12145) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
…uts are scheduled(#12145) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695
Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695
) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes #14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes #14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes #14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes #14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…uts are scheduled(#12145) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
… are scheduled (#12196) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes #11695
…uts are scheduled(netty#12145) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes netty#11695
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…che#15212) * Upgrade Netty to 4.1.76.Final and Netty Tcnative to 2.0.51.Final Fixes apache#14015 - release notes https://netty.io/news/2022/04/12/4-1-76-Final.html - contains fix for netty/netty#11695 * Upgrade grpc to 1.45.1 and protobuf to 3.19.2 - grpc < 1.45.1 is not compatible with Netty > 4.1.74.Final - grpc/grpc-java#9004 (cherry picked from commit 332a3c7)
…uts are scheduled(netty#12145) Motivation: At the moment we might end up calling timerfd_settime everytime a new timer is scheduled. This can produce quite some overhead. We should try to reduce the number of syscalls when possible. Modifications: - If we are using Linux Kernel >= 5.11 use directly epoll_pwait2(...) - If the scheduled timeout is big enough just use epoll_wait(...) without timerfd_settime and accept some inaccuracy. Result: Fixes netty#11695
I am building a websocket based broker. During load testing, we found that Epoll transport uses around 55% CPU compared to around 20% for Nio, just for maintaining the connections without doing any business specific IO on those connections. Is this expected? What could I be doing wrong? Happy to share any more info required around this.
Total concurrent connections: Around 27K
Boss Threads: 1
Worker Threads: 32
Cores in the VM: 8
Relevant code that sets up netty.
Netty version
4.1.68
JVM version (e.g.
java -version
)openjdk version "11.0.12" 2021-07-20 LTS
OpenJDK Runtime Environment Zulu11.50+19-CA (build 11.0.12+7-LTS)
OpenJDK 64-Bit Server VM Zulu11.50+19-CA (build 11.0.12+7-LTS, mixed mode)
OS version (e.g.
uname -a
)Linux bolt-004 5.8.0-1041-azure #44~20.04.1-Ubuntu SMP Fri Aug 20 20:41:09 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
Epoll
Nio
The text was updated successfully, but these errors were encountered: