Open refaelos opened 9 years ago
Another question: If I do use this sticky session solution, Won't it only be applied to one machine? What happens if I have more than one machine and requests go to both of them?
I don't know, I haven't tried it because I'm not using cluster in production. I think the problem is happening at a much lower level than can be solved by using socket.io's redis adapter. Maybe if you'd use redis as a session store for the HTTP server as well it might work. Worth a shot.
As for multiple machines (or really, multiple IPs), no idea, but also a good question. I suspect that once state is persistent (redis instead of memory) then it doesn't matter if it's a multi-process or multi-machine architecture.
Do you feel like trying any of this stuff out? :)
What do you use on production?
Yeah what you say about having one single session store is supposed to do the work. In older versions of socket.io they had an option to easily setup redis as the session store which made life VERY easy. They took it out though.
Toda!
At the moment I can afford a single process environment so none of this is a problem. This project was about future-proofing... maybe it's time to revisit the options and refresh the text.
You live in a better world then me :smile:
If this is a problem then why not keep the issue open until there's a recipe to fix it?
Oops
@refaelos, socket-io v.9 used a pub/sub redis mechanism to transfer state across processes; however, the way it was originally constructed, would not scale well as every request's handshake information was being broadcasted across all processes. As you begin to add more boxes/processes you're then forcing each process to handle an unnecessary amount of overhead and at times, even experience some kind of race condition as a result of the added latency. (Second request would get to a process before handshake data has been received by that process)
You need sticky sessions because, the way it works, socket.io tries to find the best client-server connection strategy (websocket, long-polling, etc.) based on trying them all at once; for websockets to work properly, all the handshake requests need to land on the same backing server. If you dont use sticky sessions, you'll get websockets or long polling based on a 1/clusterSize
chance.
You don't need sticky sessions if you're not planning to support fallback for long-polling or all the other transports.
So, if your clients only use websocket. Like:
var socket = io.connect(window.location.origin , {transports:['websocket']} );
The usual node cluster (master/fork) with redis adapter will work.
Here is a working example: https://github.com/squivo/chat-example-cluster.git
Some background: The socket.io docs says that sticky load balancing are required because:
This is due to certain transports like XHR Polling or JSONP Polling relying on firing several requests during the lifetime of the “socket”.
Those types of connections, requires socket.io to buffer some messages, that means it needs to know when and in which request to write the messages, thus, it requires the sticky sessions, by being the easiest way to claim those buffered messages. This is also according to the docs:
If they’re using long polling, they might or might not have sent a request that we can write to. They could be “in between” those requests. In those situations, it means we have to buffer messages in the process. In order for the client to successfully claim those messages when he sends his request, the easiest way is for him to connect to be routed to that same process.
I first imagined that the redis adapter would also solve those cases, by buffering the messages inside redis or working as a internal memory for socket.io to identify the clients, but apparently, only the websocket protocol works out of the box with the cluster and the adapter because it does not requires that buffer mechanism since it has a bi-directional connection.
Maybe it is possible to write some wrapper that will attach a userId or some other way that would make possible to socket.io to identify the client and send those buffered messages.
I have problems
Hey @elad,
I have a question related to the great example you provided here: Can you explain why we even need a sticky session? I don't understand why having the redis adapter isn't enough to support multi processes? I mean, I understand that the sticky session comes to make sure a request from a specific IP goes to a specific worker but isn't the redis adapter a solution that's supposed to make sure all socket.io processes know about all connections and can handle them all asynchronously?