jrief / django-websocket-redis

Websockets for Django applications using Redis as message queue
http://django-websocket-redis.awesto.com/
MIT License
895 stars 221 forks source link

Each websocket connection results into a brand new socket connection to redis hence it implicitly limits the maximum number of websockets that could be established by using this library #295

Open sharrajesh opened 4 years ago

sharrajesh commented 4 years ago

I have the need to support a very large number (100k+) of websocket connections from clients that do not send much but which needs to be notified by the server (DRF) once in a while when some conditions are met.

A the moment I am running DWR inside uwsgi with --gevent=2000 and 5 workers per kubernetes pod which is replicated 10 times i.e. 2000510=100000

The problem I ran into is that each websocket connection at the moment has to subscribe to a redis pubsub channel which results into a brand new socket connection on the redis.

Since redis is shared across all of our pod I cannot horizontally scale the number of supported websocket connections by just increasing my pods.

I was load testing my server with thor or sockme.

My cursory look at the code suggests that I should be able to leverage pipes/events (https://lat.sk/2015/02/multiple-event-waiting-python-3/) and fewer actual redis pubsub channels to avoid a very large number redis_fd (https://github.com/jrief/django-websocket-redis/blob/master/ws4redis/wsgi_server.py#L119).

Basically for each websocket, I will create a pipe and store the pipe handle and client-id into a worker process address space as a hash table entry.

When the server notify the redis pubsub channel and that greenlet/thread is fired running inside DWR it will get the client-id. Here I will enable the "event" based upon the client-id received. Which will enable the correct websocket loop to awaken.

I wanted to make sure before I go this direction, I talk to the most believable people here. Am I total nuts or is there a better way to support a very large number of socket connection by still using DWR.

sharrajesh@gmail.com

jrief commented 4 years ago

Well, another possibility would be to add more Redis servers and interconnect between them. The reason ws4redis opens a connection to Redis for each socket is, because it wants transparently pass that data through to the client. Adding an Id and using that for dispatching adds another layer of complexity and I'm unsure if we should do that.

One much more elegant solution would be to go async. This is something I wanted to to anyway, since greenlets are not the best solution for scaling threads. It would however require a complete redesign of ws4redis and presumably not add any additional value compared to the Channels project, except for it's much simpler setup and configuration.

sharrajesh commented 4 years ago

Thank you @jrief

I am using this as a reference for my use case.