Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New age web sockets #51

Open
thetutlage opened this issue Oct 23, 2017 · 32 comments
Open

New age web sockets #51

thetutlage opened this issue Oct 23, 2017 · 32 comments

Comments

@thetutlage
Copy link
Member

@thetutlage thetutlage commented Oct 23, 2017

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
Copy link

@G3z G3z commented Nov 9, 2017

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

@wxs77577
Copy link

@wxs77577 wxs77577 commented Nov 21, 2017

Really?

image

@diego-vieira
Copy link

@diego-vieira diego-vieira commented Nov 21, 2017

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

@ekifox
Copy link

@ekifox ekifox commented Dec 16, 2017

Any updates?

@siric
Copy link

@siric siric commented Jan 8, 2018

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
Copy link
Member Author

@thetutlage thetutlage commented Jan 9, 2018

@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
Copy link

@fgvicente fgvicente commented Jan 10, 2018

Any updates?

1 similar comment
@ekifox
Copy link

@ekifox ekifox commented Jan 10, 2018

Any updates?

@thetutlage
Copy link
Member Author

@thetutlage thetutlage commented Jan 11, 2018

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
Copy link

@ivandrenjanin ivandrenjanin commented Jan 24, 2018

Any updates on 4.0 WebSockets? Thank you @thetutlage

@ekifox
Copy link

@ekifox ekifox commented Jan 24, 2018

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

@marcus-sa
Copy link

@marcus-sa marcus-sa commented Jan 31, 2018

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

@bilguun42
Copy link

@bilguun42 bilguun42 commented Feb 2, 2018

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

@thetutlage
Copy link
Member Author

@thetutlage thetutlage commented Feb 2, 2018

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
Copy link

@G3z G3z commented Feb 2, 2018

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

@thetutlage
Copy link
Member Author

@thetutlage thetutlage commented Feb 2, 2018

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

@mathiasgmz
Copy link

@mathiasgmz mathiasgmz commented Feb 6, 2018

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

@CalvinLarano
Copy link

@CalvinLarano CalvinLarano commented Feb 7, 2018

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

@ekifox
Copy link

@ekifox ekifox commented Feb 8, 2018

the hottest topic of all discussions :)

@petarjs
Copy link

@petarjs petarjs commented Feb 10, 2018

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
Copy link
Member Author

@thetutlage thetutlage commented Feb 10, 2018

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
Copy link

@cantwait cantwait commented Feb 13, 2018

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
Copy link

@franciscosucre franciscosucre commented Feb 19, 2018

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
Copy link
Member Author

@thetutlage thetutlage commented Feb 20, 2018

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

@cgalvar
Copy link

@cgalvar cgalvar commented Mar 2, 2018

@thetutlage I love you man!

@shimjudavid
Copy link

@shimjudavid shimjudavid commented Mar 25, 2018

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

@EdZava
Copy link

@EdZava EdZava commented Jul 6, 2018

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
Copy link
Member Author

@thetutlage thetutlage commented Jul 6, 2018

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

@patrickbattisti
Copy link

@patrickbattisti patrickbattisti commented May 8, 2019

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
Copy link

@jcs224 jcs224 commented May 21, 2019

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
Copy link

@JonhnyDev JonhnyDev commented Aug 10, 2020

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:
adonisjs/core#1406
adonisjs/core#1424

I read about:
adonisjs/adonis-websocket-protocol#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 ..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
You can’t perform that action at this time.