elad / node-cluster-socket.io

Writeup on how to make node.js cluster and socket.io play nice
421 stars 63 forks source link

Why sticky-session ? #5

Open refaelos opened 9 years ago

refaelos commented 9 years ago

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?

refaelos commented 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?

elad commented 9 years ago

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? :)

refaelos commented 9 years ago

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!

elad commented 9 years ago

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.

refaelos commented 9 years ago

You live in a better world then me :smile:

elad commented 9 years ago

If this is a problem then why not keep the issue open until there's a recipe to fix it?

refaelos commented 9 years ago

Oops

janajri commented 9 years ago

@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)

gvilarino commented 9 years ago

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.

lricoy commented 8 years ago

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.

clancytom commented 6 years ago

I have problems

  1. I have http and ws request
  2. use cluster, 1master and 3workers
  3. if i use redis like demo, all the request will be handled by one worker,and other workers will do nothing
  4. I want to rebalence the http request to the 3 workers , and ws handle by the right worker