Skip to content

Commit 0d04947

Browse files
committed
docs: add issue 29 spec and baseline evidence
Refs: #29
1 parent 4a8d1fc commit 0d04947

4 files changed

Lines changed: 230 additions & 0 deletions

File tree

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Research high CPU load after UDP uptime recovery
2+
3+
**Issue**: [#29](https://github.com/torrust/torrust-tracker-demo/issues/29)
4+
**Related**:
5+
[#21](https://github.com/torrust/torrust-tracker-demo/issues/21),
6+
[#19](https://github.com/torrust/torrust-tracker-demo/issues/19)
7+
8+
## Overview
9+
10+
The UDP uptime problem tracked in [#21](https://github.com/torrust/torrust-tracker-demo/issues/21)
11+
appears resolved: newTrackon is now healthy again after the conntrack fix and server resize.
12+
However, the live server is still running at a high CPU load, which leaves limited headroom for
13+
future traffic growth and may become the next reliability risk even before external uptime drops.
14+
15+
This issue tracks a controlled investigation and remediation plan for the remaining CPU pressure.
16+
The work should change only one variable at a time, with an observation period after each change,
17+
so the impact of each action is measurable and attributable.
18+
19+
## Current Baseline (2026-05-04)
20+
21+
Live snapshot collected from the demo server on 2026-05-04:
22+
23+
- Host load average: `8.50 / 8.27 / 8.20`
24+
- Host CPU summary (`mpstat -P ALL 1 1`):
25+
- all CPUs: `%usr=35.33`, `%sys=15.38`, `%soft=19.69`, `%idle=29.20`
26+
- CPU2: `%soft=100.00`, `%idle=0.00`
27+
- Top CPU consumers:
28+
- `caddy`: about `279%`
29+
- `torrust-tracker`: about `88%`
30+
- `ksoftirqd/2`: visible in top CPU list
31+
- Docker container CPU snapshot:
32+
- `caddy`: `295.60%`
33+
- `tracker`: `91.84%`
34+
- `mysql`: `2.63%`
35+
- `grafana`: `0.29%`
36+
- `prometheus`: `0.00%`
37+
- Current request rates from Prometheus:
38+
- HTTP1: about `1982.32 req/s`
39+
- UDP1: about `2124.28 req/s`
40+
- Combined: about `4106.60 req/s`
41+
- Conntrack state:
42+
- `nf_conntrack_count`: `423120`
43+
- `nf_conntrack_max`: `1048576`
44+
- utilization: about `40.35%`
45+
- RX steering state:
46+
- `/sys/class/net/eth0/queues/rx-0/rps_cpus`: `00`
47+
- `/sys/class/net/eth0/queues/rx-0/rps_flow_cnt`: `0`
48+
- `net.core.rps_sock_flow_entries`: `0`
49+
50+
## What We Know So Far
51+
52+
### Conntrack is no longer the immediate bottleneck
53+
54+
The live conntrack table is well below the configured limit, so this does not look like a repeat
55+
of the overflow problem fixed in [#21](https://github.com/torrust/torrust-tracker-demo/issues/21).
56+
57+
### The packet path is still imbalanced on one CPU
58+
59+
One CPU is saturated in softirq while the host still has idle capacity overall. That strongly
60+
suggests packet processing is concentrated on one RX path instead of being distributed across
61+
cores.
62+
63+
The current live configuration confirms that RPS/RFS are disabled.
64+
65+
### Caddy is also consuming several CPU cores
66+
67+
This is not just a tracker-only problem. The HTTPS front-end is currently one of the largest CPU
68+
consumers on the host.
69+
70+
The current Compose file exposes UDP 443 for Caddy:
71+
72+
```yaml
73+
- "443:443/udp"
74+
```
75+
76+
This is used for HTTP/3 over QUIC. It is not required for normal HTTPS over TCP. Standard HTTPS
77+
would continue to work without it; removing it would only disable HTTP/3.
78+
79+
The deployed server currently mirrors the repository on this point: the live
80+
`/opt/torrust/docker-compose.yml` also exposes `443:443/udp`, and the host is listening on UDP 443.
81+
82+
## Controlled Action Plan
83+
84+
Important constraint: apply only one production change at a time and wait before taking the next
85+
step.
86+
87+
### Phase 1 — Preserve a reproducible baseline
88+
89+
- [x] Record a baseline evidence snapshot under `docs/issues/evidence/ISSUE-29/` before making
90+
any changes. See `00-baseline-live-snapshot.md` and `2026-05-04-htop-snapshot.png`.
91+
- [x] Capture host load, per-CPU usage, top processes, docker stats, conntrack state, and RX
92+
steering state.
93+
- [x] Record at minimum the live HTTP1 and UDP1 request rates from Prometheus.
94+
- [x] Record current newTrackon status for UDP1 and HTTP1.
95+
96+
### Phase 2 — First isolated experiment: disable HTTP/3
97+
98+
- [ ] Remove `"443:443/udp"` from the Caddy service in `server/opt/torrust/docker-compose.yml`.
99+
- [ ] Apply only that change on the live server and restart only Caddy.
100+
- [ ] Observe CPU, request rates, and external service health for an agreed window.
101+
- [ ] Decide whether Caddy CPU dropped materially enough to keep HTTP/3 disabled.
102+
103+
Rationale: this is a small, isolated change that affects only HTTP/3/QUIC support and does not
104+
change normal HTTPS or the tracker's UDP listener on port 6969.
105+
106+
### Phase 3 — Second isolated experiment: enable RPS/RFS
107+
108+
- [ ] If CPU pressure remains high after Phase 2, enable RPS and RFS as documented in
109+
`docs/udp-conntrack-runbook.md`.
110+
- [ ] Persist the configuration in the tracked server config.
111+
- [ ] Re-check whether softirq is still concentrated on one CPU.
112+
- [ ] Observe for an agreed window before taking further action.
113+
114+
Rationale: this directly targets the observed one-core softirq saturation while leaving the
115+
application stack unchanged.
116+
117+
### Phase 4 — Reassess architecture only after isolated tuning results exist
118+
119+
- [ ] If both isolated experiments fail to provide enough headroom, evaluate moving the HTTPS
120+
front-end or the UDP tracker onto separate hosts.
121+
- [ ] Treat host separation as a later step, not the first response.
122+
123+
## Questions To Answer In This Issue
124+
125+
1. How much of the current CPU load is explained by higher traffic versus avoidable packet-path
126+
inefficiency?
127+
2. Does disabling HTTP/3 reduce Caddy CPU materially without unacceptable product impact?
128+
3. Does enabling RPS/RFS spread softirq work enough to restore headroom?
129+
4. After isolated tuning, is a single-host deployment still acceptable at current traffic?
130+
131+
## Acceptance Criteria
132+
133+
- [ ] A baseline evidence snapshot exists for the pre-change state, including HTTP1 and UDP1
134+
request rates.
135+
- [ ] The first production change is isolated to a single variable and its effect is documented.
136+
- [ ] No follow-up production change is applied before the previous change has been observed.
137+
- [ ] A documented decision exists on whether `443:443/udp` should remain enabled for HTTP/3.
138+
- [ ] A documented decision exists on whether RPS/RFS should be deployed permanently.
139+
- [ ] The final issue conclusion states whether the current single-host design still has enough
140+
CPU headroom.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<!-- cspell:ignore CPUPerc urlencode -->
2+
3+
# ISSUE-29 Baseline Live Snapshot (Phase 1)
4+
5+
## Context
6+
7+
- Issue: [#29](https://github.com/torrust/torrust-tracker-demo/issues/29)
8+
- Capture timestamp (UTC): `2026-05-04T15:20:07Z`
9+
- Goal: record a pre-change baseline before any production tuning action.
10+
11+
## Commands Used
12+
13+
```bash
14+
ssh demotracker 'date -u +%Y-%m-%dT%H:%M:%SZ; uptime; nproc'
15+
ssh demotracker 'mpstat -P ALL 1 1'
16+
ssh demotracker 'ps -eo pid,comm,%cpu,%mem,stat --sort=-%cpu | head -20'
17+
ssh demotracker 'cd /opt/torrust && docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"'
18+
ssh demotracker 'sudo sysctl net.netfilter.nf_conntrack_max net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_udp_timeout net.netfilter.nf_conntrack_udp_timeout_stream'
19+
ssh demotracker 'cat /sys/class/net/eth0/queues/rx-0/rps_cpus; cat /sys/class/net/eth0/queues/rx-0/rps_flow_cnt; sudo sysctl net.core.rps_sock_flow_entries'
20+
ssh demotracker 'curl -sG "http://127.0.0.1:9090/api/v1/query" --data-urlencode "query=sum(rate(http_tracker_core_requests_received_total[5m]))"'
21+
ssh demotracker 'curl -sG "http://127.0.0.1:9090/api/v1/query" --data-urlencode "query=sum(rate(udp_tracker_server_requests_received_total[5m]))"'
22+
ssh demotracker 'curl -sG "http://127.0.0.1:9090/api/v1/query" --data-urlencode "query=sum(rate(http_tracker_core_responses_sent_total{result=\"error\"}[5m]))"'
23+
ssh demotracker 'curl -sG "http://127.0.0.1:9090/api/v1/query" --data-urlencode "query=sum(rate(udp_tracker_server_responses_sent_total{result=\"error\"}[5m]))"'
24+
```
25+
26+
External uptime sampling source:
27+
28+
```text
29+
https://newtrackon.com/raw
30+
```
31+
32+
## Key Results
33+
34+
### Host and CPU
35+
36+
- `uptime`: `load average: 10.46, 9.44, 8.85`
37+
- `nproc`: `8`
38+
- `mpstat` (all CPUs): `%usr=32.81`, `%sys=16.01`, `%soft=20.08`, `%idle=30.97`
39+
- `mpstat` (CPU2): `%soft=100.00`, `%idle=0.00`
40+
41+
### Top CPU Processes
42+
43+
- `caddy`: about `279%`
44+
- `torrust-tracker`: about `88.4%`
45+
- `ksoftirqd/2`: about `14.6%`
46+
47+
### Container CPU Snapshot
48+
49+
- `caddy`: `323.16%`
50+
- `tracker`: `84.39%`
51+
- `mysql`: `6.63%`
52+
- `grafana`: `0.37%`
53+
- `prometheus`: `0.02%`
54+
55+
### Conntrack and RX Steering
56+
57+
- `nf_conntrack_max`: `1048576`
58+
- `nf_conntrack_count`: `424607`
59+
- `nf_conntrack_udp_timeout`: `10`
60+
- `nf_conntrack_udp_timeout_stream`: `15`
61+
- `/sys/class/net/eth0/queues/rx-0/rps_cpus`: `00`
62+
- `/sys/class/net/eth0/queues/rx-0/rps_flow_cnt`: `0`
63+
- `net.core.rps_sock_flow_entries`: `0`
64+
65+
### Prometheus Request Rates
66+
67+
- HTTP1 request rate: `1983.1789473684207 req/s`
68+
- UDP1 request rate: `2240.870175438596 req/s`
69+
- Combined request rate: `4224.0491228070167 req/s`
70+
- HTTP error rate query result: empty vector (`0` at sample time)
71+
- UDP error response rate: `26.34035087719298 req/s`
72+
73+
### newTrackon Raw Snapshot (Sample)
74+
75+
Observed at capture window from `newtrackon/raw`:
76+
77+
- `https://http1.torrust-tracker-demo.com:443/announce` -> `Working`
78+
- `udp://udp1.torrust-tracker-demo.com:6969/announce` -> `Working`
79+
80+
## Attached Evidence
81+
82+
- `2026-05-04-htop-snapshot.png` (provided by maintainer)
83+
84+
## Notes
85+
86+
- This baseline is intentionally captured before changing any production setting.
87+
- The first planned production experiment remains Phase 2: disable Caddy HTTP/3
88+
(`443:443/udp`) only, then observe before any further action.
349 KB
Loading

project-words.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,13 @@ frontmatter
4747
fswc
4848
grafana
4949
healthcheck
50+
ksoftirqd
5051
leecher
5152
logfile
5253
misrouted
5354
mkpath
5455
Mailgun
56+
mpstat
5557
mysqladmin
5658
netnsid
5759
netfilter

0 commit comments

Comments
 (0)