Rinha de Backend 2026 submission in .NET 11 Native AOT: exact kNN fraud detection (k=5) over a quantized spatial index, served behind a Rust load balancer with Unix socket FD passing.
Português: see docs/README.pt-BR.md
The API accepts transactions on POST /fraud-score, extracts a 14-dimensional vector, queries a pre-built RNSPCST2 index (3M references), and returns a fraud score and approval flag. The production binary is Native AOT for linux-x64 with no managed runtime.
Client → Evented Rust LB :9999 → api1 / api2 (SCM_RIGHTS FD passing)
↓
mlock + pretouch + AVX2 search
| Component | Role |
|---|---|
Rinha.Api |
HTTP API (/ready, /fraud-score) |
Rinha.Preprocess |
Builds the index with v0-cuts header |
Rinha.Verify |
CLI to validate responses against a test dataset |
| Rust LB | Evented Load balancer on port 9999 (rinha-dotnet-lb:local) |
| 2× API | Replicas with cpuset and mlock enabled |
Production settings were chosen for parity with rinha-rust:
| Document | Scope |
|---|---|
| docs/benchmark-matrix.md | API tuning — warmup, thread pool, leaf size |
| docs/perf-rework.md | Details on the 2026 performance rework |
Recommended stack config: RINHA_PRETOUCH_INDEX=1, RINHA_MLOCK_INDEX=1, cpuset pinning, evented LB.
| Method | Route | Description |
|---|---|---|
GET |
/ready |
503 during warmup; 200 ok when ready |
POST |
/fraud-score |
JSON or text body; returns approved and fraud_score |
- .NET SDK 11 (preview; pinned in
global.json) - Docker and Docker Compose
resources/references.json.gz— official reference dataset (~48 MB)
mkdir -p resources
cp /path/to/references.json.gz resources/make up
curl http://localhost:9999/ready
# okBuilds the Docker image, starts api1, api2, and the Rust LB, then waits for readiness.
make down # stop the stack
make help # list all targetsImages are published to GHCR on pushes to main:
docker pull ghcr.io/fksegundo/rinha-dotnet:latest| Command | Description |
|---|---|
make test |
Unit and integration tests |
make build |
Build the Docker image |
make up |
Build + start the stack |
make down |
Stop containers and remove volumes |
make ready |
Wait until GET /ready returns 200 |
make preprocess |
Build index locally → test-data/ |
make verify |
Validate responses (requires index + test-data.json) |
make publish |
Native AOT publish (linux-x64) |
Defined in docker/docker-compose.yml:
- Rust LB (
ghcr.io/fksegundo/rinha-api-lb) exposes:9999and hands TCP connections to the APIs via SCM_RIGHTS - LB → API control channels use Unix domain sockets (
/sockets/*.sock) on a tmpfs volume - Resource limits:
0.45 + 0.45 + 0.10CPU,165M + 165M + 20MRAM
The image is multi-stage: index preprocess at build time, AOT publish with IlcInstructionSet=avx2, slim runtime-deps runtime (~10 MB binary).
dotnet test -c Release
dotnet run --project src/Rinha.Preprocess -c Release -- \
resources/references.json.gz test-data/rinha-specialist.idx
dotnet publish src/Rinha.Api/Rinha.Api.csproj -c Release -r linux-x64 \
-p:PublishAot=true -p:StripSymbols=true
dotnet run --project src/Rinha.Verify -c Release -- \
test-data/rinha-specialist.idx /path/test-data.json| Variable | Default (compose) | Description |
|---|---|---|
RINHA_FD_SOCKET |
(required in compose) | FD-passing control socket (e.g. /sockets/api1.sock) |
RINHA_UDS_SOCKET |
— | Kestrel UDS path for local dev without the Rust LB |
RINHA_INDEX_PATH |
/app/index/rinha-specialist.idx |
Index file path |
RINHA_WARMUP_QUERIES |
64 |
Warmup queries before /ready |
RINHA_PRETOUCH_INDEX |
1 |
Eagerly fault-in index mapping at startup |
RINHA_MLOCK_INDEX |
1 |
Locks index pages in RAM (requires memlock ulimit) |
RINHA_SEARCH_MODE |
key-first |
Index search strategy (key-first uses active keys) |
src/
Rinha.Api/ HTTP API (parser, index, endpoints)
Rinha.Preprocess/ RNSPCST1 index builder
Rinha.Verify/ Dataset verifier CLI
test/
Rinha.Tests/ Automated tests
docker/
Dockerfile AOT build + preprocess
docker-compose.yml Rust LB + 2 APIs (FD passing)
haproxy.cfg Legacy HAProxy config (benchmark override via `LB_IMAGE`)
docs/
README.pt-BR.md Portuguese documentation
benchmark-matrix.md API benchmark results
proxy-benchmark-matrix.md Load balancer benchmark results
resources/
references.json.gz Official dataset (not versioned)
- Parser: transaction-first → customer-first → JSON fallback
- Vector: 14D quantized, aligned with the official format
- kNN: exact search with k=5; precomputed JSON responses
- Index:
mmap+madvise; AVX2 search when available - Body:
ArrayPool+ReadExactlyAsync(no per-request allocation) - Readiness: async warmup; wait for
GET /readybefore load tests
Rinha de Backend 2026 participation project.