Tune gunicorn/Postgres/Redis for a memory-limited server
- gunicorn: 3 workers -> 2 (this workload isn't CPU-bound per DEPLOYMENT.md's own sizing), add --preload so workers share immutable memory via copy-on-write instead of each independently importing Django, add --max-requests so a worker that renders a WeasyPrint invoice doesn't carry that memory forever. - Postgres: trim shared_buffers/max_connections from the image defaults (128MB/100), sized for a ~0.2GB dataset instead. - Redis: cap with --maxmemory as a ceiling, not a saving.
This commit is contained in:
@@ -423,7 +423,8 @@ So do not size for the data. Size for the **processes**.
|
||||
|
||||
### What actually consumes the box
|
||||
|
||||
Measured, running this app under gunicorn with `DEBUG=False`:
|
||||
Measured, running this app under gunicorn with `DEBUG=False`, before the tuning below —
|
||||
`--workers 3`, no `--preload`, Postgres and Redis on their image defaults:
|
||||
|
||||
| | memory |
|
||||
|---|---|
|
||||
@@ -434,6 +435,13 @@ Measured, running this app under gunicorn with `DEBUG=False`:
|
||||
| OS + Docker daemon | ~400 MB |
|
||||
| **steady state** | **~1.0–1.2 GB** |
|
||||
|
||||
Since then, `Dockerfile`/`compose.yaml` were tuned for smaller boxes: `--workers 2 --preload`
|
||||
(one fewer duplicated Django process, and `--preload` shares immutable memory across workers
|
||||
via copy-on-write instead of each worker importing Django independently), plus trimmed Postgres
|
||||
`shared_buffers`/`max_connections` and a Redis `--maxmemory` cap. Expect the gunicorn and
|
||||
Postgres rows to come in lower than above — not yet re-measured, so treat the table as the
|
||||
shape of where memory goes rather than exact numbers on the current config.
|
||||
|
||||
2 GB would run it. 4 GB is the recommendation for three reasons, all of which are the kind of
|
||||
thing that bites at the worst moment:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user