Socket.io - sharing "friends activity" design pattern - node.js

I am writing some NodeJS an application for some clients (mobile, single page app...). The application is game and quite social - users can have friends and game needs to sharing events between them in realtime. So I decided to use Socket.io.
How to effectively share events between connected sockets of user's friends? One user can be connected with more then one client (so he has more connected sockets).
Is it good idea to use socket.io "rooms" where each user has one room and when some event occurs, it is emited to each room of my friends?
How to effectively handle this?
For better notion you can imagine it the same way as facebook wall (or right panel of friends activity).
How would you handle it?

You could try solving this task with socket.io rooms but i think that would kill your application because of the overhead, for example
1000 users => equals => 1000 rooms ( 1 room for each user )
thats 1000 connection without anyone particularly listening to friend activity.
So the approach above already seems like not scalable.
I would try publish/subscribe pattern which is not very difficult to implement, you can use a micro library or Backbone with .listenTo or even socket.io with Redis pub/sub.
A user would have the option to listen or stop listening to a friend events.
One user would not get a ton of notification for simple friend event.
and the list goes on depending on your application behavior.
Some questions that have interesting information.
What should I be using? Socket.io rooms or Redis pub-sub?
Node.js, Socket.io, Redis pub/sub high volume, low latency difficulties

Related

How to build a scalable realtime chat messaging with Websocket?

I'm trying to build a realtime (private) chat between users of a video game with 25K+ concurrent connections. We currently run 32 nodes where users can connect through a load balancer. The problem I'm trying to solve is how to route messages to each user?
Currently, we are using socket.io & socket.io-redis, where each websocket joins a room with its user ID, and we emit each message they should receive to that room. The problem with this design is that we are reaching the limits of Redis Pubsub, and Socket.io which doesn't scale well (socket.io emit messages to all nodes which check if the user is connected, this is not viable).
Our current stack is composed of Postgres, Redis & RabbitMQ. I have been thinking about this problem a lot and have come up with 3 different solutions :
Route all messages with RabbitMQ. When a user connects, we create an exchange with type fanout with the user ID and a queue per websocket connection (we have to handle multiple connections per user). When we want to emit to that user, we simply publish to that exchange. The problem with that approach is that we have to create a lot of queues, and I heard that this may not be very efficient.
Create a queue for each node in RabbitMQ. When a user connects, we save the node & socket ID in a Redis Set, so that when we have to send a message to that specific user, we first get the list of nodes, emit to each node queue, which then handle routing to specific client in the app. The problems with that approach is that in the case of a node failure, we may store that a user is connected when this is not the case. To fix that, we would need to expire the users's Redis entry but this is not a perfect fix. Also, if we later want to implement group chat, it would mean we have to send duplicates messages in Rabbit, this is not ideal.
Go all in with Firebase Cloud Messaging. We have a mobile app, and we plan to use it for push notifications when the user isn't connected, but would it be a good fit even if the user is connected?
What do you think is the best fit for our use case? Do you have any other idea?
I found a better solution : create a binding for each user but using only one queue on each node, then we route each messages to each user.

NodeJS and socket.io messages dispatching best practices

We are in the process of writing a multiplayer game with NodeJS and websockets. When designing the architecture of the server we came up with the idea of objects handling most of their own communication.
First example on a connection we would then pass the socket to the client object who could then handle himself the communications. One of the advantage is not having to have a global handler that has to route the messages. This makes the responsibilities very well separated.
I can then also tell the client themselves to join a specific room with the socket.io functionality by sending them the room id.
The main disadvantage we can see is that there may be occurrence were we need to duplicate the sockets. ie: if a client disconnects from a room and wants to join another.
So the other option is going a more classical way and handling all the messages globally and then routing the with associated id's to the concerned objects.
Would you guys advise one solution over the other and why?

Questions on Nodejs socket.io chat server with TONS of rooms

I'm trying to figure out how a chat app with lots of "rooms" would be implemented with nodejs and socket.io.
I know there are plenty of tutorials around for 1 room chats that run on 1 port, but my question is how would I transform something like that to support multiple chat rooms?
Would it require a different port per room? If so how would I get the server to sniff out open ports for this?.. or is there a better approach?
The target clients are native mobile sdks like iOS and android, so how would I get the server to open a room for a GET request?
Please excuse my noobness, I'm really trying to learn.
I have to point you to ActionHeroJS, namely the built-in chat server. This is accomplished with a single websocket port on the server, where each connection and each room is stored inside Redis. When a message is broadcast to a room, only those connections in that room get the message.
I might encourage you to try out the framework as an alternative to starting from scratch, but definitely look at the concepts as a way to manage a chat system at scale, beyond single-room-tutorials.

Using Backbone.iobind (socket.io) with a cluster of node.js servers

I'm using Backbone.iobind to bind my client Backbone models over socket.io to the back-end server which in turn store it all to MongoDB.
I'm using socket.io so I can synchronize changes back to other clients Backbone models.
The problems starts when I try to run the same thing over a cluster of node.js servers.
Setting a session store was easy using connect-mongo which stores the session to MongoDB.
But now I can't inform all the clients on every change, since the clients are distributed between the different node.js servers.
The only solution I found is to set a pub/sub queue between the different node.js servers (e.g. mubsub), which seems like a very heavy weight solution that will trigger an event on all the servers for every change.
How did you reach the conclusion that pub/sub is a "very heavy weight solution"?
Sounds like you got it right up until that part :-)
Oh, and pub/sub is not a queue.
Let's examine that claim:
The nice thing about pub/sub is that you publish and subscribe to channels/topics.
So, using the classic chat server example, let's say you have a million users connected in total, but #myroom only has 50 users in it.
When a message is sent to #myroom, it's being published once. No duplication whatsoever.
In most use-cases you won't even need to store it on disk/RAM, so we're mostly looking at network/bandwidth here. And, I mean, you're probably throwing more data (probably over the wire?) to MongoDB already, so I assume that's not your bottleneck.
If you also use socket.io's rooms features (which is basically its own pub/sub mechanism), that means only 5 users will have that message emitted to them over the websocket.
And no, socket.io won't iterate over 1M clients to find out which of them are in room #myroom ;-)
So the message is published once, each subscriber (node.js instance) will get notified once, and only the relevant clients -- socket.io won't waste CPU cycles in order to find them as it keeps track of them when they join() or leave() a room -- will receive the message.
Doesn't that sound pretty efficient and light-weight?
Give Redis a shot.
It's really simple to set-up, runs entirely in memory, blazing-fast, replication is extremely simple, etc.
That's the way socket.io recommends passing events between nodes.
You can find more information/code here.
Additionally, if MongoDB can't handle the load at any point, you can use Redis as your session-store as well.
Hope this helps!

Building a web app to support team collaboration using Socket.io

I'm building a web application that will allow team collaboration. That is, a user within a team will be able to edit shared data, and their edits should be pushed to other connected team members.
Are Socket.io rooms a reasonable way of achieving this?
i.e. (roughly speaking):
All connected team members will join the same room (dynamically created upon first team member connecting).
Any edits received by the
server will be broadcast to the room (in addition to being persisted,
etc).
On the client-side, any edits received will be used to update
the shared data displayed in the browser accordingly.
Obviously it will need to somehow handle simultaneous updates to the same data.
Does this seem like a reasonable approach?
Might I need to consider something more robust, such as having a Redis database to hold the shared data during an editing session (with it being 'flushed' to the persistant DB at regular intervals)?
All you need is Socket.IO (with RedisStore) and Express.js. With Socket.IO you can setup rooms and also limit the access per room to only users who are auth.
Using Redis you can make your app scale outside a process.
Useful links for you to read:
Handling Socket.IO, Express and sessions
Scaling Socket.IO
How to reuse redis connection in socket.io?
socket.io chat with private rooms
How to handle user and socket pairs with node.js + redis
Node.js, multi-threading and Socket.io

Resources