Nginx 502 Bad Gateway: Kernel Báo Lỗi “Cannot assign requested address”

Nhìn các anh chia sẻ học hỏi được nhiều quá mà toàn kinh nghiệm giá trị, nên khi em muốn chia sẻ gì cũng lo là nó cơ bản thì không đem lại value cho các bạn, nhưng nghĩ là đều là kinh nghiệm không phục vụ các bác trình cao như các anh vẫn chia sẻ thì phục vụ các bạn như mình.

Nay tranh thủ dậy sớm xem lại docs đã note, em xin chia sẻ một issue mà em nghĩ là rất nhiều bác mới làm quen với Nginx làm Reverse Proxy sẽ dính. Đó là khi hệ thống tải cao, Nginx lăn ra chết, nhưng không phải do thiếu CPU hay RAM, mà là do “hết số” :Đ

Cụ thể ở đây là hết Ephemeral Port. Các bác cùng em mổ xẻ lỗi Cannot assign requested address nhé.

0f5a1acb-016b-44d4-abb2-9d670215707f

Bài toán

Vụ này em gặp trên một hệ thống API Gateway sử dụng Nginx để forward traffic vào cụm Microservices phía sau (backend viết bằng Go).

  • Infrastructure: Nginx chạy trên máy ảo Linux (4 vCPU, 8GB RAM).
  • Architecture: Nginx đóng vai trò Load Balancer, nhận request từ Client và proxy_pass vào Upstream server (Backend).
  • Traffic Pattern: Bình thường khoảng 200-300 RPS (Request Per Second). Hôm đó có đợt tăng đột biến, traffic dựng đứng lên 3000 RPS.
  • Configuration: Config Nginx mặc định, chỉ khai báo proxy_pass đơn giản.

Biểu hiện

Ngay khi traffic chạm ngưỡng 2000 RPS, Monitoring Dashboard đỏ lòm. Client bên ngoài nhận về hàng loạt lỗi 502 Bad Gateway.

Em nhảy vào check log Nginx error.log, thì thấy dòng lỗi này spam liên tục (em đã ẩn một số thông tin):

2025/MM/dd 10:00:00 [crit] 12345#0: *67890 connect() to x.x.x.x:8080 failed (99: Cannot assign requested address) while connecting to upstream, client: y.y.y.y, server: api.example.com, request: "GET /v1/products HTTP/1.1", upstream: "http://x.x.x.x:8080/v1/products"

Các bác chú ý kỹ cái mã lỗi 99: Cannot assign requested address. Đây không phải là lỗi Timeout (110) hay Connection Refused (111). Đây là Kernel đang từ chối cấp phát resource mạng cho Nginx.

Các chỉ số gây hiểu lầm và Điều tra

Lúc đầu em hơi hoảng, đoán mò vài hướng sai lầm:

  • Đoán sai 1: Backend (Upstream) bị sập?

    • Em check log của Backend service thì thấy vẫn sống nhăn, CPU thấp. Thậm chí số lượng request đến Backend còn giảm đi (vì Nginx không đẩy vào được).
  • Đoán sai 2: Server Nginx hết RAM hoặc CPU?

    • Em chạy htop, CPU mới chỉ load 30%, RAM còn trống cả đống.
  • Investigation Path chuẩn:

    • Từ cái lỗi Cannot assign requested address, em nghi ngờ liên quan đến TCP Socket.
    • Em dùng lệnh ss (socket statistics) để xem tình trạng connection: ss -s

    Kết quả trả về một con số giật mình:

    • Total: 30000 (kernel 0)
    • TCP: 29500 (estab 500, closed 0, orphaned 0, synrecv 0, timewait 29000/0), ports 0

    Các bác thấy gì không? Có tới 29,000 socket đang ở trạng thái TIME_WAIT.

Nguyên nhân gốc và biện pháp khắc phục

Root Cause: Vấn đề nằm ở cơ chế TCP/IP và cách Nginx mặc định xử lý connection tới Upstream.

  1. Ephemeral Port Limit: Mỗi khi Nginx mở một connection tới Upstream, nó cần một Source IP và một Source Port. Cái Source Port này được lấy từ dải Ephemeral Port của Linux Kernel (thường config trong net.ipv4.ip_local_port_range, mặc định khoảng từ 32768 đến 60999, tức là chỉ có khoảng ~28,000 ports khả dụng).

  2. TCP TIME_WAIT: Mặc định, Nginx dùng HTTP/1.0 để nói chuyện với Upstream và không dùng Keepalive. Nghĩa là:

    • Nginx mở connection => Gửi Request => Nhận Response => Nginx chủ động đóng connection.
    • Theo chuẩn TCP, bên nào chủ động đóng connection (Active Close) sẽ phải giữ socket ở trạng thái TIME_WAIT trong một khoảng thời gian (thường là 60 giây) để đảm bảo mọi packet lạc trôi được xử lý hết.
  3. Toán học phũ phàng: Với 28,000 ports và thời gian TIME_WAIT là 60s. Max Throughput = 28,000 / 60s = ~466 Request/giây (cho mỗi IP Upstream).

    Khi traffic lên 3000 RPS, em đã đốt sạch quỹ port chỉ trong vài giây. Kernel không còn port nào rảnh để cấp cho connection mới => Lỗi Cannot assign requested address.

Remediation (Giải pháp): Cách xử lý triệt để nhất là tái sử dụng connection (Connection Pooling) thay vì mở mới rồi đóng liên tục.

Em sửa config Nginx như sau: Bước 1: Định nghĩa upstream block có directive keepalive.

upstream backend_api {
    server 10.0.1.5:8080;
    # Giữ tối đa 64 idle keepalive connections tới mỗi worker process
    keepalive 64;
}

Bước 2: Trong location block, bắt buộc Nginx dùng HTTP/1.1 và xóa header Connection: close.

location / {
    proxy_pass http://backend_api;

    # Bắt buộc dùng HTTP 1.1 (Mặc định là 1.0)
    proxy_http_version 1.1;

    # Xóa header Connection để Nginx không gửi "close" tới Upstream
    proxy_set_header Connection "";
}

Sau khi reload Nginx, số lượng connection TIME_WAIT tụt dốc không phanh từ 29,000 xuống còn vài trăm. Lỗi 502 biến mất hoàn toàn.

Bài học

Qua vụ này, em cũng note ra mấy bài học các bác nếu gặp có thể tham khảo:

  1. Luôn bật Keepalive cho Inter-service Communication: Trong môi trường Microservices, việc mở/đóng TCP connection liên tục là cực kỳ tốn kém (về CPU cho TCP Handshake và về Resource như Port). Luôn đảm bảo cơ chế Connection Pooling được kích hoạt ở mọi tầng (Nginx, Database Driver, HTTP Client).
  2. Đừng vội tune Kernel bừa bãi: Nhiều bác search Google/AI sẽ thấy lời khuyên sửa net.ipv4.tcp_tw_reuse hoặc net.ipv4.tcp_tw_recycle (đã bị bỏ trong kernel mới).
    • tcp_tw_reuse: Có thể dùng, nhưng là giải pháp ở tầng OS.
    • tcp_tw_recycle: Tuyệt đối không dùng trong môi trường NAT, nó sẽ làm rớt gói tin lung tung.
    • Giải pháp ở tầng Application/Config (như bật Keepalive) luôn tốt hơn và an toàn hơn tuning Kernel.
  3. Hiểu về TCP State Diagram: Làm DevOps/SRE mà không nắm vững TCP Handshake (SYN, SYN-ACK, ACK) và quy trình đóng connection (FIN, FIN-ACK, TIME_WAIT) thì debug network rất khó. Cái lỗi Cannot assign requested address này là ví dụ điển hình của việc hiểu sai về lifecycle của một socket.

Thông tin nổi bật

Sự kiện phát trực tiếp​

Event Thumbnail

Báo cáo quan trọng

Article Thumbnail
Article Thumbnail
Chia sẻ bài viết:
Theo dõi
Thông báo của
0 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận

Tiêu điểm chuyên gia