How to use PM2 Cluster with Socket IO?
Asked Answered
F

4

7

I am developing an application that relies completely on Socket.io. As we all know NodeJS by default runs only on one core. Now I would like to scale it across multiple cores. I am finding it difficult to make socketio work with PM2 Cluster Mode. Any sample code would help.

I am using Artillery to test. And when the app runs on single core I get the response while It runs in cluster the response would be NaN

When Ran in a Cluster

When Ran Without Cluster

Foilsman answered 5/3, 2018 at 17:33 Comment(1)
Hi, I have the same issue. did you find the solution?Mendelson
C
3

PM2 docs say

Be sure your application is stateless meaning that no local data is stored in the process, for example sessions/websocket connections, session-memory and related. Use Redis, Mongo or other databases to share states between processes.

Socket.io is not stateless.

Kubernetes implementation get around the statefull issues by routing based on source IP to a specific instance. This is still not 100% since some sources may present more than one IP address. I know this is not PM2, but gives you an idea of the complexity.

Clothilde answered 5/3, 2018 at 18:26 Comment(1)
stateless makes sense.Delija
C
2

NESTjs SERVER

I use Socket server 2.4.1 so then i get the compatible redis adapter that is 5.4.0

I need to extend nest's adepter class "ioAdapter" that class only works for normal ws connections not our pm2 clusters

import { IoAdapter } from '@nestjs/platform-socket.io';
import * as redisIOAdapter from 'socket.io-redis';
import { config } from './config';

export class RedisIoAdapter extends IoAdapter {
  createIOServer(port: number, options?: any): any {
    const server = super.createIOServer(port, options);
    const redisAdapter = redisIOAdapter({
      host: config.server.redisUrl,
      port: config.server.redisPort,
    });
    server.adapter(redisAdapter);
    return server;
  }
}

That is actually nestjs implementation

Now i need to tell nest im using that implementetion so i go to main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { config } from './config';
import { RedisIoAdapter } from './socket-io.adapter';
import { EventEmitter } from 'events';

async function bootstrap() {
  EventEmitter.defaultMaxListeners = 15;
  const app = await NestFactory.create(AppModule);
  app.enableCors();
  app.useWebSocketAdapter(new RedisIoAdapter(app));
  await app.listen(config.server.port);
}
bootstrap();

I have a lot of events for this one so i had to up my max event count

now for every gateway you got, you need to use a different connection strategy, so instead of using polling you need to go to websocket directly

...
@WebSocketGateway({ transports: ['websocket'] })
export class AppGateway implements OnGatewayConnection, OnGatewayDisconnect {
...

or if you are using namespaces

...
@WebSocketGateway({ transports: ['websocket'], namespace: 'user' })
export class UsersGateway {
...

last step is to install the redis database on your AWS instance and that is another thing; and also install pm2

nest build
pm2 i -g pm2
pm2 start dist/main.js -i 4

CLIENT

const config: SocketIoConfig = {
  url: environment.server.admin_url, //http:localhost:3000
  options: {
    transports: ['websocket'],
  },
};

You can now test your websocket server using FireCamp

Copyright answered 22/5, 2021 at 23:25 Comment(0)
C
0

Try using this lib:

https://github.com/luoyjx/socket.io-redis-stateless

It makes socket io stateless through redis.

Clearway answered 23/7, 2020 at 8:53 Comment(0)
H
0

You need to setup Redis with your Node server. Here is how I managed to get cluster mode to work with Socket.io

First install Redis. If you are using Ubuntu, follow this link: https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-redis-on-ubuntu-18-04

Then:

npm i socket.io-redis

Now place Redis in your Node server

const redisAdapter = require('socket.io-redis')

global.io = require('socket.io')(server, { transports: [ 'websocket' ]})

io.adapter(redisAdapter({ host: 'localhost', port: 6379 }))

That was all I had to do to get PM2 cluster mode to work with socket.io in my server.

Handset answered 3/8, 2020 at 14:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.