Horizontally scaling socket.io across multiple Amazon EC2 instances - node.js

Have everything setup and working correctly with 2 Amazon EC2 servers running my node application. Currently sitting behind an Application Load Balancer.
I am emitting socket messages using code like this
const ioredis = require('socket.io-redis');
io = require('socket.io')(server);
io.adapter(ioredis({
host: 'localhost',
port: 6379
}));
io.to('roomName').emit('message', data);
However, when emitting a message using socket.io, the message is only broadcast from the originating node server.
Server 1 emits a socket.io message -> Anyone connected to Server 1 hears the message, but anyone connected to Server 2 doesn't.
Server 2 emits a socket.io message -> Anyone connected to Server 2 hears the message, but anyone connected to Server 1 doesn't.
What i need help with is how to emit the socket.io message from Server 1 and either Relay it to all other server's aswell, possibly by using a single instance of redis on a seperate server?
OR
Have another Server as a socket emitter that Server 1 and Server 2 send and receive socket messages from.
Not quite sure which option is the best and correct way to go, any help would be appreciated.

I managed to solve the problem by creating a 3rd server, installing Redis on it and setting all of the other servers to use that single instance of redis.
Now socket messages are broadcast to all servers regardless of the originating server.

Related

Running multiple socket.io servers and connecting to them from one express website

I need to make system what is used on page: https://www.csgohunt.com/
They have 3 socket.io servers running on: ws.csgohunt.com, chat.csgohunt.com, csgohunt.com
First two seems to be running on different http server, but when you connect to all 3 sockets from website csgohunt.com (You can see it from network tab), then all 3 sockets communictating.
Whats more interesting is, that even those 2 sockets what runs on different http server share express session and they know when user is logged and when not.
I have working Express + Socket.IO + Passport app where session sharing works fine when you connect to socket server running on same http server as express. But when I start nsecond socket server on different http server (but same app) and using same sessionStore, second server not see sessions.
Whats the best way to achieve this kind of system? I don't want to have 1 socket server for everything.
EDIT: I found that they using Heroku. Is this giving them possibility to do what I described? I have absolutely no expirience with it.

Persist websocket connection object across the multiple server

I am using a websocket library on server for establishing socket connection.
https://github.com/websockets/ws
I have a more than one server in cluster, I want to know how can I use same socket connection object on another server in cluster.
And also I want to know what is the best option for webchat implementation native websocket or socket.io
You cannot use the same actual socket object across multiple servers. The socket object represents a socket connection between a client and one physical server process. It is possible to build a virtual socket object that would know what server its connection is on, send that server a message to then send out over the actual socket from that other server.
The socket.io/redis adapter is one such virtual ways of doing this. You set up a node.js cluster and you use the redis adapter with socket.io. It uses a central redis-based store to keep track of which serve process each physical connection is one. Then, when you want to send a message to a particular client from any of the server processes, you send that message through socket.io and it looks up for you in the redis database where that socket is connected, contacts that actual server and asks it to send the message to that particular client over the socket.io connection that is currently present on that other server process. Similarly, you can broadcast to groups of sockets and it will do all the work under the covers of making sure the message gets to the clients no matter which actual server they are connected to.
You could surely build something similar yourself for plain webSocket connections and others have built pieces of it. I'm not familiar enough with what exists out there in the wild to offer any recommendations for a plain webSocket. There plenty of articles on scaling webSocket servers horizontally which you can find with Google and read to get started if you want to do it with a plain webSocket.

socketio inter server communication with redis and haproxy

I'm working on a project which uses SocketIO and should be Horizontally scalable. Im using
A Load Balancer using HAProxy
Multiple Node Servers (2-4)
Database server(Redis and MongoDB)
I'm able to redirect my incoming Socket connections to Node servers using roundrobin method. Socket connection is stable and if I use socket.emit() I'm receiving the data. I'm also able to emit to the Other socket connection connected to the same Node server.
I'm facing issue in the following scenario:
User A connected to Node server 1 and User B connected to Node Server 2
My intention is to store the Socket data in redis
If User A wants to send some data to User B, how can I tell the Node server 2 to emit the data to User B from Node server 1
Please let me know how can I achieve this (with ref if possible).
Thanks in advance.
This scenario is a match for the case Pub/Sub of Redis.
If you haven't already, you should try Pub/Sub.
Have a look at socket.io Redis adapter. It should be exactly what you need.
clients() method in particular looks promising. Keep in mind, that socket.io creates a unique room for each client.

Horizontally scale socket.io with redis

I currently am creating a horizontally scalable socket.io server which looks like the following:
LoadBalancer (nginx)
Proxy1 Proxy2 Proxy3 Proxy{N}
BackEnd1 BackEnd2 BackEnd3 BackEnd4 BackEnd{N}
My question is, with socket-io redis module, can I send a message to a specific socket connected to one of the proxy servers from one of the backend servers if they are all connected to the same redis server? If so, how do I do that?
As you wan to scale socket.io server, and you have used nginx as load balancer, do not forget to setup sticky load balancing, othersie single connection will be connected to multiple server based on load balancer pass the connection to socket.io server. So better to use sticky load balancing
With the redis socket io adapter, you can send and receive message with one or more socket.io server with help of Redis Pub/Sub implementation.
if you tell me which technology is used for Proxy and Backend, i will let you know more information on this.
Using the socket.io-redis module all of your backend servers will share the same pool of connected users. You can emit from Backend1 and if a client is connected to Backend4 he will get the message.
The key for this working though with Socket.io is to use sticky sessions on nginx so that once I client connects, it stays on the same machine. This is because the way that socket.io starts with a WebSocket and several long polling threads, they all need to be on the same backend server to work correctly.
Instead of sticky sessions, you can change your client connection optons to use Websockets ONLY and this will remove the problems with the multiple connections to multiple servers as there will only be one connection, the single websocket. This will also make your app lose the ability to downgrade to long-polling instead of WebSockets.

Scale node.js socket.io with 3 servers

I know their are a lot of questions and answers about this issue on the net but I can't get it to work.
I have a server written in node.js and listening to connections with socket.io
Now, The sockets can exchange messages between them, like a chat and I'm broadcasting the incoming messages to all other sockets on the server.
I want to run my node server on 3 different servers, each one of them have different IP, Lets call them: SERVER1, SERVER2 and SERVER3.
Here comes my confusion, if i'm sending a message from a socket which connected to SERVER1, How the sockets that connected to SERVER2 and SERVER3 will see this message?
I heard about RedisStore, RabbitMQ and other stuff but i can't find a good article/post/book that can explain me how to do it right...
Can someone help me please?
I believe RedisStore does this automatically for you, here's a good post about it: http://www.ranu.com.ar/2011/11/redisstore-and-rooms-with-socketio.html
How is this done internally?
Well as you have heard, Redis, RabbitMQ, ZeroMQ etc have pub-sub functionality, meaning you can subscribe to channels and publish info on them (to all the connected peers):
https://github.com/mranney/node_redis#publish--subscribe
So server A, B and C are subscribed to the same channel. When a client connected to server A wants to send a message for all the users connected to the chat room "js" for example, he sends a message to the server A and server A publishes a message on the "js" channel.
All the rest of the servers get that message and broadcast it to all their clients.

Resources