mirror of
https://github.com/frappe/gunicorn.git
synced 2026-07-08 05:31:29 +08:00
docs: Redesign architecture page with visual components
Add tabbed worker types, comparison table, decision guide admonitions, and scaling callouts. Rename master to arbiter throughout.
This commit is contained in:
parent
571bc121d1
commit
c959daeb82
@ -3,81 +3,201 @@
|
|||||||
|
|
||||||
A brief look at Gunicorn's architecture.
|
A brief look at Gunicorn's architecture.
|
||||||
|
|
||||||
## Server model
|
## Server Model
|
||||||
|
|
||||||
Gunicorn uses a pre-fork worker model: a master process manages worker
|
Gunicorn uses a **pre-fork worker model**: an arbiter process manages worker
|
||||||
processes, while the workers handle requests and responses. The master never
|
processes, while the workers handle requests and responses. The arbiter never
|
||||||
touches individual client sockets.
|
touches individual client sockets.
|
||||||
|
|
||||||
### Master
|
<div class="pillars" markdown>
|
||||||
|
|
||||||
The master process listens for signals (TTIN, TTOU, CHLD, etc.) and adjusts the
|
<div class="pillar" markdown>
|
||||||
worker pool accordingly. `TTIN`/`TTOU` change the number of workers; `CHLD`
|
<div class="pillar__icon">⚖️</div>
|
||||||
indicates a worker exited and must be restarted.
|
|
||||||
|
|
||||||
### Sync workers
|
### Arbiter
|
||||||
|
|
||||||
The default `sync` worker handles one request at a time. Errors affect only the
|
Orchestrates the worker pool. Listens for signals (`TTIN`, `TTOU`, `CHLD`,
|
||||||
current request. Because connections close after each response, persistent
|
`HUP`) to adjust workers, restart them on failure, or reload configuration.
|
||||||
connections are not supported even if you set `Keep-Alive` headers manually.
|
</div>
|
||||||
|
|
||||||
### Async workers
|
<div class="pillar" markdown>
|
||||||
|
<div class="pillar__icon">⚙️</div>
|
||||||
|
|
||||||
Async workers are powered by [greenlets](https://github.com/python-greenlet/greenlet)
|
### Worker Pool
|
||||||
through [Eventlet](http://eventlet.net/) or [Gevent](http://www.gevent.org/).
|
|
||||||
Most apps work without modification, though full compatibility may require
|
|
||||||
patches (for example installing [`psycogreen`](https://github.com/psycopg/psycogreen/)
|
|
||||||
when using [Psycopg](http://initd.org/psycopg/)). Some apps that depend on the
|
|
||||||
original blocking behaviour may not be compatible.
|
|
||||||
|
|
||||||
### Gthread workers
|
Each worker handles requests independently. Worker types determine
|
||||||
|
concurrency model: sync, threaded, or async via greenlets/asyncio.
|
||||||
|
</div>
|
||||||
|
|
||||||
`gthread` is a threaded worker. The main loop accepts connections and places
|
<div class="pillar" markdown>
|
||||||
them in a thread pool. Keep-alive connections return to the pool to await
|
<div class="pillar__icon">📡</div>
|
||||||
further events; idle connections close after the keepalive timeout.
|
|
||||||
|
|
||||||
### Tornado workers
|
### Signal Communication
|
||||||
|
|
||||||
A Tornado worker class exists for Tornado-based applications. While it can
|
`TTIN`/`TTOU` adjust worker count. `CHLD` triggers restart of crashed
|
||||||
serve WSGI apps, this configuration is not recommended.
|
workers. `HUP` reloads configuration. See [Signals](signals.md).
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Worker Types
|
||||||
|
|
||||||
|
Choose a worker type based on your application's needs.
|
||||||
|
|
||||||
|
=== "Sync"
|
||||||
|
|
||||||
|
The **default** worker. Handles one request at a time per worker.
|
||||||
|
|
||||||
|
- Simple and predictable
|
||||||
|
- Errors affect only the current request
|
||||||
|
- No keep-alive support (connections close after response)
|
||||||
|
- Requires a buffering proxy (nginx, HAProxy) for production
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Gthread"
|
||||||
|
|
||||||
|
Threaded worker with a **thread pool** per worker process.
|
||||||
|
|
||||||
|
- Supports keep-alive connections
|
||||||
|
- Good balance of concurrency and simplicity
|
||||||
|
- Threads share memory (lower footprint than workers)
|
||||||
|
- Idle connections close after keepalive timeout
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app -k gthread --threads 4
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Gevent"
|
||||||
|
|
||||||
|
**Greenlet-based** async worker using [Gevent](http://www.gevent.org/).
|
||||||
|
|
||||||
|
- Handles thousands of concurrent connections
|
||||||
|
- Supports keep-alive, WebSockets, long-polling
|
||||||
|
- May require patches for some libraries (e.g., `psycogreen` for Psycopg)
|
||||||
|
- Not compatible with code that relies on blocking behavior
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app -k gevent --worker-connections 1000
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "Eventlet"
|
||||||
|
|
||||||
|
**Greenlet-based** async worker using [Eventlet](http://eventlet.net/).
|
||||||
|
|
||||||
|
- Similar capabilities to Gevent
|
||||||
|
- Handles high concurrency for I/O-bound apps
|
||||||
|
- Some libraries may need compatibility patches
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app -k eventlet --worker-connections 1000
|
||||||
|
```
|
||||||
|
|
||||||
|
=== "ASGI"
|
||||||
|
|
||||||
|
Native **asyncio** support for modern async frameworks.
|
||||||
|
|
||||||
|
- For FastAPI, Starlette, Quart, and other ASGI apps
|
||||||
|
- Full async/await support
|
||||||
|
- See the [ASGI Guide](asgi.md) for details
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app -k uvicorn.workers.UvicornWorker
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comparison
|
||||||
|
|
||||||
|
| Worker | Concurrency Model | Keep-Alive | Best For |
|
||||||
|
|--------|-------------------|------------|----------|
|
||||||
|
| `sync` | 1 request/worker | ❌ | CPU-bound apps behind a proxy |
|
||||||
|
| `gthread` | Thread pool | ✅ | Mixed workloads, moderate concurrency |
|
||||||
|
| `gevent` | Greenlets | ✅ | I/O-bound, WebSockets, streaming |
|
||||||
|
| `eventlet` | Greenlets | ✅ | I/O-bound, long-polling |
|
||||||
|
| ASGI workers | AsyncIO | ✅ | Modern async frameworks (FastAPI, etc.) |
|
||||||
|
|
||||||
|
!!! tip "Quick Decision Guide"
|
||||||
|
|
||||||
|
- **Simple app behind nginx?** → `sync` (default)
|
||||||
|
- **Need keep-alive or moderate concurrency?** → `gthread`
|
||||||
|
- **WebSockets, streaming, long-polling?** → `gevent` or `eventlet`
|
||||||
|
- **FastAPI, Starlette, or async framework?** → ASGI worker
|
||||||
|
|
||||||
|
## When to Use Async Workers
|
||||||
|
|
||||||
|
Synchronous workers assume your app is CPU or network bound and avoids
|
||||||
|
indefinite blocking operations. Use async workers when you have:
|
||||||
|
|
||||||
|
- Long blocking calls (external APIs, slow databases)
|
||||||
|
- Direct internet traffic without a buffering proxy
|
||||||
|
- Streaming request/response bodies
|
||||||
|
- Long polling or Comet patterns
|
||||||
|
- WebSockets
|
||||||
|
|
||||||
|
!!! info "Testing Slow Clients"
|
||||||
|
|
||||||
|
Tools like [Hey](https://github.com/rakyll/hey) can simulate slow responses
|
||||||
|
to test how your configuration handles them.
|
||||||
|
|
||||||
|
## Scaling
|
||||||
|
|
||||||
|
### How Many Workers?
|
||||||
|
|
||||||
|
!!! warning "Don't Over-Scale"
|
||||||
|
|
||||||
|
Workers ≠ clients. Gunicorn typically needs only **4–12 workers** to handle
|
||||||
|
heavy traffic. Too many workers waste resources and can reduce throughput.
|
||||||
|
|
||||||
|
Start with this formula and adjust under load:
|
||||||
|
|
||||||
|
```
|
||||||
|
workers = (2 × CPU cores) + 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `TTIN`/`TTOU` signals to adjust the worker count at runtime.
|
||||||
|
|
||||||
|
### How Many Threads?
|
||||||
|
|
||||||
|
With the `gthread` worker, you can combine workers and threads:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gunicorn myapp:app -k gthread --workers 4 --threads 2
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! info "Threads vs Workers"
|
||||||
|
|
||||||
|
- **Threads** share memory → lower footprint
|
||||||
|
- **Workers** isolate failures → better fault tolerance
|
||||||
|
- Combine both for the best of both worlds
|
||||||
|
|
||||||
|
Threads can extend request time beyond the worker timeout while still
|
||||||
|
notifying the arbiter. The optimal mix depends on your runtime (CPython vs
|
||||||
|
PyPy) and workload.
|
||||||
|
|
||||||
|
## Configuration Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Sync (default) - simple apps behind nginx
|
||||||
|
gunicorn myapp:app
|
||||||
|
|
||||||
|
# Gthread - keep-alive and thread concurrency
|
||||||
|
gunicorn myapp:app -k gthread --workers 4 --threads 4
|
||||||
|
|
||||||
|
# Gevent - high concurrency for I/O-bound apps
|
||||||
|
gunicorn myapp:app -k gevent --workers 4 --worker-connections 1000
|
||||||
|
|
||||||
|
# Eventlet - alternative async worker
|
||||||
|
gunicorn myapp:app -k eventlet --workers 4 --worker-connections 1000
|
||||||
|
|
||||||
|
# ASGI - FastAPI/Starlette with Uvicorn worker
|
||||||
|
gunicorn myapp:app -k uvicorn.workers.UvicornWorker --workers 4
|
||||||
|
```
|
||||||
|
|
||||||
<span id="asyncio-workers"></span>
|
<span id="asyncio-workers"></span>
|
||||||
### AsyncIO workers
|
|
||||||
|
|
||||||
Use third-party workers to pair Gunicorn with asyncio frameworks (see the
|
!!! note "Third-Party AsyncIO Workers"
|
||||||
|
|
||||||
|
For asyncio frameworks, you can also use third-party workers. See the
|
||||||
[aiohttp deployment guide](https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn)
|
[aiohttp deployment guide](https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn)
|
||||||
or the [Flask aiohttp example](https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py)).
|
for examples.
|
||||||
|
|
||||||
## Choosing a worker type
|
|
||||||
|
|
||||||
Synchronous workers assume your app is CPU/network bound and avoids indefinite
|
|
||||||
operations. Any outbound HTTP calls or other blocking behaviour benefit from an
|
|
||||||
async worker. Because synchronous workers are vulnerable to slow clients,
|
|
||||||
Gunicorn requires a buffering proxy in front of the default configuration. Tools
|
|
||||||
like [Hey](https://github.com/rakyll/hey) can simulate slow responses to test
|
|
||||||
this scenario.
|
|
||||||
|
|
||||||
Examples that need async workers:
|
|
||||||
|
|
||||||
- Long blocking calls (outbound web services)
|
|
||||||
- Direct internet traffic (no buffering proxy)
|
|
||||||
- Streaming request/response bodies
|
|
||||||
- Long polling
|
|
||||||
- WebSockets / Comet
|
|
||||||
|
|
||||||
## How many workers?
|
|
||||||
|
|
||||||
Do **not** scale workers to match client count. Gunicorn usually needs only 4–12
|
|
||||||
workers to handle heavy traffic. Start with `(2 * num_cores) + 1` and adjust
|
|
||||||
under load using `TTIN`/`TTOU`.
|
|
||||||
|
|
||||||
Too many workers waste resources and can reduce throughput.
|
|
||||||
|
|
||||||
## How many threads?
|
|
||||||
|
|
||||||
Since Gunicorn 19 you can set `--threads` (with the `gthread` worker) to process
|
|
||||||
requests concurrently. Threads can extend request time beyond the worker
|
|
||||||
timeout while still notifying the master. The optimal mix of threads and worker
|
|
||||||
processes depends on the runtime (for example CPython vs. Jython). Threads share
|
|
||||||
memory, lowering footprint, and still allow reloads because application code is
|
|
||||||
loaded in worker processes.
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user