Search code examples
nginxwebsockettornado

Tornado Websocket Instances behind a Load Balancer (Nginx, HaProxy)


I have previously used Tornado behind Nginx in production, that too with multiple tornado instances, but presently with Websockets implementation in Tornado, I am unable to understand few things.

NOTE : Just running Websockets with Tornado is not my problem, I can get it to work and have used it in many projects fairly easily, but all as a single Tornado instance with/without a reverse-proxy or load balancer (nginx), both working fine.

With that said, my doubts are regarding how to handle multiple tornado websocket instances behind a load balancer. Lets look at a use case:

Use Case : 2 Tornado Websocket Instances, T1 and T2 behind Nginx and there are 3 Clients (Browsers), lets say C1, C2, C3.

                                     ______|-------|      
 C1-----------------|               |      |  T1   |
                    |               |      |_______|       
 C2-----------------|---> Nginx --->|       
                    |               |      |-------| 
 C3-----------------|               |______|  T2   |   
                                           |_______|

Step 1 - C1 initiated a websocket connection, at location w.x.y.z:80. Now Nginx load balanced the connection to lets say T1, which triggered the open event in T1's(Tornado's) websocket handler. Now T1 knows of a websocket connection object which is opened, let the object be w1.

Step 2 - Now, C2 initiated a websocket connection, same as above, but now Nginx laod balanced it to T2 which triggered T2's(Tornado's) websocket handler's open event. Now T2 knows of a websocket connection object which is opened, let the object be w2.

Step 3 - Now, similarly C3 initiated a websocket connection, Nginx load balanced it to T1, which now has a new opened websocket connection object, let the object be w3.

Step 4 - Now, C1, our first client sent a message via the browser's ws.send() method, where ws is the browser(client) side's websocket object used to create the websocket connection in Step 1. So when the message reached Nginx, it load balanced it to T2.

Now here is my question.

Does Nginx load balance it to T2 or does it know that it should proxy the request to T1 itself?

Suppose it sends it to T2, now T2 doesn't have the w1 object with it, since it is with T1, so when T2's websocket handler tries to process the request, which should originally trigger the on_message handler, so now,

what happens at this condition, does T2 raise an Exception or what happens exactly?

Also, how to manage the websocket connections in these cases when there are multiple tornado instances running behind a load balancer, how to solve this?

If suppose we use Redis as a solution, then what would redis actually store? The websocket objects? Or, what exactly should it store to let the instances work properly, if Redis is one of the solutions you are going to propose?


Solution

  • Messages are always attached to a connection; they are not load-balanced separately. So in step 4, nginx sends the message on the C1 connection to T1, not T2.