Series MapLesson 18 / 35
Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Build CoreOrdered learning track

Rate Limiting and Traffic Protection

Rate Limiting, Connection Limiting, Throttling, and Traffic Shaping

Memahami limit_req, limit_conn, token bucket, burst, nodelay, per-IP/per-user/per-tenant limit, 429, dan Retry-After.

9 min read1663 words
PrevNext
Lesson 1835 lesson track07–19 Build Core
#rate-limiting#limit-req#limit-conn#throttling+2 more

Part 018 — Rate Limiting, Connection Limiting, Throttling, and Traffic Shaping

1. Tujuan Part Ini

Rate limiting sering dianggap sederhana:

batasi request terlalu banyak

Dalam production enterprise system, masalahnya lebih kompleks.

Rate limiting harus menjawab:

siapa yang dibatasi?
berdasarkan key apa?
berapa rate normal?
berapa burst yang wajar?
apa response saat dibatasi?
apakah retry client aman?
apakah limit berlaku per pod atau global?
apakah limit melindungi Java/JAX-RS service atau malah memblokir customer valid?

Part ini membahas rate limiting, connection limiting, throttling, dan traffic shaping di NGINX dari sudut pandang backend engineer yang harus menjaga API tetap stabil, adil, dan debuggable.


2. Mental Model: Rate, Concurrency, and Throughput

Tiga konsep sering tercampur:

KonsepPertanyaanNGINX control umum
RateBerapa request per waktu?limit_req
ConcurrencyBerapa koneksi aktif bersamaan?limit_conn
Bandwidth/transferSeberapa cepat data dikirim?limit_rate

Contoh:

100 request per second kecil-kecil
10 upload besar bersamaan
1 download besar sangat lambat

Tiga kasus itu memberi tekanan yang berbeda.

Rate limiting melindungi dari request spike. Connection limiting melindungi dari terlalu banyak koneksi aktif. Bandwidth throttling melindungi transfer resource yang terlalu agresif.

Untuk Java/JAX-RS backend, ketiganya berdampak pada:

thread pool
connection pool
heap pressure
DB pool
Kafka producer/consumer pressure
external API calls
latency tail

3. Where Rate Limiting Can Live

Rate limit bisa diterapkan di banyak layer:

CDN / cloud edge
cloud WAF
cloud load balancer / application gateway
API gateway
NGINX / ingress
service mesh
application middleware
Redis/distributed limiter
database/domain quota

NGINX cocok untuk:

per-IP protection
coarse API protection
protect expensive route
basic partner route shaping
shield Java service from obvious spikes

NGINX kurang cocok untuk:

global distributed quota across many ingress pods
complex per-user billing quota
tenant-aware quota with central consistency
business entitlement enforcement
adaptive risk scoring

Prinsip:

Use NGINX for edge protection.
Use application/API gateway/distributed limiter for business-aware quota.

4. Token Bucket Mental Model

NGINX request rate limiting memakai mental model mirip token/leaky bucket.

Bayangkan satu bucket per key:

key = client IP / tenant / header / route
rate = token masuk per detik
burst = kapasitas antrean sementara

Jika request datang sesuai rate:

request accepted

Jika request datang melebihi rate tetapi masih dalam burst:

request delayed atau accepted immediately tergantung nodelay

Jika request melewati burst:

request rejected -> biasanya 503 default atau 429 jika dikonfigurasi

Diagram:

flowchart TD A[Request arrives] --> B[Compute limit key] B --> C{Within configured rate?} C -->|Yes| D[Pass to upstream] C -->|No| E{Within burst?} E -->|Yes, delay mode| F[Delay then pass] E -->|Yes, nodelay| G[Pass immediately but account burst] E -->|No| H[Reject with configured status]

5. Basic limit_req Configuration

Pola dasar:

http {
    limit_req_zone $binary_remote_addr zone=per_ip_api:10m rate=10r/s;

    server {
        location /api/ {
            limit_req zone=per_ip_api burst=20 nodelay;
            limit_req_status 429;

            proxy_pass http://jaxrs_upstream;
        }
    }
}

Komponen penting:

BagianFungsi
limit_req_zonemendefinisikan key, shared memory zone, dan rate
$binary_remote_addrkey berbasis IP dalam bentuk efisien
zone=per_ip_api:10mshared memory zone untuk state limiter
rate=10r/srate dasar
limit_reqmengaktifkan limiter pada context tertentu
burst=20toleransi spike sementara
nodelayburst tidak ditahan, langsung diteruskan sampai quota burst habis
limit_req_status 429gunakan 429 agar semantik jelas

Poin penting:

limit_req_zone hanya mendefinisikan zone.
limit_req harus dipasang di server/location agar berlaku.

6. Choosing the Right Limit Key

Key adalah desain paling penting.

Contoh key:

limit_req_zone $binary_remote_addr zone=per_ip:10m rate=10r/s;
limit_req_zone $http_x_tenant_id zone=per_tenant:10m rate=100r/s;
limit_req_zone $http_authorization zone=per_token:10m rate=20r/s;

Perbandingan:

KeyKelebihanRisiko
IPsederhana, edge-friendlyNAT/proxy membuat banyak user terlihat satu IP
Hostmudah untuk per-domaintidak membedakan user
URIcocok untuk route mahalhigh cardinality jika URI dinamis
Header tenanttenant-awareheader bisa spoofed jika belum trusted
Authorization tokenuser-ishsensitif, high cardinality, jangan log raw token
JWT claimbutuh parsing tambahanNGINX OSS tidak native claim-aware

Rule penting:

Do not use untrusted identity header as limiter key unless it is set by trusted auth layer.

Jika X-Tenant-ID berasal dari client publik, attacker bisa mengganti tenant ID untuk menghindari limit.


7. Per-IP Rate Limiting

Per-IP adalah pola paling umum.

limit_req_zone $binary_remote_addr zone=ip_login:10m rate=5r/m;

server {
    location /api/v1/login {
        limit_req zone=ip_login burst=5 nodelay;
        limit_req_status 429;
        proxy_pass http://auth_upstream;
    }
}

Cocok untuk:

login endpoint
password reset endpoint
public unauthenticated API
scanner/fuzzer protection
coarse abuse control

Risiko:

banyak user berada di balik NAT corporate yang sama
partner integration memakai shared outbound proxy
mobile carrier NAT membuat IP sharing besar
attacker memakai botnet banyak IP

Karena itu per-IP limit harus dilihat sebagai coarse protection, bukan fairness sempurna.


8. Per-Route Limiting

Tidak semua route sama mahal.

Contoh:

GET /api/v1/products        relatif murah
POST /api/v1/quotes/calc    mahal
POST /api/v1/orders/submit  kritikal
GET /api/v1/report/export   berat

Pola:

limit_req_zone $binary_remote_addr zone=general_api:10m rate=50r/s;
limit_req_zone $binary_remote_addr zone=expensive_api:10m rate=2r/s;

server {
    location /api/ {
        limit_req zone=general_api burst=100 nodelay;
        limit_req_status 429;
        proxy_pass http://jaxrs_upstream;
    }

    location /api/v1/quotes/calculate {
        limit_req zone=expensive_api burst=5 nodelay;
        limit_req_status 429;
        proxy_pass http://jaxrs_upstream;
    }
}

Review question:

Apakah expensive route punya limit lebih ketat?
Apakah critical route perlu protection atau malah lebih longgar?
Apakah background job/internal caller terkena limit yang sama?

9. Burst and nodelay

burst menentukan toleransi spike.

Tanpa nodelay, request burst bisa ditunda agar mengikuti rate. Dengan nodelay, request burst diteruskan langsung sampai burst capacity habis.

Contoh:

limit_req zone=per_ip_api burst=20;

Perilaku:

request berlebih bisa ditunda
latency client naik
upstream lebih terlindungi

Dengan nodelay:

limit_req zone=per_ip_api burst=20 nodelay;

Perilaku:

spike kecil diterima cepat
latency lebih rendah
upstream menerima burst lebih tajam

Trade-off:

ModeKelebihanRisiko
delaysmoothing lebih kuatlatency tidak terlihat sebagai rejection
nodelayUX lebih baik untuk burst kecilbackend tetap menerima spike

Untuk API enterprise, nodelay sering lebih mudah dipahami client karena request diterima atau ditolak jelas, bukan diam-diam delay lama.


10. Return 429 Instead of Ambiguous 503

Secara default, beberapa limit rejection bisa tampak seperti 503 tergantung konfigurasi/module/version.

Untuk API, lebih baik eksplisit:

limit_req_status 429;
limit_conn_status 429;

429 punya semantik jelas:

Too Many Requests

Tambahkan Retry-After jika client bisa retry:

location /api/ {
    limit_req zone=per_ip_api burst=20 nodelay;
    limit_req_status 429;
    add_header Retry-After "1" always;
    proxy_pass http://jaxrs_upstream;
}

Hati-hati:

Retry-After harus masuk akal.
Jika semua client retry persis setelah 1 detik, bisa terjadi synchronized retry spike.

Lebih baik client memakai exponential backoff dengan jitter.


11. Connection Limiting with limit_conn

Connection limiting membatasi koneksi aktif per key.

Contoh:

http {
    limit_conn_zone $binary_remote_addr zone=addr_conn:10m;

    server {
        location /api/ {
            limit_conn addr_conn 20;
            limit_conn_status 429;
            proxy_pass http://jaxrs_upstream;
        }
    }
}

Cocok untuk:

slow client protection
large download protection
WebSocket/SSE guardrail
partner integration concurrency cap
upload endpoint protection

Namun hati-hati untuk HTTP/2:

satu koneksi HTTP/2 bisa membawa banyak stream
connection count tidak selalu sama dengan request concurrency

Connection limiting harus dipahami bersama HTTP version dan load balancer behavior.


12. limit_rate and Transfer Throttling

limit_rate membatasi kecepatan transfer response.

Contoh:

location /downloads/ {
    limit_rate 1m;
    proxy_pass http://jaxrs_upstream;
}

Cocok untuk:

large binary download
export file
non-critical bulk transfer
protect bandwidth

Risiko:

request time menjadi lebih lama
connection lebih lama tertahan
worker connection pressure naik
client timeout jika terlalu lambat

Throttling bandwidth bukan solusi utama untuk overload API JSON. Untuk API JSON, rate/concurrency limit lebih relevan.


13. Protecting Java/JAX-RS Thread Pools

Java/JAX-RS service biasanya punya beberapa resource terbatas:

HTTP worker thread
DB connection pool
Kafka producer buffer
external API client pool
heap memory
CPU

Rate limit di NGINX harus didesain berdasarkan bottleneck aktual.

Contoh:

Endpoint calculate quote memanggil pricing engine dan DB.
DB pool service = 50 connections.
App replicas = 5.
Max safe expensive concurrent work sekitar 150, bukan unlimited.

NGINX rate limit dapat mengurangi burst, tetapi tidak tahu kondisi DB pool.

Untuk protection yang lebih presisi:

application semaphore per expensive use case
distributed quota per tenant
circuit breaker
bulkhead
queue/backpressure

NGINX adalah layer pertama, bukan satu-satunya control.


14. Per-Tenant and Per-User Limiting Challenge

Enterprise SaaS atau BSS/OSS system sering butuh limit berdasarkan:

tenant
customer
partner
user
client application
subscription plan
contract entitlement

NGINX OSS tidak secara natural memahami domain identity.

Opsi desain:

OpsiKapan cocokRisiko
NGINX per-IPpublic coarse protectiontidak tenant-aware
NGINX header-based keyidentity sudah trusted dari gateway/authspoofing jika tidak trusted
API Gateway quotaproduct/API subscription modellayer tambahan
App-level quotadomain-awarerequest sudah masuk app
Redis distributed limitermulti-pod consistent quotacomplexity, Redis dependency
Service mesh policyservice-to-service protectiontidak selalu north-south cocok

Jika organisasi butuh per-tenant quota yang kuat, NGINX biasanya hanya menjadi coarse front-line protection.


15. Distributed Rate Limiting Limitation

Dalam Kubernetes, ingress controller biasanya punya beberapa pod.

Pertanyaan penting:

Apakah rate limit state shared antar pod?

Jika tidak shared, limit efektif bisa menjadi:

configured limit × jumlah ingress pod

Contoh:

limit 100 r/s per IP
3 ingress controller pods
client tersebar ke 3 pods
limit efektif mendekati 300 r/s

Tergantung load balancing dan stickiness, hasil aktual bisa tidak stabil.

Untuk quota global yang kuat, pertimbangkan:

API gateway dengan quota store
Redis/distributed limiter
NGINX Plus feature jika tersedia dan sesuai
custom auth/rate-limit service

Internal verification wajib dilakukan sebelum menyebut limit sebagai global.


16. Ingress Controller Rate Limit Annotations

Di ingress-nginx, rate limiting sering dikonfigurasi via annotation.

Contoh konseptual:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/limit-rps: "10"
    nginx.ingress.kubernetes.io/limit-burst-multiplier: "5"

Namun annotation spesifik bergantung controller dan versi.

Jangan menyamakan:

community ingress-nginx
NGINX Inc Kubernetes Ingress Controller
NGINX Plus Ingress Controller
cloud-native ingress/gateway controller

Checklist:

Controller mana yang dipakai?
Annotation apa yang didukung?
Apakah limit berlaku per ingress pod?
Apakah status rejection 429 atau 503?
Apakah metrics tersedia?
Apakah global ConfigMap bisa override?

17. Rate Limiting Authenticated vs Unauthenticated Traffic

Unauthenticated traffic:

belum tahu user/tenant
per-IP atau per-route adalah pilihan umum
cocok untuk login/reset/search public

Authenticated traffic:

bisa dibatasi per token/user/tenant jika identity trusted
lebih adil
lebih dekat ke business quota

Tetapi di NGINX, identity authenticated mungkin belum tersedia kecuali:

API gateway sudah memvalidasi token dan menyet header trusted
NGINX auth_request memanggil auth service
NGINX Plus/JWT module digunakan
Lua/njs/custom module digunakan

Jika auth dilakukan di Java/JAX-RS app, NGINX tidak bisa rate limit berdasarkan user dengan aman tanpa membaca token.


18. Interaction with Retries

Rate limiting dan retry bisa menciptakan storm.

Skenario buruk:

NGINX returns 429
client retries immediately
all clients retry together
NGINX rejects more
traffic spike makin besar

Retry policy client harus:

respect 429
respect Retry-After jika ada
use exponential backoff
use jitter
avoid retrying non-idempotent requests blindly

Untuk Java/JAX-RS API, dokumentasikan retry safety:

Method/use caseRetry safe?Catatan
GET quote detailBiasanya yaselama cache/state semantics jelas
POST calculate quoteTergantungbisa mahal, mungkin idempotency key diperlukan
POST submit orderTidak tanpa idempotency keyrisiko duplicate order
PUT update resourceBiasanya lebih amantetap perlu version/concurrency control
DELETE resourceTergantungidempotency domain-specific

NGINX tidak tahu business idempotency. Jangan memakai retry/limit policy yang mengasumsikan semua POST aman.


19. Rate Limit Response Contract

Response 429 sebaiknya konsisten.

Contoh response API:

{
  "error": "rate_limited",
  "message": "Too many requests. Please retry later.",
  "requestId": "abc-123"
}

Jika NGINX menghasilkan HTML default, client API bisa gagal parse.

Pola:

limit_req_status 429;
error_page 429 = @rate_limited;

location @rate_limited {
    default_type application/json;
    add_header Retry-After "1" always;
    return 429 '{"error":"rate_limited","requestId":"$request_id"}';
}

Catatan:

requestId harus selaras dengan log NGINX dan aplikasi.
Jika request tidak sampai aplikasi, requestId edge menjadi satu-satunya pegangan support.

20. Observability for Rate Limiting

Rate limiting tanpa observability akan terlihat seperti random API failure.

Metric/log penting:

rate limit rejected count
connection limit rejected count
429 count by route/host/client/tenant if safe
request rate before/after limiting
upstream request reduction
latency impact from delay mode
top source IP / partner / client
false positive report

Access log perlu membedakan:

status=429 from NGINX
upstream_status empty
request_time small
upstream_response_time empty

Contoh log format field:

log_format main_json escape=json
'{'
  '"time":"$time_iso8601",'
  '"request_id":"$request_id",'
  '"remote_addr":"$remote_addr",'
  '"host":"$host",'
  '"method":"$request_method",'
  '"uri":"$request_uri",'
  '"status":$status,'
  '"request_time":$request_time,'
  '"upstream_status":"$upstream_status",'
  '"upstream_response_time":"$upstream_response_time"'
'}';

Jika upstream_status kosong pada 429, berarti rejection terjadi di NGINX sebelum aplikasi.


21. Avoiding False Positives

False positive adalah request valid yang dibatasi.

Penyebab umum:

corporate NAT membuat ribuan user terlihat satu IP
partner batch job mengirim spike sesuai kontrak
mobile carrier NAT
health check ikut dihitung
CORS preflight ikut dibatasi terlalu ketat
retry client memperbesar traffic
multi-tab browser membuat burst
load test tidak diberi bypass terkontrol

Mitigasi:

bedakan route public/authenticated/internal
buat allowlist untuk trusted partner jika sah
gunakan key yang lebih adil jika identity trusted
exclude health check dari limiter
observasi sebelum blocking
mulai dengan threshold longgar
review log top offenders sebelum tighten

Jangan membuat allowlist permanen tanpa owner dan alasan.


22. Dry Run and Gradual Enforcement

Idealnya rate limit diperkenalkan bertahap:

observe current traffic
simulate/dry run jika fitur tersedia
alert only
apply to low-risk route
apply to high-risk route with conservative threshold
monitor false positive
adjust

Jika dry run tidak tersedia di platform, lakukan pendekatan alternatif:

log-only di aplikasi/API gateway
shadow dashboard dari access log
temporary high threshold
canary ingress
limited host/tenant rollout

Prinsip:

Do not introduce aggressive rate limiting blindly in production.

23. Rate Limiting and CORS Preflight

Browser API sering mengirim OPTIONS preflight.

Jika preflight ikut rate-limited terlalu ketat:

browser request gagal sebelum actual request
client melihat CORS error, bukan 429 jelas
application log tidak menunjukkan request actual

Strategi:

handle OPTIONS ringan di edge jika sesuai
bedakan limit untuk OPTIONS dan actual method
pastikan CORS response pada 429 tetap masuk akal jika browser client perlu membaca response

Namun jangan membuat OPTIONS selalu public jika API policy membutuhkan auth tertentu. Selaraskan dengan security model.


24. Rate Limiting and Long-Lived Connections

WebSocket, SSE, dan long polling butuh perhatian khusus.

Rate limiting request per second tidak cukup karena masalah utamanya sering concurrency/idle connection.

Untuk WebSocket/SSE:

limit_conn lebih relevan
idle timeout penting
worker_connections capacity penting
load balancer timeout penting

Contoh:

limit_conn_zone $binary_remote_addr zone=ws_conn:10m;

location /ws/ {
    limit_conn ws_conn 5;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://jaxrs_realtime;
}

Jangan menerapkan limit_req sangat ketat pada long polling tanpa memahami polling interval client.


25. Rate Limiting and File Upload/Download

Upload besar dan download besar memberi tekanan berbeda.

Upload besar:

client body buffering
temporary disk
slow upload
request body timeout
upstream handoff timing

Download besar:

long connection
bandwidth
send timeout
slow client
connection slot held

Controls:

client_max_body_size
client_body_timeout
limit_conn
limit_rate
proxy_request_buffering
proxy_buffering

Rate limiting per request tidak selalu cukup untuk payload besar. Satu request bisa sangat mahal.


26. Protecting Expensive Domain Operations

Dalam quote/order domain, beberapa endpoint bisa mahal:

quote calculation
pricing simulation
catalog eligibility check
order validation
bulk import/export
contract generation
report generation

NGINX bisa memberi guardrail awal:

lebih ketat untuk expensive route
limit burst kecil
connection limit untuk export
body size limit untuk import

Tetapi domain-aware protection tetap perlu di aplikasi:

idempotency key
tenant quota
async job queue
bulkhead
circuit breaker
per-operation concurrency semaphore
priority queue

Rate limiting di NGINX adalah traffic shaping, bukan domain workload scheduler.


27. AWS/Azure/On-Prem Considerations

AWS/EKS

Rate limiting mungkin ada di:

AWS WAF
CloudFront
ALB listener rule/WAF integration
API Gateway usage plan
NGINX Ingress
application service

Cek apakah source IP yang dipakai limiter adalah:

client IP
CloudFront IP
ALB IP
NLB source IP preserved
proxy protocol result

Azure/AKS

Rate limiting bisa muncul di:

Azure Front Door WAF
Azure Application Gateway WAF
Azure API Management policy
NGINX Ingress
application service

Cek apakah NSG/Application Gateway mengubah source visibility.

On-prem/hybrid

Perhatikan:

corporate proxy membuat banyak client berbagi IP
partner traffic datang dari NAT gateway
L4/L7 appliance mungkin sudah punya rate policy
proxy chain membuat X-Forwarded-For panjang

Rate limit harus didesain berdasarkan observed traffic path, bukan asumsi topologi ideal.


28. Failure Modes

SymptomKemungkinan penyebab
Banyak 429threshold terlalu rendah, traffic spike, abuse, retry storm
503 saat limitstatus limit belum diset ke 429
Partner valid terblokirNAT/shared IP, allowlist belum ada, contract burst tidak dipahami
App tetap overloadlimiter key salah, limit per pod bukan global, burst terlalu tinggi
Limit tidak bekerjalimit_req_zone ada tapi limit_req tidak diterapkan
Semua user satu kantor gagalper-IP limit terlalu ketat untuk corporate NAT
WebSocket gagallimit_conn terlalu rendah, idle timeout salah
CORS error anehOPTIONS/preflight terkena limiter
Latency naik tanpa 429delay mode menahan request
Dashboard tidak jelas429 dari NGINX tidak dipisahkan dari app response

29. Debugging Playbook

Pertanyaan pertama:

Apakah rejection dari NGINX atau dari aplikasi?

Ciri rejection di NGINX:

upstream_status kosong
upstream_response_time kosong
application log tidak ada
request_time kecil, kecuali delay mode
status 429/503 dari edge

Cek config final:

nginx -T | grep -n "limit_req\|limit_conn\|limit_req_zone\|limit_conn_zone"

Di Kubernetes:

kubectl describe ingress <name> -n <namespace>
kubectl get configmap -n <ingress-namespace>
kubectl logs deploy/<ingress-controller> -n <ingress-namespace>

Test sederhana:

for i in $(seq 1 50); do
  curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/api/v1/quotes &
done
wait

Cek response headers:

curl -v https://api.example.com/api/v1/quotes

Cari:

HTTP/1.1 429
Retry-After
X-Request-ID
Content-Type application/json

30. PR Review Checklist

Purpose

Masalah apa yang ingin diselesaikan limiter ini?
Abuse, overload, fairness, partner quota, atau expensive endpoint protection?

Scope

Apakah limit global, per host, per route, per IP, per user, atau per tenant?
Apakah berlaku untuk public, partner, internal, atau admin route?

Key

Apakah key trusted?
Apakah key high-cardinality?
Apakah NAT/shared proxy dipertimbangkan?
Apakah source IP yang dipakai benar?

Threshold

Apakah threshold berdasarkan data traffic?
Apakah burst masuk akal?
Apakah ada peak hour/batch job/partner traffic?

Behavior

Apakah rejection memakai 429?
Apakah Retry-After sesuai?
Apakah response body sesuai API contract?
Apakah CORS/browser behavior dipertimbangkan?

Distributed behavior

Apakah limit per ingress pod atau global?
Apakah HPA ingress mengubah effective limit?
Apakah perlu distributed limiter?

Observability

Apakah 429 terlihat di dashboard?
Apakah bisa dibedakan dari app-generated 429?
Apakah top offender bisa dianalisis tanpa melanggar privacy?

Safety

Apakah ada dry run/canary?
Apakah ada rollback?
Apakah ada exception process?
Apakah support/runbook tahu cara mendiagnosis false positive?

31. Internal Verification Checklist

Cek hal berikut di internal CSG/team:

Apakah rate limiting dilakukan di NGINX, API gateway, cloud WAF, app, atau kombinasi.
Controller Ingress apa yang digunakan dan annotation limit apa yang valid.
Apakah limit state shared antar ingress controller pod.
Apakah NGINX Plus feature digunakan atau hanya OSS/community controller.
Apakah status rejection default 429 atau 503.
Apakah Retry-After distandardisasi.
Apakah partner/customer contract punya burst/rate requirement.
Apakah ada route expensive seperti quote calculation/export/import.
Apakah auth identity tersedia di edge atau baru di aplikasi.
Apakah X-Tenant-ID/X-User-ID trusted atau berasal dari client.
Apakah source IP preservation sudah benar.
Apakah corporate NAT/partner proxy dipertimbangkan.
Apakah health check, monitoring, dan internal job terkena limit.
Apakah ada dashboard 429/limit rejection.
Apakah ada runbook false positive dan emergency bypass.
Apakah limit change butuh approval platform/security/SRE.

32. Anti-Patterns

Memakai per-IP limit untuk semua customer tanpa mempertimbangkan NAT.
Menganggap NGINX rate limit sebagai tenant quota yang kuat.
Menggunakan X-Tenant-ID dari client publik sebagai trusted key.
Membuat limit agresif tanpa data traffic.
Tidak mengubah rejection status menjadi 429.
Tidak menyediakan response JSON untuk API client.
Tidak mengamati 429 di dashboard.
Menerapkan limit_req ke WebSocket/SSE tanpa memahami long-lived connection.
Menaikkan burst sangat tinggi sampai limiter tidak melindungi apa pun.
Mengaktifkan limit di banyak layer tanpa koordinasi.
Mengabaikan retry storm setelah 429.
Tidak punya emergency bypass untuk partner critical integration.

33. Practical Senior Engineer Heuristics

Gunakan heuristik berikut:

Rate limit is a product and reliability policy, not only an NGINX directive.
Start with observed traffic, not arbitrary numbers.
Per-IP is protection, not fairness.
Per-tenant quota requires trusted identity and usually distributed state.
429 is better than ambiguous 503 for client behavior.
Retry-After without client backoff discipline can amplify spikes.
Burst protects UX but can still hurt upstream.
Delay mode hides overload as latency.
Every limiter must have dashboard, owner, and rollback.
False positives are production incidents.

34. Ringkasan

Rate limiting di NGINX adalah alat penting untuk melindungi backend Java/JAX-RS dari traffic spike, abuse, slow clients, dan expensive route overload.

Namun rate limiting yang buruk bisa menyebabkan:

customer valid terblokir
partner integration gagal
latency naik diam-diam
retry storm
false sense of global quota
incident yang tidak terlihat di application logs

Target pemahaman senior engineer:

membedakan rate, concurrency, dan bandwidth
memilih key yang benar
memahami burst/nodelay
mengembalikan 429 yang konsisten
melihat keterbatasan distributed limiter di Kubernetes
menghubungkan limiter dengan Java/JAX-RS resource bottleneck
mereview limiter sebagai reliability/security/product contract

NGINX rate limiting yang baik tidak hanya membatasi traffic. Ia membuat sistem lebih stabil, lebih adil, dan lebih mudah dioperasikan saat traffic nyata tidak berjalan sesuai asumsi desain.

Lesson Recap

You just completed lesson 18 in build core. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.