1. Ringkasan Insiden
Layanan API berbasis Actix Web mengalami lonjakan sporadis galat 502 Bad Gateway pada klien. Metrik menunjukkan kegagalan terjadi terutama saat jeda antar-request atau pada trafik rendah ke menengah. Tidak ditemukan panic, alokasi memori berlebih, atau log error di tingkat aplikasi Actix Web, namun log reverse proxy (Nginx / AWS Application Load Balancer) mencatat pemutusan koneksi upstream secara mendadak.
2. Akar Masalah: Race Condition pada TCP Keep-Alive
Galat 502 ini dipicu oleh perebutan penutupan koneksi (race condition) antara reverse proxy dan backend Actix Web pada level TCP. Keduanya memelihara koneksi persisten (HTTP Keep-Alive) untuk mengurangi overhead jabat tangan TCP/TLS.
Masalah timbul ketika durasi idle keep-alive pada Actix Web lebih pendek atau mendekati durasi keep-alive pada reverse proxy:
- Koneksi TCP pada pool proxy berada dalam status menganggur (idle).
- Actix Web mencapai batas
keep_aliveinternalnya dan mengirimkan paket TCPFINuntuk menutup koneksi. - Pada milidetik yang sama, reverse proxy menerima request baru dari klien dan langsung meneruskannya ke koneksi idle tersebut sebelum menerima atau memproses paket
FINdari Actix Web. - Kernel Actix Web menerima data HTTP pada soket yang statusnya sudah ditutup (
FIN_WAIT_2/CLOSED), sehingga kernel secara otomatis merespons dengan paket TCPRST(Reset). - Reverse proxy menerima paket
RSTsaat mengharapkan header respons HTTP, memutus transaksi, dan mengembalikan status502 Bad Gatewayke klien.
3. Prosedur Observabilitas dan Investigasi
Identifikasi masalah memerlukan korelasi log proxy dan inspeksi jaringan.
Log Nginx
Pada Nginx, pola kegagalan ini meninggalkan jejak spesifik di /var/log/nginx/error.log:
[error] 1042#1042: *8912 upstream prematurely closed connection while reading response header from upstream, client: 10.0.1.20, server: api.internal, request: "GET /v1/resource HTTP/1.1", upstream: "http://127.0.0.1:8080/v1/resource"Atau varian pemutusan koneksi level soket:
recv() failed (104: Connection reset by peer) while reading response header from upstreamAWS Application Load Balancer (ALB)
Pada log akses ALB, periksa kolom elb_status_code dan target_status_code:
type: http
elb_status_code: 502
target_status_code: -
target_processing_time: -1
reason_code: TargetConnectionResetNilai target_status_code: - dan reason_code: TargetConnectionReset mengonfirmasi bahwa target merespons dengan TCP RST sebelum header HTTP dikirimkan.
Verifikasi Paket Jaringan
Jalankan tcpdump pada host backend untuk mengonfirmasi urutan paket FIN/RST:
sudo tcpdump -nnvv -i any 'tcp[tcpflags] & (tcp-rst) != 0' and port 80804. Solusi Teknis: Standardisasi Hierarchy Timeout
Prinsip absolut penanganan koneksi persisten:
Aturan Timeout: Durasi Keep-Alive Upstream (Actix Web) HARUS selalu lebih besar daripada Durasi Keep-Alive Downstream (Reverse Proxy). Tambahkan toleransi minimal 5 hingga 15 detik.
Implementasi pada Actix Web
Konfigurasikan HttpServer::keep_alive secara eksplisit menggunakan durasi yang lebih tinggi dari proxy (misalnya 75 detik jika proxy menggunakan 60 detik):
use actix_web::{web, App, HttpServer, HttpResponse, Responder};
use std::time::Duration;
async fn health_check() -> impl Responder {
HttpResponse::Ok().body("healthy")
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/health", web::get().to(health_check))
})
// Pastikan nilai ini lebih besar dari keep-alive timeout reverse proxy
.keep_alive(Duration::from_secs(75))
// ponytail: single-worker bypass, upgrade ke num_cpus untuk production traffic
.bind(("0.0.0.0", 8080))?
.run()
.await
}Konfigurasi Nginx Pasangannya
Konfigurasikan Nginx agar menutup koneksi idle sebelum Actix Web menutupnya:
upstream actix_backend {
server 127.0.0.1:8080;
keepalive 32; # Pool koneksi idle ke upstream
}
server {
listen 80;
server_name api.internal;
location / {
proxy_pass http://actix_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
# Harus lebih rendah dari keep_alive Actix Web (75s)
keepalive_timeout 60s;
# Mekanisme retry aman jika koneksi tertutup
proxy_next_upstream error timeout invalid_header http_502;
proxy_next_upstream_tries 3;
}
}5. Tindakan Preventif Pasca-Insiden
- Sinkronisasi Konfigurasi Infrastruktur: Dokumentasikan matriks timeout. Jika ALB memiliki Idle Timeout 60 detik, konfigurasi Actix Web wajib disetel minimal 65-75 detik.
- Retry Aman pada Proxy: Pastikan proxy dikonfigurasi untuk mencoba ulang (retry) pada server upstream lain atau koneksi baru jika menerima
errorsaat inisiasi koneksi. Pastikan request non-idempotent ditangani secara hati-hati agar tidak terjadi duplikasi proses transaksi. - Pemantauan Galat: Pasang metrik alarm pada AWS CloudWatch (
HTTPCode_Target_5XX_Count) atau Prometheus untuk mendeteksi anomali rasio 502 terhadap total request dalam interval 1 menit.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!