agentleFS
mazreanmazrean/agent-skills/skills/tuning-isucon-linux-and-nginx/SKILL.md

tuning-isucon-linux-and-nginx

Skill2 starsChanged 8 months agoMITView on GitHub

Problem-independent infrastructure tuning for ISUCON-style multi-host web apps on Linux, distilled from a 17-hour measured tuning run (1,085 → ~2.9M). Covers a prebuilt nginx 1.28 + AWS-LC binary with syscall-saving patches (drop-in replacement, no build needed), TLS termination spread across hosts with netfilter DNAT + nftables flowtable, NIC IRQ / XPS / SO_INCOMING_CPU alignment, sysctl, cloud NIC allowance limits (EC2 ENA bw/pps), per-host cost measurement that does not need a benchmark run, transferable app patterns (in-memory + local WAL, long-poll, SSE, Go→Rust), and a prebuilt patched kernel + XDP load balancer that cuts front-host packet CPU (with when it pays), and a list of measured dead ends (XDP on stock ENA, NAPI deferral, NOTRACK). Use when tuning nginx/TLS/kernel/NIC on ISUCON hosts, when the app is no longer the only bottleneck, or when deciding which infra levers are worth contest time.

The file

We split this skill into the rules it gives an agent

2 rules. About 0 are common, 2 are distinctive, and 0 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 0

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Every change must survive reboot: All tuning below is applied by systemd oneshot units or config files, never by hand.

    line 29
  2. Distinctive:

    Check the regulation: before replacing certificates, adding hosts to the request path, or changing anything the benchmarker might validate.

    line 31

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Tuning ISUCON Linux and nginx

Infra levers that carried over across the whole run, ordered by cost × yield. Everything here is independent of the problem's domain; only the host names and the app's upstream change. For contest strategy see winning-isucon; for how an agent should run the contest (bench queue, parallel agents, stalls) see running-isucon-as-an-agent.

Use this skill when the app is already reasonable (no N+1, data in memory or indexed) and per-host CPU shows nginx/TLS/softirq near the top, or when deciding which infra work is worth contest time.

Ground rules (learned the hard way)

  1. Measure the hosts, not just the score. Scores varied ±5–12 % run to run; per-host CPU split (usr/sys/soft/idle), egress, and allowance counters are far more stable. Use assets/net/node-metrics.sh start|stop around any load (MEASUREMENT.md). Freeing CPU on a host that is not the bottleneck does not move the score — move work onto it instead.
  2. Cheap observations before deep work. One measurement usually exposes the next 2–3 levers (an idle host to shift TLS to, connection churn, allowance drops). An hour of kernel/XDP work in the run produced 0 %.
  3. Every change must survive reboot. All tuning below is applied by systemd oneshot units or config files, never by hand.
  4. Check the regulation before replacing certificates, adding hosts to the request path, or changing anything the benchmarker might validate.

Lever checklist (do in this order)

#LeverCostObserved effectDetails
1Stop CPU-eating daemons (keep ssh + cloud agent)2 minsmall, removes noiseNET-TUNE.md
2sysctl (backlogs, ports, buffers) + LimitNOFILE2 minprevents collapse under loadNET-TUNE.md
2bClient keepalive_timeout from the measured gap CDF (bench fds/ports are finite)10 minwrong values FAILed 2 runs (fd, then port exhaustion on the client)NGINX.md
3nginx: upstream keepalive, access_log off, h2, reuseport, worker_cpu_affinity auto, open_file_cache, gzip_static10 minlarge; HTTP/1.1 to the client was −5 % vs h2NGINX.md
4Co-located nginx→app over a Unix socket; separate DB/app/nginx hosts15 min3-host split ≈ +10 %; UDS small +NGINX.md
5Prebuilt nginx + AWS-LC (drop-in via systemd override)5 min+5 % score; TLS hosts +10 pt idle CPUNGINX-AWSLC.md
6TLS 1.3 only, X25519, session cache/tickets; ECDSA cert only if allowed5 minECDSA P-256 + X25519: +3 %NGINX.md
7Spread TLS termination across hosts: DNAT + MASQUERADE + flowtable15 minthe step that let 3 hosts share TLS CPUTLS-LB.md
8NIC IRQ → CPU pinning, XPS, pfifo_fast, irqbalance off5 min+2 %NET-TUNE.md
9Worker ↔ CPU ↔ NIC queue alignment (SO_INCOMING_CPU, built into the prebuilt nginx)0 min with lever 5+1–2 %NGINX-AWSLC.md
10Watch cloud NIC allowances; compress large responses5 minprevented a 15 % "mystery" regressionNET-TUNE.md
10bLong inter-host RTT (emulated regions): per-route initcwnd/initrwnd + larger default tcp_rmem; nginx client_body_buffer_size ≥ typical upload; cap every disk cache10 minone RTT off 80–100 KB responses; best run +~6 %; prevented disk-full FAILsDEAD-ENDS.md
11App-side: in-memory state + local WAL, long-poll empty polls, app terminates TLS itselfhourslargest wins overallAPP-PATTERNS.md
12Only if the front host is the bottleneck (lowest idle, high soft%): prebuilt patched kernel (ENA XDP_TX on shared rings, batched doorbells) + XDP L4 LB instead of iptables TLS-LB20 min + rebootfront host −60 % doorbells, softirq 33→27 %, idle 4–7 → 14–16 %; +3 % score when weights were shifted to it, 0 % while another host was the limitKERNEL-XDP.md

Measured dead ends — do not spend contest time

TriedResult
napi_defer_hard_irqs=2 + gro_flush_timeout=50usIRQs 37k/s → 0.1k/s but −5 % (latency)
raw-table NOTRACK for proxied flowsno change
GRO off on the front hostno change
XDP L4 load balancer on the stock ENA driver−2 %: ENA XDP needs 2 × queues ≤ max queues → halves queues (the patched kernel in lever 12 removes this)
PREEMPT_NONE aloneno measurable change
preempt=none boot paramno effect without CONFIG_PREEMPT_DYNAMIC
HTTP/1.1 instead of h2 to the client−5 %
Go app terminating TLS itself (crypto/tls)−10 % (Rust + rustls/aws-lc-rs was +4 %)
Cache-Control: max-age on static filesworkload-dependent: −35 % in one phase, + later — always A/B
Home-made TLS edge proxy replacing nginx−4 % handshakes/s; 0-point run from h2-cancel bugs before it was dropped
Read-local replica cluster across the TLS hosts−8 %: replication CPU competes with TLS
TLS session cache/ticket tuning when the client never resumesno effect — check $ssl_session_reused first
DB streaming standby on the app hosts−45 %: WAL replay pinned the app hosts' disk IOPS
remote_apply (synchronous) replication on every commitscore halved
proxy_request_buffering offFAIL

Details and numbers: DEAD-ENDS.md.

Reference files

  • MEASUREMENT.md — node-metrics.sh, perf/strace recipes, A/B protocol without the official bench.
  • NGINX.md — config skeleton (main, upstream, TLS, static, SSE, UDS).
  • NGINX-AWSLC.md — download/verify/install the prebuilt binary; what the patches do; rebuild fallback.
  • TLS-LB.md — splitting TLS termination over N hosts with netfilter; weights; flowtable.
  • NET-TUNE.md — IRQ/XPS/qdisc, sysctl, daemons, cloud NIC allowances.
  • APP-PATTERNS.md — transferable app designs and the Go→Rust decision.
  • KERNEL-XDP.md — prebuilt patched kernel + XDP LB: measured CPU effect, when it turns into score, safe one-shot install.
  • DEAD-ENDS.md — everything that did not work, with numbers.
  • assets/ — nginx-awslc/ (build script, patches, systemd override), net/ (scripts, units, sysctl, metrics), kernel/ (patch, config, build/install), xdp/ (XDP LB source + loader).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.