4 ms·
An ordinary Comet server with long-poll can actually end up eating quite some CPU. I run beaconpush.com which is a cloud-based service for browser push message
by cgbystrom 16y ago
An ordinary Comet server with long-poll can actually end up eating quite some CPU.
I run beaconpush.com which is a cloud-based service for browser push messages. We're based on Netty and Java, which works out well for us. We've looked at Erlang and wrote some initial prototypes in it but Java became our language of choice. Mainly because we knew it and had some experiences with Netty, a NIO library for Java. Netty did also outperform Erlang and mochiweb (both vanilla configured).
Anyway, the problem tend to be with long-poll that users re-establish their connection back to the servers each time they receive a message or navigate to another page (or reload the page).
This end up taking a big toll on the system. We're to some extent limited to how fast we can perform accept() on our sockets.
If you use long-polling with multi-part you can get away with sending more messages on a single established connection (it becomes request/response/response/response or similar). That can reduce the system load and the use of WebSockets can eliminate the use of reconnections altogether (disregarding any page reloads).
Facebook's use of AJAX navigation (i.e not reloading the entire page when user clicks on links etc) also reduces this load. This due to not having to re-establish a connection each time a user reloads a page.
So yes, we're actually CPU bound by the accept() behavior (at least to how the JVM does accept()). But would our connection be more permanent in nature then no, we would of course be more I/O bound if not completely.
- axod 16y agoI'd do some more in depth checks. I find it very hard to believe you're cpu bound within NIO itself. I do around 1k req/s per cpu and never see load avg above 0.5 >> "re-establish their connection back to the servers each time they receive a message or navigate to another page (or reload the page). This end up taking a big toll on the system. We're to some extent limited to how fast we can perform accept() on our sockets." I'd expect what you're seeing is the overhead of your system creating new objects initializing requests etc rather than anything low level. (Mibbit uses keep alive long polling XHR / websocket, using custom app server in Java +NIO)
- cgbystrom 16y agoIt turns out that Java synchronizes on accept() capping the number of socket accepts that can made each second on a single port. But even if that would be solved or if you used something more low-level like, say nginx, you'd still be limited of how fast you can accept(). Try using ApacheBench and hit one server with keep-alive on and off respectively. Even nginx, which I would say is a performant web server, show quite some discrepancies between having to reconnect each time and having a permanent connection. I file this under the penalty of having to set up and tear down a socket each time. Something that only can be avoided by doing less reconnecting. I could of course be wrong but these are the findings from doing performance testing and discussing it on the Netty mailing list. But I'd gladly accept suggestions on how to improve this situation for our service.
- axod 16y agoI'd personally start by not using Netty if you have the time to start from scratch :/
- cgbystrom 16y agoNetty is not the problem. Java NIO has that limitation. And performance isn't in any way bad, just that there's more to extract (I believe).
- axod 16y ago> "Netty is not the problem. Java NIO has that limitation." As I say, I'd be interested in numbers to back that up. It's certainly not a limitation I've noticed.