pythonflasksocket.iogunicorneventlet

Understanding Gunicorn Worker and Thread Configuration for Flask-SocketIO with Eventlet


I'm developing a Flask web application that uses SocketIO and am facing issues with configuring Gunicorn, particularly with the number of workers and threads. My server runs on Ubuntu with 32GB DDR4 memory and an i7 7700k CPU. I've tried several configurations, but I'm puzzled by the performance results and SocketIO errors I'm encountering. Here's what happens with different commands:

  1. Basic Gunicorn Command:
gunicorn --bind 0.0.0.0:5000 wsgi:app
Result: Extremely poor performance and SocketIO errors.
  1. Increased Workers and Threads:
gunicorn -w 12 -t 3 --bind 0.0.0.0:5000 wsgi:app
Result: Great performance but still SocketIO errors.
  1. Using Eventlet with One Worker:
gunicorn -k eventlet -w 1 -t 100 --bind 0.0.0.0:5000 wsgi:app
Result: Great performance and no SocketIO errors.
  1. Using Eventlet with Two Workers:
gunicorn -k eventlet -w 2 -t 100 --bind 0.0.0.0:5000 wsgi:app
Result: Great performance but back to SocketIO errors.

Given the above scenarios, I have several questions:

  1. Performance with Single Worker in Eventlet: Why am I getting good performance in scenario 3 with only a single Eventlet worker? How does this single worker manage to handle the load effectively?
  2. SocketIO Errors with Multiple Workers: Why do SocketIO errors reappear when I increase the number of workers (scenario 4) while using Eventlet? If eventlet -w 1 is allocating single worker for eventlet, then is my program being allocated extra workers automatically? If not then why is my app performing good?
  3. Optimal Configuration for Performance and Stability: Based on my server specs and the behavior observed, what would be the optimal Gunicorn configuration for balancing performance and stability with Flask-SocketIO and Eventlet?

Solution

    1. eventlet is good for IO bound tasks. So, you 'll get a good performance with this type worker. Thread option -t 100 mean the server will handle 100 request in the same time, when many requests come worker master load 100 request to child worker that deployed application. Because requests are mostly IO tasks, they are processed "concurrently" by eventlet mode. If you set a few --thread, the server is low performance
    2. Through the post: due to the limited load balancing algorithm used by gunicorn, it is not possible to use more than one worker process when using this web server. For that reason, all the examples above include the -w 1 option. So, if you use Flask-SocketIO version < 2.0, It doesn't support multiple workers and leads to errors. Each worker has a different memory area that leading client's request being divided among another worker that was not processed by the previous worker
    3. Again in the post at Using Multiple Workers, You must use Flask-SocketIO >= 2.0 and need a queue such as redis for many workers can get client connections of the other worker before increase number worker.