Home > Net >  Socket.IO Cluster In Kubernetes With Multiple Nodes Not Emitting To All Clients
Socket.IO Cluster In Kubernetes With Multiple Nodes Not Emitting To All Clients

Time:12-13

i have a kubernetes environment i am trying to publish my socket.io nodejs app to it for scaling.

It only emits the message to clients connected to same server, other clients are not getting any message at all.

Using:

[email protected]

[email protected]

[email protected]

I was following this documentation:

Here is my clustered-socket.js:

const cluster = require("cluster");
const http = require("http");
const { Server } = require("socket.io");
const numCPUs = require("os").cpus().length;
const { setupMaster, setupWorker } = require("@socket.io/sticky");
const { createAdapter, setupPrimary } = require("@socket.io/cluster-adapter");

if (cluster.isMaster) {
    console.log(`Master ${process.pid} is running`);

    const httpServer = http.createServer();

    setupMaster(httpServer, {
        loadBalancingMethod: "least-connection",
    });

    setupPrimary();

    cluster.setupMaster({
        serialization: "advanced",
    });

    httpServer.listen(80);

    console.log(`Starting ${numCPUs} workers...`);

    for (let i = 0; i < numCPUs; i  ) {
        var worker = cluster.fork();
        console.log(`Worker ${worker.process.pid} started.`);
    }

    console.log(`Started ${numCPUs} workers.`);

    cluster.on("exit", (worker) => {
        console.log(`Worker ${worker.process.pid} died`);
        cluster.fork();
    });
} else {
    console.log(`Worker ${process.pid} started`);

    const httpServer = http.createServer();
    const io = new Server(httpServer, {
        transports: ["websocket"],
        cors: {
            origin: "*",
            methods: ["GET", "POST"]
        }
    });

    io.adapter(createAdapter());
    setupWorker(io);

    io.on('connection', (socket) => {
        socket.emit("MESSAGE", "Welcome to Stream Socket.");

        socket.on('disconnect', () => { });

        socket.on('SUBSCRIBE', (msg) => {
            try {
                console.log(msg);
                
                var obj = JSON.parse(msg);
                socket.join(obj.requestedStream);

                if (obj.requestedStream.startsWith("OLD_MESSAGES")) {
                    // This here is only emitting to clients connected to same server.
                    io.to("OLD_MESSAGES").emit("___OLD MESSAGES HERE____");
                }

            } catch (e) { console.log(e); }
        });

        socket.on('UNSUBSCRIBE', (msg) => {
            var obj = JSON.parse(msg);
            socket.leave(obj.requestedStream);
        });
    });
}

I've enabled sticky-session on kubernetes with nginx, ingress:

nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/affinity-mode: "persistent"
nginx.ingress.kubernetes.io/affinity-canary-behavior: "sticky"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
nginx.ingress.kubernetes.io/session-cookie-hash: "sha1"
nginx.ingress.kubernetes.io/session-cookie-expires: "10800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "10800"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "3600" 
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
nginx.ingress.kubernetes.io/send-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-ssl-server-name: "on"

Here is how i am connecting to socket:

    var server = document.getElementById('address').value;

    socket = io(server, {
        transports: ["websocket"],
        'reconnection': false,
        
    });

    socket.on('MESSAGE', (msg) => {
        logResponse(msg);
    });

    socket.on('MESSAGE', (msg) => {
        logResponse(msg);
    });

And finally my dockerfile:

FROM node:14
EXPOSE 80
EXPOSE 443

WORKDIR /usr/src/app
COPY package*.json ./
RUN apt-get update && \
    apt-get install -y software-properties-common && \
    rm -rf /var/lib/apt/lists/*
RUN sed -i "/^# deb.*multiverse/ s/^# //" /etc/apt/sources.list
RUN sed -i "/^# deb.*universe/ s/^# //" /etc/apt/sources.list
RUN npm install
RUN npm ci --only=production
COPY . .
CMD ["node", "clustered-socket.js"]

CodePudding user response:

Use an adapter that uses a database connected to all nodes like Redis, Mongodb or Postgres adapters.

  • Related