discussion icon indicating copy to clipboard operation
discussion copied to clipboard

New age web sockets

Open thetutlage opened this issue 7 years ago • 32 comments

The previous ( legacy ) version of AdonisJs has support for Web-sockets, which has been removed from AdonisJs 4.0 and not something anyone was expecting. However, the implementation was insufficient and had some potential issues with horizontal scaling.

Also, it was implemented on top of socket.io, where some users did complain about memory leaks. I personally never faced any issues with socket.io. but the internet is full of such issues.

Nevertheless, I wanted to set some clear and realistic goals, which can help in making AdonisJs the perfect fit for real-time apps.


Concerns

The big concerns in scaling web-sockets are

  1. They are stateful but starts stateless.
  2. How to notify clients connected to multiple servers.
  3. How to sync server's state with each other.

Stateful, but starts stateless

If you have any prior experience with Web-sockets, you do know that majority of frameworks ( including socket.io ) starts an HTTP connection with long polling, which later gets upgraded to a web-socket connection.

Now when these HTTP calls are being made, we need to make sure they reach to a single server. For that we have to implement sticky sessions on a load balancer, which makes sure that a request with X session goes to the same server, where it was created.

This was required because there wasn't proper browser support for Web-sockets and some private networks kill long-lived web-socket connections.

As far as browsers are concerned, all major browsers support web-sockets http://caniuse.com/#search=WebSocket and there are simple ways to tackle with long-lived connections killing.

The implementation of AdonisJs will use https://github.com/websockets/ws, which makes a pure Web-socket connection and thus there is no need of implementing sticky sessions.

Notifying clients

If your application is running on multiple servers, then you need a way of notifying users connected to these servers. For example

User A is connected to Server X. User B is connected to Server Y.

Now when User A sends a message, we need to send this message to Server Y, before it can reach User B.

One classic way to solve this problem is using the Redis pub/sub to notify all the servers connected to a single Redis server. This works great and used by many Socket libraries, even Ruby on Rails makes use of Redis pub/sub.

Wait wait wait! If Redis goes down, for sure your application also goes down with it. I will share the Adonis implementation in a while after the next section.

Sharing state

Delivering messages via Pub/Sub works excellent with Redis, but how about sharing state. For example:

We want to show a list of all the online users across multiple servers and notifying all servers when a new user connects/disconnects.

The naive way is to store this info inside Redis again ( since we are using it for pub/sub ) with a list of users for a given server. Now if a server dies, we will have orphan data in Redis living forever.

Adonis Combat

I have spent a good chunk of time building small demo’s to see what can be an ideal way to combat these issues and the answer is to remove the external dependency on Redis and instead make all servers talk to each other directly.

I am working on a small module which let you connect to servers inside the same network or across data centers using TCP. Each server will act as a server + client at the same time and uses the Gossip protocol to find when a server dies unexpectedly.

This is how it will look eventually.

Server X starts the server on PORT 3333 and client on PORT 3334. The job of the client is to connect to other multiple servers. Same goes for other servers too, they all need to run the actual server with a client that can connect to other servers.

Instead of using Redis for pub/sub, Adonis will use the Client -> Server TCP connection to notify all servers and share/sync state with each other.

If a server dies gracefully, it will notify all connected clients, and in case of unexpected failure, the gossip ping timeout will discover that one of the connected servers is not reachable anymore.

It helps in

  1. Removing 3rd party dependencies like Redis.
  2. There is no master, servers talks to each other.
  3. There is no global state storage, which means if a server dies, its state will be dropped with it and hence no more orphan data problems.

When can I use it?

I will start working on it from ( 11th November, 2017 ), and hence the entire module will take about a month and a half to get completed.

Once again, If you want to help, please consider donating on Patreon so that eventually I can spend more time on the framework.

thetutlage avatar Oct 23 '17 16:10 thetutlage

Hello, have you considered https://github.com/uNetworking/uWebSockets ? They claim to be like ws but better

G3z avatar Nov 09 '17 09:11 G3z

Really?

image

wxs77577 avatar Nov 21 '17 06:11 wxs77577

Not sure if I would trust a module that doesn't accept issues or is open for discussion. WebSockets https://github.com/uNetworking/uWebSockets/wiki/FAQ

dv336699 avatar Nov 21 '17 08:11 dv336699

Any updates?

herenickname avatar Dec 16 '17 07:12 herenickname

https://socketcluster.io/#!/ Scaling across multiple hosts https://socketcluster.io/#!/docs/scaling-horizontally

AlexMistVrn avatar Dec 28 '17 12:12 AlexMistVrn

This lightweight clusterWS alternative would be ideal to incorporate into this framework: https://github.com/ClusterWS/ClusterWS

Is there still interest in implementing WS? @thetutlage

siric avatar Jan 08 '18 08:01 siric

@siric1 It looks great, but again they rely on master and child nodes. The problem with a master is that if it goes down, everything else goes down with it.

And if we have to rely on master/child model, then why not simply use redis as the master node.

thetutlage avatar Jan 09 '18 08:01 thetutlage

Any updates?

fgvicente avatar Jan 10 '18 13:01 fgvicente

Any updates?

herenickname avatar Jan 10 '18 13:01 herenickname

I am working on it. Got a first basic version ready. Next it to make it working seamless within Node.js cluster, and then I may release it.

After that, following will follow

  1. Multiple servers support
  2. Presence

thetutlage avatar Jan 11 '18 11:01 thetutlage

Any updates on 4.0 WebSockets? Thank you @thetutlage

ivandrenjanin avatar Jan 24 '18 07:01 ivandrenjanin

a very necessary thing, which will decide a framework that we take as the basis of the project @thetutlage please do it 🙏

herenickname avatar Jan 24 '18 16:01 herenickname

Have you thought about using Primus with primus-cluster? From what I've heard this is the real deal when it comes to scaling.

marcus-sa avatar Jan 31 '18 14:01 marcus-sa

So how long will it take? Will it be released in 2018? @thetutlage

tebitobi avatar Feb 02 '18 07:02 tebitobi

120% in 2018 😝

I have a fulltime job, also have to manage dozen of issues every morning and then maintain the existing packages too

thetutlage avatar Feb 02 '18 16:02 thetutlage

@thetutlage you have been a lot more polite than I would have been :)

G3z avatar Feb 02 '18 16:02 G3z

Everyone has their own situations. Being polite is the least we can do for each other 😀

thetutlage avatar Feb 02 '18 16:02 thetutlage

Hello @thetutlage !! thank you for your work, It's very important!! any news?

mathiasgmz avatar Feb 06 '18 17:02 mathiasgmz

Hi @thetutlage , thanks for your work! but any update ?

CalvinLarano avatar Feb 07 '18 05:02 CalvinLarano

the hottest topic of all discussions :)

herenickname avatar Feb 08 '18 21:02 herenickname

Adonis is what makes me excited to get up and work on side projects! Would be awesome to have some info when we can expect websockets in 4.0 - weeks, months? :D

petarjs avatar Feb 10 '18 15:02 petarjs

Since I am done with 4.1 release, update indicative. This is what I have in my fulltime bucket.

Should be out in a month or so

thetutlage avatar Feb 10 '18 15:02 thetutlage

Hi @thetutlage I hope you 've been doing great lately, I am not js expert but I like challenges, I would like to contribute to adonisjs in any way useful, reach out to me in case you need some help.

cantwait avatar Feb 13 '18 21:02 cantwait

Hi @thetutlage , how is the websocket support do it? My complete respects for you man you are increidible! AdonisJS is my favorite framework so far

franciscosucre avatar Feb 19 '18 16:02 franciscosucre

Protocol paper on same https://github.com/adonisjs/adonis-websocket-protocol. Stay tuned, more to come

thetutlage avatar Feb 20 '18 06:02 thetutlage

@thetutlage I love you man!

cgalvar avatar Mar 02 '18 15:03 cgalvar

I assume it is ready by now. Saw your tweet about its documentation :)

shimjudavid avatar Mar 25 '18 06:03 shimjudavid

For minor projects can you use socket.io with the adonis.js? or is it no longer compatible?

Is there an example of adonis.js with socket.io?

EdZava avatar Jul 06 '18 13:07 EdZava

@EdZava What's the problem with the AdonisJs implementation of Websockets?

thetutlage avatar Jul 06 '18 13:07 thetutlage

hi @thetutlage, amazing your project, thanks for your work. I looked in the documentation but did not find it. it is possible to customize the socket id, similar to the io.engine.generateId for socket.io?

1729patrick avatar May 08 '19 18:05 1729patrick