docs(compose): the app CPU cap cannot separate compression from the request path
The comment read "CPU ceiling for the two image workers + ffmpeg poster extraction", which describes a separation Docker cannot make: `compression.rs` runs that work in `tokio::task::spawn_blocking` — same process, same cgroup as every Axum handler — and `cpus`/`cpu_shares` are per-container. What actually happens is worth knowing when sizing this box: `cpu.max` is `120000 100000`, so two CPU-pegged blocking workers exhaust the 120 ms quota after ~60 ms of each 100 ms period and the kernel freezes the WHOLE cgroup — uploads, feed and SSE included — for the rest of it. Over a 100-photo burst that is ~210 s during which every request can eat up to 40 ms of throttle. The value stays at 1.2: an app that can take both cores starves Postgres, and every request path goes through Postgres. A slightly stalled request beats a starved database. The comment now says which knob actually shortens the backlog (COMPRESSION_WORKER_CONCURRENCY) rather than implying this one does.
This commit is contained in:
@@ -178,9 +178,22 @@ services:
|
|||||||
# Bounds a runaway ffmpeg transcode (large uploads, 2 workers) so it can't
|
# Bounds a runaway ffmpeg transcode (large uploads, 2 workers) so it can't
|
||||||
# OOM the single box and take down Postgres.
|
# OOM the single box and take down Postgres.
|
||||||
memory: 1G
|
memory: 1G
|
||||||
# CPU ceiling for the two image workers + ffmpeg poster extraction. Bounded below
|
# CPU ceiling for the WHOLE app container. Bounded below 2.0 so it can never take both
|
||||||
# 2.0 so the app can never take both cores on its own.
|
# cores on its own, which is what protects Postgres.
|
||||||
# COMPRESSION_WORKER_CONCURRENCY=2 is the memory bound; this is the CPU one.
|
# COMPRESSION_WORKER_CONCURRENCY=2 is the memory bound; this is the CPU one.
|
||||||
|
#
|
||||||
|
# It does NOT cap "the two image workers + ffmpeg" separately from the request path, as
|
||||||
|
# this used to claim. `compression.rs` runs that work in `tokio::task::spawn_blocking` —
|
||||||
|
# same process, same cgroup as every Axum handler — and `cpus`/`cpu_shares` are
|
||||||
|
# per-container, so nothing here can tell them apart. Concretely: `cpu.max` is
|
||||||
|
# `120000 100000`, so two CPU-pegged blocking workers exhaust the 120 ms quota after
|
||||||
|
# ~60 ms of each 100 ms period and the kernel then freezes the ENTIRE cgroup — uploads,
|
||||||
|
# feed and SSE included — for the remainder. Across a 100-photo burst (~210 s of
|
||||||
|
# draining) every request in that window can eat up to 40 ms of throttle stall.
|
||||||
|
#
|
||||||
|
# Kept anyway: an app that can take both cores starves Postgres, and every request path
|
||||||
|
# goes through Postgres. A slightly stalled request beats a starved database. If the
|
||||||
|
# backlog needs to drain faster, the knob is COMPRESSION_WORKER_CONCURRENCY, not this.
|
||||||
cpus: '1.2'
|
cpus: '1.2'
|
||||||
# Half the default weight, and this is the ceiling's other half: the cap alone leaves
|
# Half the default weight, and this is the ceiling's other half: the cap alone leaves
|
||||||
# 0.8 vCPU for db + frontend + caddy, which frontend and caddy can consume between them.
|
# 0.8 vCPU for db + frontend + caddy, which frontend and caddy can consume between them.
|
||||||
|
|||||||
Reference in New Issue
Block a user