mirror of
https://github.com/Rainyy21/framework_note.git
synced 2026-10-10 23:30:28 -04:00
vault backup: 2026-06-01 23:17:01
This commit is contained in:
@@ -1,175 +0,0 @@
|
||||
---
|
||||
aliases:
|
||||
up: "[[00_devop_note]]"
|
||||
tags:
|
||||
- devop
|
||||
---
|
||||
|
||||
# Uvicorn and Gunicorn
|
||||
|
||||
Both are Python application servers — they run your Python web app and hand requests back and forth with a web server like Nginx. But they solve **different problems**, and you'll often see them used **together**.
|
||||
|
||||
The key split: **Gunicorn is WSGI** (synchronous), **Uvicorn is ASGI** (asynchronous).
|
||||
|
||||
## Quick refresher: WSGI vs ASGI
|
||||
|
||||
| | WSGI | ASGI |
|
||||
|---|---|---|
|
||||
| Spec | PEP 3333 | "Asynchronous Server Gateway Interface" |
|
||||
| Model | Sync, one request per worker at a time | Async, many concurrent requests per worker |
|
||||
| Frameworks | Django (classic), Flask | FastAPI, Starlette, Django (async views), Sanic |
|
||||
| Supports WebSockets? | No | Yes |
|
||||
| Supports HTTP/2, SSE? | No | Yes |
|
||||
|
||||
If your app uses `async def` view functions or WebSockets, you need ASGI.
|
||||
If it's a traditional Django/Flask app with `def` views, WSGI is fine.
|
||||
|
||||
---
|
||||
|
||||
## Gunicorn ("Green Unicorn")
|
||||
|
||||
A **WSGI** server. Mature, simple, battle-tested. The de facto default for Django/Flask in production.
|
||||
|
||||
### Why people pick it
|
||||
|
||||
- **Simple config** — most options are sensible by default
|
||||
- **Pre-fork worker model** — master process forks N workers; each worker handles one request at a time
|
||||
- **Stable** — has been the standard for years
|
||||
- **Good signal handling** — graceful reloads, zero-downtime restarts
|
||||
|
||||
### Minimal usage
|
||||
|
||||
```bash
|
||||
gunicorn myproject.wsgi:application --workers 4 --bind 0.0.0.0:8000
|
||||
```
|
||||
|
||||
Or with a config file `gunicorn.conf.py`:
|
||||
|
||||
```python
|
||||
bind = "unix:/tmp/myproject.sock"
|
||||
workers = 4
|
||||
worker_class = "sync" # default
|
||||
timeout = 30
|
||||
accesslog = "-"
|
||||
errorlog = "-"
|
||||
```
|
||||
|
||||
### Worker classes
|
||||
|
||||
Gunicorn lets you swap the worker type:
|
||||
|
||||
- `sync` — default, one request at a time per worker
|
||||
- `gthread` — threaded workers (good for I/O-bound apps)
|
||||
- `gevent` / `eventlet` — async via greenlets (legacy)
|
||||
- `uvicorn.workers.UvicornWorker` — **this is the bridge to ASGI** (see below)
|
||||
|
||||
### How many workers?
|
||||
|
||||
Rule of thumb: `(2 × CPU cores) + 1`. So a 4-core box → 9 workers.
|
||||
|
||||
---
|
||||
|
||||
## Uvicorn
|
||||
|
||||
An **ASGI** server built on `uvloop` and `httptools` — both written in C, which makes it very fast. It's the standard server for FastAPI and modern async Python web apps.
|
||||
|
||||
### Why people pick it
|
||||
|
||||
- **Async-native** — handles thousands of concurrent connections per worker
|
||||
- **WebSockets + HTTP/2 support**
|
||||
- **Very fast** — uvloop is a drop-in faster replacement for asyncio's event loop
|
||||
- **Lightweight** — small dependency surface
|
||||
|
||||
### Minimal usage
|
||||
|
||||
```bash
|
||||
uvicorn myproject.main:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
For development with auto-reload:
|
||||
|
||||
```bash
|
||||
uvicorn myproject.main:app --reload
|
||||
```
|
||||
|
||||
### Where it falls short alone
|
||||
|
||||
Uvicorn by itself is **single-process**. To use multiple CPU cores in production, you need to either:
|
||||
|
||||
1. Run multiple Uvicorn instances behind a load balancer, OR
|
||||
2. Run Uvicorn **inside Gunicorn** as worker processes (the common pattern)
|
||||
|
||||
---
|
||||
|
||||
## The common production combo: Gunicorn + Uvicorn
|
||||
|
||||
This is the standard FastAPI production setup:
|
||||
|
||||
```bash
|
||||
gunicorn myproject.main:app \
|
||||
--workers 4 \
|
||||
--worker-class uvicorn.workers.UvicornWorker \
|
||||
--bind 0.0.0.0:8000
|
||||
```
|
||||
|
||||
What's happening:
|
||||
|
||||
- **Gunicorn** is the process manager — forks workers, handles signals, restarts dead workers, manages graceful shutdowns
|
||||
- **Uvicorn** runs *inside* each Gunicorn worker — provides the ASGI event loop that runs your async code
|
||||
|
||||
You get the best of both: Gunicorn's robust process management + Uvicorn's async performance.
|
||||
|
||||
### Visual
|
||||
|
||||
```
|
||||
┌─ Uvicorn worker (async loop) ─ FastAPI app
|
||||
│
|
||||
Nginx → Gunicorn ├─ Uvicorn worker (async loop) ─ FastAPI app
|
||||
(master) │
|
||||
├─ Uvicorn worker (async loop) ─ FastAPI app
|
||||
│
|
||||
└─ Uvicorn worker (async loop) ─ FastAPI app
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Decision guide
|
||||
|
||||
| Your situation | Use |
|
||||
|---|---|
|
||||
| Django (sync), Flask | **Gunicorn** alone |
|
||||
| FastAPI, Starlette, async Django | **Gunicorn + UvicornWorker** |
|
||||
| Local dev, single FastAPI process | **Uvicorn** alone (`--reload`) |
|
||||
| WebSockets required | Must be ASGI → **Uvicorn** (alone or under Gunicorn) |
|
||||
| Legacy app, uWSGI already configured | [[uWSGI]] — no urgent need to migrate |
|
||||
|
||||
---
|
||||
|
||||
## Comparison with [[uWSGI]]
|
||||
|
||||
| | Gunicorn | Uvicorn | uWSGI |
|
||||
|---|---|---|---|
|
||||
| Protocol | WSGI | ASGI | WSGI (+ many others) |
|
||||
| Async support | No (sync workers) | Yes (native) | Limited |
|
||||
| Config complexity | Low | Low | **Very high** |
|
||||
| WebSockets | No | Yes | Partial |
|
||||
| Speed (raw) | Good | **Fastest** for async | Fast but heavy |
|
||||
| Maintained actively | Yes | Yes | Concerns |
|
||||
| Best for | Django/Flask | FastAPI | Legacy / specialized features |
|
||||
|
||||
---
|
||||
|
||||
## Common gotchas
|
||||
|
||||
1. **Don't run Uvicorn `--reload` in production** — it's a dev-only feature, has overhead and isn't safe.
|
||||
2. **Workers ≠ threads** — each Gunicorn worker is a separate Python process with its own memory. Database connections, in-memory caches, etc. are *not* shared between workers.
|
||||
3. **Timeouts matter** — Gunicorn's default `timeout=30s` will kill workers running long async tasks. Tune it for your workload.
|
||||
4. **Nginx is still recommended in front** — Uvicorn/Gunicorn don't do SSL termination, static files, or rate limiting as well as Nginx.
|
||||
5. **Logging** — by default both log to stdout/stderr; route to your log aggregator via container stdout (`-` in config).
|
||||
|
||||
---
|
||||
|
||||
## Related
|
||||
|
||||
- [[uWSGI]] — older alternative, mostly WSGI
|
||||
- [[Apache Tomcat]] — the Java equivalent (servlet container)
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
aliases:
|
||||
up: "[[00_devop_note]]"
|
||||
tags:
|
||||
- devop
|
||||
---
|
||||
w
|
||||
# What is uWSGI?
|
||||
|
||||
**uWSGI** is an application server that sits between a web server (like Nginx or Apache) and a Python web application (like Django, Flask, or FastAPI). It runs your Python code and handles incoming web requests.
|
||||
|
||||
The name comes from **WSGI** (Web Server Gateway Interface), which is the standard Python spec (PEP 3333) that defines how web servers talk to Python applications. The lowercase "u" is the Greek letter μ (micro), suggesting it's lightweight — though in practice it grew into a full-featured server.
|
||||
|
||||
## Why do we need it?
|
||||
|
||||
A plain web server like Nginx doesn't know how to execute Python code. It only serves static files (HTML, CSS, images) and forwards dynamic requests elsewhere. You need a process that:
|
||||
|
||||
1. Loads your Python application into memory
|
||||
2. Receives requests from the web server
|
||||
3. Calls your Python code with the request
|
||||
4. Returns the response back to the web server
|
||||
|
||||
That middle process is uWSGI (or alternatives like Gunicorn).
|
||||
|
||||
## The typical stack
|
||||
|
||||
```
|
||||
Browser → Nginx → uWSGI → Python app (Django/Flask)
|
||||
```
|
||||
|
||||
- **Nginx**: handles SSL, static files, load balancing, gzip, caching
|
||||
- **uWSGI**: runs Python workers, manages processes/threads
|
||||
- **Python app**: your business logic
|
||||
|
||||
Nginx and uWSGI usually talk over a **Unix socket** (fast, local) or a TCP port. The protocol between them is called the **uwsgi protocol** (lowercase) — a binary protocol that's faster than plain HTTP.
|
||||
|
||||
## Key features
|
||||
|
||||
- **Process management**: spawns multiple worker processes to handle concurrent requests
|
||||
- **Threading**: each worker can run multiple threads
|
||||
- **Auto-reload**: restart workers when code changes (dev mode)
|
||||
- **Emperor mode**: one master process supervising many vassal apps
|
||||
- **Cheaper mode**: dynamically scale workers up/down based on load
|
||||
- **Multi-language**: despite the name, also supports Ruby, Perl, Go, etc.
|
||||
|
||||
## Minimal config example
|
||||
|
||||
A typical `uwsgi.ini`:
|
||||
|
||||
```ini
|
||||
[uwsgi]
|
||||
module = myproject.wsgi:application
|
||||
master = true
|
||||
processes = 4
|
||||
threads = 2
|
||||
socket = /tmp/myproject.sock
|
||||
chmod-socket = 660
|
||||
vacuum = true
|
||||
die-on-term = true
|
||||
```
|
||||
|
||||
- `module`: entry point (the WSGI callable)
|
||||
- `processes`: how many worker processes to fork
|
||||
- `socket`: where Nginx connects to
|
||||
- `vacuum`: clean up the socket on exit
|
||||
- `die-on-term`: shut down cleanly on SIGTERM
|
||||
|
||||
## Running it
|
||||
|
||||
```bash
|
||||
uwsgi --ini uwsgi.ini
|
||||
```
|
||||
|
||||
Or in production, run it under **systemd** so it restarts on failure.
|
||||
|
||||
## uWSGI vs Gunicorn
|
||||
|
||||
Both are WSGI servers. The community has largely shifted toward **Gunicorn** because:
|
||||
|
||||
- Simpler config
|
||||
- Fewer footguns
|
||||
- Easier to deploy
|
||||
|
||||
uWSGI is more feature-rich and faster in some benchmarks, but its config surface is huge (hundreds of options) and the project has had governance/maintenance concerns. For new projects, Gunicorn behind Nginx is the common default.
|
||||
|
||||
## When you'll see uWSGI
|
||||
|
||||
- Legacy Django/Flask deployments
|
||||
- Setups that need uWSGI-specific features (Emperor, cheaper, etc.)
|
||||
- Docker images for older Python web apps
|
||||
|
||||
## Related
|
||||
|
||||
- [[Apache Tomcat]] — the Java equivalent role (servlet container running Java apps behind a web server)
|
||||
Reference in New Issue
Block a user