简体   繁体   中英

How to share a global variable in node js multi cluster mode when socket io is running on NGNIX load balancer but on fork using pm2?

I have a socket io app running using NGNIX Load balancing and my app is running on 6 cores and load is distributed among these. When I do pm2 list myapp it shows it's running in fork mode but spanning across 6 processes, due to nginx load balancing

│ myapp-1         │ 21  │ fork │ 
│ myapp-2         │ 45  │ fork │
│ myapp-3         │ 32  │ fork │
│ myapp-4         │ 11  │ fork │ 
│ myapp-5         │ 911  │ fork │ 
│ myapp-6         │ 101 │ fork │ 

Here is a sample of how my ngnix file looks

# Nodes for load balancing myapp
upstream myapp_nodes{
    ip_hash;
    server 1.2.3.4:1001;
    server 1.2.3.4:1002;
    server 1.2.3.4:1003;
    server 1.2.3.4:1004;
    server 1.2.3.4:1005;
    server 1.2.3.4:1006;
}

In my myapp.js, I have a global var, called Queue and this stores the users when they come on the page and they wait to be connected with another person. When the other person comes, the old person is popped from the queue and they both share a common ID to chat together. I am using socket.id of the first person as room then.

Sample code


var Queue = []; //global array of people waiting to chat

    socket.on("newUserJoinedFromClient", function (Username) {


      //check if someone is already waiting then pop it and return the pop SID as room
      if (Queue.length > 0) {
        var partner = Queue.pop();
        //remove special char from SID
        var room = partner.id.replace(/[^a-zA-Z0-9]/g, "");

        //return and tell the client its room
        socket.emit('sendRoomToClient', {
          room: room,
          users: numUsers
        }); //this person room will be same as the waiting partner room
      }
      // if nobody is in queue, queue is empty
      else {
        //add this user socket id to queue
        Queue.push(socket);
        //remove special char from SID
        var room = socket.id.replace(/[^a-zA-Z0-9]/g, "");
        //return and tell the client its room
        socket.emit('sendRoomToClient', {
          room: room,
          users: numUsers
        }); // Because we are calling socket itself id as his room, and he will wait
      }

    });

The logic seems to work perfect on single core myapp.js, if I run it in fork mode in simple 1 processor, but when I run it in NGNIX load balancer mode, it does not connect 2 users if they come from different IPs. (or I am assuming if both hit on a different process. See scenario below which I don't want but this is happening now,

  1. User A comes to the page using process (let's say process-2), => it is added to the Queue
  2. User B comes to the page using process (let's say process-4), => it is added to the Queue as well, but it should really not, because there is already 1 person waiting in process-2. In perfect case, User A should be popped and connected to User B. But here User B keeps waiting.
    1. If User C comes, it is also gone on waiting state:(

How do I share my global variable and its values among all processes of myapp that are process-1 to process-6?

I am already using Redis, as you can see at bottom here https://socket.io/docs/using-multiple-nodes/ but it can only pass emit events to other processes, how can i share my queue variable to maintain its persistent state and values among all processes of myapp?

Ideally I want it to work like this:

  1. User A (first user) comes to the page using process (let's say process-5 or any other process by load balancer's choice), => it is added to the Queue
  2. User B (Second user) comes to the page using process (let's say process-2 or any other process), => User A is popped and connected with this user B because user A was already waiting to be connected to anyone randomly.

I just want 2 users to be connected together whenever and however they come to this common page. and if 3rd comes, it is kept in waiting state (in queue) until 4th comes, and then 3rd is popped to be connected to 4th, and so on. But right now my variable Queue seems to be unique variable among the 6 myapp processes.

I am using Redis like this:

var app = express();
if (process.env.ENV == "development") {

  var server = require("http").createServer(app);
} else {
  // Setting up a HTTPS Server

  var server = require("https").createServer(,
    app // i have removed configs for https.
  );

}
var io = require('socket.io');
var redis = require("socket.io-redis");
io.adapter(redis({
  host: "localhost",
  port: 6379
}));
server.listen(port, function () {
  console.log("Server listening at port %d", port);
});

io.attach(server);

and then



io.sockets
  .on('connection', socketioJwt.authorize({
    hash: jwt,
    timeout: 15000 // 15 seconds to send the authentication message
  })).on('authenticated', function (socket) {
//all socket io events go here
});

I am not sure what is the syntax to store and retrieve values/array values of variable queue in Redis.

this case is my problem too,.. i havent answer about this, but.. may be you can switch variable temporary user to database that have replicate when load balance is on.. use Redis one of the best for this case..

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM