Horizontal scale of nodejs TCP Server - node.js

I'm trying to figure out how to horizontally scale my nodejs TCP Server.
Example server:
var socketServer = net.createServer(function (socket) {
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort
// Put this new client in the list
clients.push(socket);
sockets[socket.name] = socket;
// Handle incoming messages from clients.
socket.on('data', function (data) {
// Write to a specific user
var socketName = "xx.xx.xx.xx:56512";
sockets[socketName].write("Hello!");
}
}).listen(8080);
The following example stores each new connection in an array so that we can write a message to a specific user down the road.
I would like to scale this with haproxy as the loadbalancer. But how can i get all of my servers to share the same array of connected clients?
Stickysessions is not a solution that would work for me, since two people talking (two clients) could be on different servers, so all servers somehow have to share the same array of connected clients.
Any ideas how this can be done?
An idea i had:
Is it maybe possible to store each connection in MySQL?
Edit
Maybe the only way of actually doing this is by using Redis?
Any ideas if that would be a suitable option? The load is going to be extremely heavy

1.Use Redis to share your session with your servers.
2.Write a Login-Server,all users should login in Login-Server.
firstly.Login-server will generate a session,and share session on Redis-server and return transaction server ip and port,
Secondly,Client receive ip and port, disconnect Login-server, and connect to the transaction server,
Lastly,You can provide several TCP servers to handle transaction,Login-server will balance load through ip and port. of course, you can use haproxy to do that.but i don't know how to configure it.

Related

How to use socket.io-redis with multiple servers?

i have following code on two machines
var server = require('http').createServer(app);
io = require('socket.io')(server);
var redisAdapter = require('socket.io-redis');
io.adapter(redisAdaptebr({host: config.redis.host, port: config.redis.port}));
server.listen(config.port, function () {
and I store socket.id of every client connected to these two machines on central db, ID of sockets is being saved and event sending on same server works flawlessly, but when I try to send message to the socket of other server it doesn't work..
subSocket = io.sockets.connected[userSocketID];
subSocket.emit('hello',{a:'b'})
How can i know that redis is wokring good.
How to send message to socket connected on another server.
You can't. Socket.IO requires sticky sessions. The socket must communicate solely with the originating process.
docs
You can have the socket.io servers communicate to each other to pass events around, but the client must continue talking to the process with which it originated.
I'm in a similar issue but I can answer your first question.
you can monitor all the commands processed by redis using that command on the terminal:
redis-cli monitor
http://redis.io/commands/MONITOR
Unfortunately I cannot help you further as I am still having issues even though both server are sending something to redis.

How to check socket is alive (connected) in socket.io with multiple nodes and socket.io-redis

I am using socket.io with multiple nodes, socket.io-redis and nginx. I follow this guide: http://socket.io/docs/using-multiple-nodes/
I am trying to do: At a function (server site), I want to query by socketid that this socket is connected or disconnect
I tried io.of('namespace').connected[socketid], it only work for current process ( it mean that it can check for current process only).
Anyone can help me? Thanks for advance.
How can I check socket is alive (connected) with socketid I tried
namespace.connected[socketid], it only work for current process.
As you said, separate process means that the sockets are only registered on the process that they first connected to. You need to use socket.io-redis to connect all your nodes together, and what you can do is broadcast an event each time a client connects/disconnects, so that each node has an updated real-time list of all the clients.
Check out here
as mentioned above you should use socket.io-redis to get it work on multiple nodes.
var io = require('socket.io')(3000);
var redis = require('socket.io-redis');
io.adapter(redis({ host: 'localhost', port: 6379 }));
I had the same problem and no solution at my convenience. So I made a log of the client to see the different methods and variable that I can use. there is the client.conn.readystate property for the state of the connection "open/closed" and the client.onclose() function to capture the closing of the connection.
const server = require('http').createServer(app);
const io = require('socket.io')(server);
let clients = [];
io.on('connection', (client)=>{
clients.push(client);
console.log(client.conn.readyState);
client.onclose = ()=>{
// do something
console.log(client.conn.readyState);
clients.splice(clients.indexOf(client),1);
}
});
When deploying Socket.IO application on a multi-nodes cluster, that means multiple SocketIO servers, there are two things to take care of:
Using the Redis adapter and Enabling the sticky session feature: when a request comes from a SocketIO client (browser) to your app, it gets associated with a particular session-id, these requests must be kept connecting with the same process (Pod in Kubernetes) that originated their ids.
you can learn more about this from this Medium story (source code available) https://saphidev.medium.com/socketio-redis...

How to keep a tcp connection always open with node.js

I'm building a tcp-message server with nodejs.
It just sits on my server waiting to accept a connection from lets say an Arduino.
As it, at connection-time, identifies itself with an unique ID (not an IP) I'm able to write data from server > arduino without knowing the IP address of the client-device.
But for that to be efficient, I want the connection to be open as long as possible, preferably as long as the client-device closes the connection. (eg on ip change or something)
This is the (relevant part of) the server:
var net = require('net'),
sockets = {};
var tcp = net.createServer(function(soc){
soc.setKeepAlive(true); //- 1
soc.on('connect', function(data){
soc.setKeepAlive(true); //- 2
});
soc.on('data', function(data) {
//- do stuff with the data, and after identification
// store in sockets{}
})
}).listen(1111);
Is soc.setKeepAlive(true) the right method to keep the connection alive?
If so, what is the right place to put it? In the connect event (1), or right in the callback (2).
If this is not the way to do it, what is?
Your best bet is to periodically send your own heartbeat messages.
Also, you don't need soc.on('connect', ...) because the client socket is already connected when that callback is executed.

Scaling SockJS keeping track of clients

Im in the process of scaling up my Nodejs server which runs a SockJS server. Its a basic chat where the SockJS server stores each connected client.
Basically i store it like this:
var clients = [];
var sockets = {};
// Identify this client
socket.name = socket.remoteAddress + ":" + socket.remotePort
// Put this new client in the list
clients.push(socket);
sockets[socket.name] = socket;
This is how i write to the socket:
sockets[socketName].write("{\"type\":\"type\", \"msg\": \"" + escp(obj.msg) + "\", \"name\": \"" + obj.name+ "\", \"location\": \"" + obj.location + "\"}");
My idea is to now scale up and start more instances on Amazon. And i'll have HAProxy in the front balacing the load.
The problem is that both people chatting would have to be on the same instance, since the connectedClients isent shared amongst my ec2 instances.
Any ideas how to accomplish this? Do i need to store connectedClients in a db? (Is that even possible)?
Basically i need to share sockets and clients between my instances
I think you'll probably have to store the session connection in redis/mongodb and have those nodes server do pub/sub to the redis in order to have consistent request /response across the node. therefore, when user send message to HAProxy irrespective of which server the HAProxy route the request to the node has check-in redis if there is existing connection.

Can socket.io client connect to two different servers/ports?

Can socket.io client connect to two different ports on the same server?
Can socket.io client connect to two different server?
Sure:
var io1 = require('socket.io').listen(8001);
io1.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
});
var io2 = require('socket.io').listen(8002);
io2.sockets.on('connection', function (socket) {
socket.emit('flash', { hello: 'world' });
});
Perhaps this is an interesting read: (from github)
// connect at the same host / port as your website
var socket = io.connect();
// different port or host
var socket = io.connect('http://url.com');
// secure
var socket = io.connect('https://localhost');
Can socket.io client connect to two different ports on the same
server?
I assume both machines share same domain. I believe it can use long-polling(websockets, flashsockets, etc also work), even passing along cookie. But I still need to test this on Internet Explorer because that browser never does what I want...
Can socket.io client connect to two different server?
The big question is if those both machines are on different domains. If on same domain it will work just fine even passing along cookie(s). If they are on different domains then on some browser we fall-back to json-p transport(worst transport imaginable), but it will work. Unfortunately then the cookie is not passed along, because of same origin policy. Right now I am toying to get around this cookie restriction(hard problem)...

Resources