This was a long time coming! I'm very happy to see socket.io 1.0 finally released. Pre-1.0 had some deal-breaking technical issues, such as starting with websockets and falling back to polling. I think the new approach is starting with polling and then seeing if a) websockets are supported by the current browser and b) messages sent via websocket are received by the server (a firewall might prevent this).
Finally!! I was going to switch to naked engine.io because it can handle many more connections without going crazy. Now I can get it without changing my code. Woo hoo!
Its dependent on sticky load balancing - a pretty big caveat. And as far as I can tell, it still doesn't work with the cluster module, which is what that issue is about.
It appears that the answer is "kind of". You can't use cluster, but you can put multiple processes behind a load balancer if the load balancer can do sticky routing. They should probably be a lot more explicit about this; the scalability section seems to avoid mentioning that socket.io isn't compatible with the cluster module.
Sticky load balancing was a deal breaker for us when we built the https://map.couple.me visualization with socket.io. At the last minute I just pulled older browser support and left it with raw websockets instead of socket.io because the cluser module couldn't be used otherwise.
We had two issues with sticky load balancing:
1. AWS ELB had to run in TCP mode (for websockets) which meant no stickiness
2. Within each instance we have a node-cluster running to utilize multiple CPUs and putting haproxy with stickiness there increased complexity
We could avoid using the ELB but then you lose the ability to use an EC2 Auto Scaling group, introducing significant admin overhead.
Ultimately we didn't need the nodes communicating between each other (it's a one way stream from us to the client) so raw websockets ended up being the simplest solution.
I've since switched to SockJS for all of my projects (after struggling with memory issues in Socket.io 0.9.*). Any compelling reasons to give Socket.io another try?
The new engine.io module used behind the scenes is amazing. It will start with long polling, and upgrade to WebSockets seamlessly (so you get a very fast start every time, even in old browsers or proxied envs). AFAIK, this is the opposite of what was happening previously (trying WebSockets, then falling back to long polling). Engine.io is also much more scalable and robust.
Disclaimer: I work at Automattic, we've been using engine.io on cloudup.com for a while.
When I switched to SockJS, I tried Engine.io too, but I ended up going with SockJS mostly because Engine.io didn't expose the client's IP address to Node, which made IP banning impossible. It looks like it's still an issue, sadly.
This is exactly how I've always wanted the web to work. i've spent some time with socket.io working through "nodejs in action" and I can't wait to use it for new apps.
I like the separation of the transports into engine.io, however it would be even better if it exposed a standard Node.js Stream interface so that it played nicely with the growing ecosystem of Stream-related modules.
That probably works fine, but if it's encapsulating a stream over Socket.io's protocol then it's going to be much less efficient than the other way around.
You can't use both.
In Primus you can select only one transformer, listed above by V1, but if something doesn't work, you can just switch it with a single line of code. No rewrites, no need to learn a new API.
I've been using engine.io directly in production for quite a while, and it's been stable and reliable. Glad to see this release, having the option of going back to the higher-level socket.io api is welcome.
This seems like a good place to ask: Does anyone know of a library (preferably C++/Emscripten) that simplifies using WebRTC to create real time network games?
I looked for a library for a similar WebRTC project. All of the libraries I found contained superfluous functionality, as I was only interested in data channels and did not want to be locked in by a particular third party. I ended up rolling my own; the WebRTC API is simple enough [1] and there is some example code from Google that points the right direction [2]. Additionally, Socket.io makes for a convenient signalling server prototype, though it is overkill.
If you want a simpler signaling server for WebRTC, you might check out the "caress" server I developed for Chatphrase: http://github.com/chatphrase/caress
Congrats on the release! I know this was a long time coming.
A scalability question:
You note "Turn on sticky load balancing (for example by origin IP address). This ensures that long-polling connections for example always route requests to the same node where buffers of messages could be stored."
I read this to mean that we are responsible (in our load balancer/proxy/etc) to keep connections from clients returning to the same server. This is OK, but what about nodeJS clusters? How should I ensure that client A always connects to cluster-node member 3?
The node.js cluster module is not flexible enough to be used with engine.io / socket.io / sockjs etc. Just run several processes and put something like HAproxy in front of them. If using a cookie to ensure stickiness, you can scale to multiple load-balancers easily.
That seems like a pretty big requirement that could frequently be deal-breaking. I would expect a big warning somewhere that you can't cluster if you're using socket.io.
I tried using faye and it died very quickly under load with the redis backend. For every message that you send it queues it up into a redis list for each faye server in the cluster to read which doesn't scale very well in their very chatty redis queue system.
I would do significant load testing for each use case before using it (or socket.io for that matter). I needed to push 30-50 messages per second to each connected client and faye started choking as soon as there were more than 20-30 clients. socket.io would choke at around 50-100 connected clients. Raw websockets were able to reach closer to 100 clients but performed more or less similar to socket.io.
That's an incredibly high rate of messages. What could you possibly need that many messages for? I'm in no way surprised that generic solutions don't work for your case.
We kept the design simple, otherwise a "batching" mechanism could be introduced that would replay a single batch of 50 messages but that would make everything a second delayed. However, part of the map allows you to login and see your messages live on the screen as you're sending them to your partner and for that the real time streaming is pretty critical.
It looks like you're sending the same data to every client, but it sounds like Socket.IO/Faye aren't handling this well. Do they not have a `broadcast` method of something of that nature that handles your use-case?
I've used Socket.IO quite a bit, congrats on shipping! Did the issue/"lack of feature" get fixed where not all transport methods fire a disconnect event? That was especially a pain on a recent project, ended up forcing websocket only to get around it.
EDIT: Ack, I should probably clarify this better. The issue is that a client disconnected is not determined by the server. The server waits for the client to send a disconnect event to it prior to leaving the page. This is particularly a problem on iPad where the event will not fire for certain transports so disconnect doesn't fire when you shut off an iPad unless websockets are actively used.
Something about this site just kills both Firefox and Chrome on my Windows 7 computer: everything becomes choppy and laggy, even outside the browser. On both browsers, things return to normal when I close the tab.
Task Manager shows no unusual CPU activity beyond the initial page load.
You need mandatory ACKs in both directions if you want to implement a reliable stream over HTTP requests. Otherwise, data can get lost in several scenarios, including: server responds to a long-poll request, connection breaks before client receives it, server assumes the data arrived, user never sees the message. Instead of having an ACK for every message in both C2S and S2C directions, socket.io implements some kind of bizarre optional-per-message ACK functionality that you manage with callbacks. There are libraries/protocols that do this right, including Closure Library's BrowserChannel.
I am trying to develop an application that can be horizontally scaled. I understand using the socket.io-redis package seems to allow you to emit to a particular socketid from one instance while that connection itself is connected to another machine and the redis connection will take care of the communicating. This in a sense abstracts away the fact that there are multiple servers by just taking care of it transparently.
Are there any provisions within socket.io or another package that allows you to sync normal js objects across servers as well? The alternative as I see it is to use redis pub/sub to keep the state in sync but this feels like it should be a solved problem that one need not reinvent the wheel for.
75 comments
[ 2.8 ms ] story [ 144 ms ] threadWould be pretty hesitant to use it until there's some sort of closure on this.
We had two issues with sticky load balancing:
1. AWS ELB had to run in TCP mode (for websockets) which meant no stickiness
2. Within each instance we have a node-cluster running to utilize multiple CPUs and putting haproxy with stickiness there increased complexity
We could avoid using the ELB but then you lose the ability to use an EC2 Auto Scaling group, introducing significant admin overhead.
Ultimately we didn't need the nodes communicating between each other (it's a one way stream from us to the client) so raw websockets ended up being the simplest solution.
Disclaimer: I work at Automattic, we've been using engine.io on cloudup.com for a while.
Dominic Tarr, substack, and others have been advocating this idea for awhile: https://github.com/substack/stream-handbook
Gluing together various types of streams and stream transformers is a really nice way to build certain types of applications.
Fortunately it should be easy to write a Stream compatible wrapper.
https://github.com/primus/primus
(Primus uses engine.io,sockjs,browserchannel,websockets internally so you're no longer locked into a specific framework)
why would I need engine.io,websockets for example when engine.io already uses websockets if it can upgrade the connection to them?
You can tell engine.io to only use websockets, but what's the point if you can use websockets directly and have the same API?
[1] http://dev.w3.org/2011/webrtc/editor/webrtc.html
[2] https://bitbucket.org/webrtc/codelab
A scalability question:
You note "Turn on sticky load balancing (for example by origin IP address). This ensures that long-polling connections for example always route requests to the same node where buffers of messages could be stored."
I read this to mean that we are responsible (in our load balancer/proxy/etc) to keep connections from clients returning to the same server. This is OK, but what about nodeJS clusters? How should I ensure that client A always connects to cluster-node member 3?
Related section of the blog post: http://socket.io/blog/introducing-socket-io-1-0/#scalability
I would do significant load testing for each use case before using it (or socket.io for that matter). I needed to push 30-50 messages per second to each connected client and faye started choking as soon as there were more than 20-30 clients. socket.io would choke at around 50-100 connected clients. Raw websockets were able to reach closer to 100 clients but performed more or less similar to socket.io.
We kept the design simple, otherwise a "batching" mechanism could be introduced that would replay a single batch of 50 messages but that would make everything a second delayed. However, part of the map allows you to login and see your messages live on the screen as you're sending them to your partner and for that the real time streaming is pretty critical.
offtopic: please fix your blog, it breaks the browser history in IE 11 (spammed with hash entries)
"The benefits of this particular modularization can’t be overstated"
EDIT: found it at http://socket.io/demos/computer/
Would be great to see some benchmark of how this can scale especially with the new redis integration.
Task Manager shows no unusual CPU activity beyond the initial page load.
I am trying to develop an application that can be horizontally scaled. I understand using the socket.io-redis package seems to allow you to emit to a particular socketid from one instance while that connection itself is connected to another machine and the redis connection will take care of the communicating. This in a sense abstracts away the fact that there are multiple servers by just taking care of it transparently.
Are there any provisions within socket.io or another package that allows you to sync normal js objects across servers as well? The alternative as I see it is to use redis pub/sub to keep the state in sync but this feels like it should be a solved problem that one need not reinvent the wheel for.
No module lock-in!
Yes i'm a bit biased.