The production image is built against musl, whose allocator is slow and
takes a global lock. Profiling /json on a 1 CPU / 1 GB Alpine container
showed malloc/free at ~11% of total CPU, the largest user-space cost;
the rest is mostly the kernel network stack, already at one recvfrom
and one writev per request.
mimalloc alone, however, kept the freed ~96 MB MMDB buffer resident
after a database update (RSS stayed at ~197 MB in two of three swaps),
and MIMALLOC_PURGE_DELAY=0 fixes that only by giving back most of the
speedup. So blocks of 1 MiB or more, in practice only the MMDB file
contents, go to the system allocator, which unmaps them on free; RSS
returns to ~98 MB after every swap, as before.
Median of three alternating 20 s runs: /json across random IPs rose
from 131.6k to 142.4k rps (+8%), p50 latency 0.465ms -> 0.443ms; a
single IP rose from 124.5k to 127.4k rps (+2%). Steady-state RSS grows
by ~12 MB. Responses are byte-identical to before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cache the serialized /json fields per MMDB record. Every field except
`ip` depends only on the record, and many IPs share one record, so the
response is now the cached fields with the address prepended. The cache
is keyed by data-section offset, capped at 16 MiB, and owned by the
loaded database so a hot-swapped DB never serves stale entries. A hit
costs ~0.27us instead of ~2.5us for decode + serialize; a miss is no
slower than before thanks to a pre-sized serialization buffer.
Trim per-request framework overhead shared by all endpoints:
- Dispatch by Host with a plain HostRouter service instead of an outer
Router wrapping a service_fn, skipping a second route match and box.
- Apply security headers via tower's MapResponseLayer instead of
middleware::from_fn, and reserve header capacity up front.
- Add a RequestedIp extractor that reads headers in place instead of
cloning the whole HeaderMap.
On a 1 CPU / 1 GB Alpine (musl) container, /json throughput rose from
76.5k to 123.5k rps for a single IP (+61%) and from 84.9k to 130.5k rps
across 20k random IPs (+54%); p50 latency fell from 0.85ms to 0.52ms.
Responses are byte-identical to before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add i18n module with Locale enum, PO parser, and Accept-Language negotiation
- Create gettext .po translation files for en, es, de, ja, ko, id, fr, ru, pt, it, zh-Hant, zh-Hans, nl, ar
- Route HTML pages under /{lang}/ prefix using IETF language tags
- Auto-detect browser language and redirect from / to /{lang}/
- Add language selector dropdown in footer
- Localize geo names (country, city) from MMDB where available
- Add hreflang alternate links and multilingual sitemap for SEO
- Support RTL layout for Arabic
- Update integration tests for new routing structure