jrief / django-websocket-redis

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

uWSGI Only Allowing <num_worker> Connections #166

Closed pkkid closed 8 years ago

pkkid commented 8 years ago

I don't expect you to be debug my environment, but was hoping you might have some ideas on where I should be looking?

I've can't get nginx / uwsgi / ws4redis to allow more connections than the specified number of workers. This seems incorrect as the docs explain that the configuration should allow for 1000 connections with workers=2 and gevent=1000.

I've been reading all night and trying everything I could think of. If I increase the number of workers, I can get that many websocket connections. I assume the problem has something to do with gevent not properly doing it's thing. I tried adding the gevent.monkey.patch_thread() lines to the top of the wsgi_web.py as I saw you did that in the example but that also had no affect. I am not doing anything fancy in the application, just running the straight unmodified version of uWSGIWebsocketServer. My configuration looks like the following:

Nginx Config
server {
  listen 443 ssl;
  listen [::]:443 ssl;
  server_name mywebsite.com;
  add_header Strict-Transport-Security "max-age=31536000";
  ssl on; ssl_prefer_server_ciphers on;
  ssl_stapling on; ssl_stapling_verify on;
  ssl_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/mywebsite.com/privkey.pem;
  ssl_trusted_certificate /etc/letsencrypt/live/mywebsite.com/fullchain.pem;
  location /static/ {
    alias /home/mikes/Projects/mywebsite/pk/collectstatic/;
  }
  location /ws/ {
    proxy_pass http://unix:/home/mikes/Projects/mywebsite/web.sock;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_buffers 8 32k;
    proxy_buffer_size 64k;
  }
  location / {
    include uwsgi_params;
    uwsgi_pass unix:/home/mikes/Projects/mywebsite/django.sock;
  }
}
uwsgi-web.ini (running via emperor)
[uwsgi]
plugins = python3,gevent
chdir = /home/mikes/Projects/mywebsite
virtualenv = /home/mikes/.virtualenvs/mywebsite
module = pk.wsgi_web:application
pidfile2 = /home/mikes/Projects/mywebsite/web.pid
http-socket = /home/mikes/Projects/mywebsite/web.sock
http-websockets = true
chown-socket = mikes:www-data
chmod-socket = 664
uid = mikes
gid = mikes

master = true
no-orphans = true
vacuum = true
workers = 2
max-requests = 5000
gevent = 123
please-fail = true
wsgi_web.py
import os
import gevent.socket
import redis.connection
redis.connection.socket = gevent.socket
os.environ.update(DJANGO_SETTINGS_MODULE='pk.settings.settings')
from ws4redis.uwsgi_runserver import uWSGIWebsocketServer
application = uWSGIWebsocketServer()
pkkid commented 8 years ago

It took some digging, but I figured this out. The big difference between your configuration and mine was that I am running Django with Python3 (as well as being on Ubutnu 15.10). So I learned the following things, that should probably be added to the documentation as Python3 is coming.

The problems on Ubuntu 15.10 are that the apt-get version of uWSGI in does not have the gevent support. There is also no uwsgi-plugin-gevent-python3 package in the repos either. The good news however is that uwsgi can be installed with gevent support very easily through pip, but we need to integrate that into systemd to get it running all nice.

Install uWSGI for Python3 with Gevent Support
# Install dependencies for pcre support
sudo apt-get install python3-pip
sudo apt-get install libpcre3 libpcre3-dev   # for pcre support

# Remove current uwsgi installations & reinstall via pip3.
sudo apt-get remove uwsgi
sudo -H pip3 uninstall uwsgi
sudo -H pip3 install uwsgi
Create a Systemd Script

Edit the file with sudo vim /etc/systemd/system/uwsgi.service.

# Systemd Script for uWSGI.
# location: /etc/systemd/system/
[Unit]
Description=uWSGI application server in Emperor mode

[Service]
ExecStart=/usr/local/bin/uwsgi --master --die-on-term --emperor /etc/uwsgi/apps-enabled
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=uwsgi.service

Then you can start and stop the service with sudo systemctl start uwsgi. The configurations above all work great, except that I simply needed to remove the lines plugin = python3,gevent from both ini files. It doesn't matter since we compiled uwsgi via python3 (or pip3). Also the gevent plugin is enabled by default when installing via pip.