adonisjs / discussion

Discussing about new features and sharing random thoughts: ⚠️ Not every request will be accepted
50 stars 4 forks source link

New age web sockets #51

Open thetutlage opened 6 years ago

thetutlage commented 6 years ago

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.

G3z commented 6 years ago

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

wxs77577 commented 6 years ago

Really?

image

dv336699 commented 6 years ago

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

herenickname commented 6 years ago

Any updates?

AlexMistVrn commented 6 years ago

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

siric commented 6 years ago

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

thetutlage commented 6 years ago

@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.

fgvicente commented 6 years ago

Any updates?

herenickname commented 6 years ago

Any updates?

thetutlage commented 6 years ago

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
ivandrenjanin commented 6 years ago

Any updates on 4.0 WebSockets? Thank you @thetutlage

herenickname commented 6 years ago

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

marcus-sa commented 6 years ago

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

tebitobi commented 6 years ago

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

thetutlage commented 6 years ago

120% in 2018 😝

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

G3z commented 6 years ago

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

thetutlage commented 6 years ago

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

mathiasgmz commented 6 years ago

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

CalvinLarano commented 6 years ago

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

herenickname commented 6 years ago

the hottest topic of all discussions :)

petarjs commented 6 years ago

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

thetutlage commented 6 years ago

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

cantwait commented 6 years ago

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.

franciscosucre commented 6 years ago

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

thetutlage commented 6 years ago

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

cgalvar commented 6 years ago

@thetutlage I love you man!

shimjudavid commented 6 years ago

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

EdZava commented 6 years ago

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?

thetutlage commented 6 years ago

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

1729patrick commented 5 years ago

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?

jcs224 commented 5 years ago

Any word about whether Adonis websockets can horizontally scale across several servers (rather than just within a cluster on a single server)? That would honestly be quite a game-changer!

JonhnyDev commented 3 years ago

It still doesn't work ... even following the cluster mode, making it compatible with PM2, adonis JS still can't send WebSocket notifications to multiple ports in a cluster mode.

I tried using the PM2 cluster mode and tenten doing the load balance and with multi-fork it didn't even work ...

I made some publications about: https://github.com/adonisjs/core/discussions/1406 https://github.com/adonisjs/core/discussions/1424

I read about: https://github.com/adonisjs/adonis-websocket-protocol/issues/4 https://forum.adonisjs.com/t/how-do-you-scale-your-adonis-apps/4973/2 https://forum.adonisjs.com/t/not-work-broadcast-using-websockets/2376/4 https://forum.adonisjs.com/t/scalability-recommendations/4518/5 https://forum.adonisjs.com/t/websocket-with-cluster/1186/6 https://forum.adonisjs.com/t/websocket-clustering/3618

and so far the only hope of making it work is with Redis even though it’s not ideal.

Does anyone know if adonisJS keeps trying to be compatible with cluster or multi-server mode? because what I see for 3 years now has topics about it without any with a clearer resolution on the subject ..