Nginx, HAProxy hay Envoy

Tùng Duy

23/01/2026

Tình cờ xem được bài viết này bên devopsvn, hay là một chuyện mà có nhiều góc nhìn cho các bạn mới, Nên mình đã clone về để cho mọi người xem, chứ chẳng có nghĩ ra được nội dung như vậy đâu.

Bài toán này đến từ một hạ tầng phục vụ nội bộ bên tôi (và có nhánh ra cho partner thân thiết – nghĩ vậy cho dễ hình dung) về cơ bản thì vẫn chạy nhưng có vấn đề là hệ thống không hề chậm theo kiểu rõ ràng. Mà nó khiến trải nghiệm khó chịu như là:

  • Anh em lâu lâu than: “Sao API lúc nhanh lúc chậm?”
  • Webhook partner gửi log: “Thỉnh thoảng thấy timeout”
  • Grafana thì không báo đỏ, nhưng p95/p99 cứ nhích lên từng tuần, đặc biệt khi có đợt spike.

Tôi coi lại kiến trúc và thấy thứ đập ngay vào mắt: reverse proxy/gateway. Đây là tầng mà nếu bạn chọn đúng, bạn gần như quên nó tồn tại. Chọn sai… bạn sẽ sống cùng nó mỗi ngày (câu này nghe từ đâu khi đọc blog kỹ thuật trước đây ấy nên lúc đó hình dung ngay đến).

Vậy là tôi quyết định benchmark cụ thể (còn trước đó công ty tôi dùng gì anh em đừng hỏi làm gì nhé…), về cơ bản thì cũng ngâm lâu, muốn xem cụ thể sao chứ đọc lý thuyết, hỏi AI cũng tương đối với có số liệu review lương cũng dễ :))).

3 cái tên rất quen thuộc là:

  • Nginx: ai cũng biết, dễ triển khai, làm được nhiều thứ.
  • HAProxy: nổi tiếng về tính ổn định, chịu tải cao rất tốt.
  • Envoy: cloud-native, gRPC/HTTP2 mạnh, telemetry ngon.

Mục tiêu rõ ràng là không phải tool nào nhanh hơn 5%, mà là câu hỏi thực tế: Nếu giờ mình đặt nó ở gateway production, tool nào cho p99 ổn định nhất nhất?

Vô việc thôi chứ ở trên cũng rõ ràng lắm rồi, quý lắm mới share nhé :Đ

Nhân tiện các anh em thích đọc bài chia sẻ của tôi thì cùng tham gia góp ý State of DevOps VietNam 2026 để anh em cùng biết mình đang đứng ở đâu và học hỏi nhau nhé.

Bài toán benchmark

Tôi cũng từng thấy các bài benchmark kiểu:

  • Backend trả OK trong 50 micro giây
  • Chạy chung một máy
  • Tắt TLS
  • Kết luận A nhanh hơn B 2 lần =))

Nhìn vui, nhưng đem ra production thì chưa thực tế được.

Tôi chọn một bài toán mà tôi gặp hàng ngày:

  1. REST API keep-alive (chiếm phần lớn traffic): JSON nhỏ, request/response vài KB
  2. Webhook (đáng ghét nhất): nhiều client không reuse connection -> TLS handshake nhiều
  3. HTTP/2 (phần web/app mới): multiplexing
  4. gRPC unary (internal calls): cần p99 ổn và route theo header/metadata

Với bài toán của tôi thì tôi cũng không cần cố bơm lên 200k req/s cho oai làm gì, làm sao share vậy. Tôi chọn mức mà một đội nhỏ chạy SaaS vừa/nhỏ vẫn gặp: 5k–25k rps tùy kịch bản, đủ để thấy khác biệt.

Chuẩn bị hạ tầng

Hạ tầng công ty dư nhưng phục vụ đúng phạm vi thì cũng bình thường thôi, tôi dùng 3 con VM để tránh benchmark bị nhiễu kết quả do cache cục bộ (local cache) hoặc vòng lặp nội bộ (loopback):

  • Loadgen: bắn traffic
  • Proxy: lần lượt chạy Nginx/HAProxy/Envoy
  • Backend: service Go đơn giản (HTTP + gRPC)

Cấu hình mỗi máy:

  • 4 vCPU, 8GB RAM, Ubuntu 22.04 (tôi thấy rất nhiều bài toán benchmark anh em Việt Nam hay thế giới rất ưa lựa cấu hình như này, từ lâu tôi cũng dựa vào)
  • cùng subnet, latency nội bộ khoảng 0.3-0.8ms

Backend thì chắc chắn không phải hello world rồi. Tôi cho nó làm một chút CPU nhẹ (parse + marshal) để giống API thật. Không có DB để tránh nhiễu.

Và tôi bật TLS termination ở proxy. Không TLS thì benchmark gần như tối ưu hơn hẳn nhưng… môi trường production thực tế không lý tưởng như vậy.

Tôi chuẩn hóa điều kiện để fair (đo cái cần đo)

Luật chơi tôi đặt là:

  • Tắt access log (log nhiều là giết benchmark)
  • Cùng TLS policy (TLS1.3, cipher suite tương tự)
  • Backend không đổi
  • Tăng ulimit -n, backlog… đủ để test không chết vì OS

Có thể có bạn nghĩ nhì nhằng nhưng mà thực hiện cấu hình cơ bản để kết quả phản ánh đúng hiệu năng của proxy, tránh bị giới hạn bởi ngưỡng tài nguyên hệ thống (OS limits/ulimit).

Kịch bản tôi chạy

Tôi chạy 4 kịch bản riêng:

A) REST keep-alive (HTTP/1.1)

  • 500 concurrent
  • Target ~20k rps
  • Chạy 60s (warm-up 20s)

B) Webhook/short connection

  • 1k concurrent
  • Target ~5k rps
  • Cố tình giảm connection reuse để giả lập client khó chịu

C) HTTP/2

  • Ít connection nhưng nhiều stream
  • Target ~15k rps

D) gRPC unary

  • 500 concurrent
  • Target ~10k rps

Metric tôi quan tâm nhất: p95/p99 và error rate. RPS là quan trọng, nhưng p99 mới là chỉ số phản ánh chính xác trải nghiệm người dùng (user experience) về độ ổn định của hệ thống.

Kết quả

A) REST keep-alive tầng giao diện của hệ thống

Tôi ghi lại kết quả kiểu đồng bộ dữ liệu từ Grafana vào bảng thống kê:

ProxyRPS đạt đượcp95p99CPU proxyRAM proxy
HAProxy~22.1k~11.8ms~18.6ms~310%~55MB
Nginx~20.3k~13.5ms~22.4ms~330%~90MB
Envoy~18.4k~16.1ms~27.9ms~360%~260MB

Cảm giác của tôi khá rõ: HAProxy cho thấy sự tối ưu vượt trội. Không cần cấu hình phức tạp, nhưng p99 đẹp và tài nguyên gọn.

Nginx thì không hề tệ. Nếu mà bạn đã dùng Nginx từ trước, thì giữ nguyên hoàn toàn khả thi, vì chênh lệch không quá đáng. Nhưng Envoy rõ ràng nặng hơn trong bài toán REST keep-alive.

B) Webhook/short connection nơi chi phí TLS bắt đầu phát sinh đáng kể

Khi tôi chuyển sang kịch bản short connection, mọi thứ chậm đi thấy rõ, đúng như dự đoán.

ProxyRPS đạt đượcp95p99Error
HAProxy~5.3k~41ms~55ms~0.1%
Nginx~5.0k~45ms~60ms~0.2%
Envoy~4.6k~55ms~75ms~0.4%

Điểm tôi rút ra ngay: Nếu hệ thống có nhiều webhook hoặc client không tái sử dụng kết nối (connection reuse), quá trình TLS handshake trở thành chi phí tài nguyên (overhead) mà gateway phải xử lý. Ở kịch bản này, HAProxy vẫn giữ lợi thế về tính ổn định dưới tải cao.

C) HTTP/2 Envoy bắt đầu khẳng định ưu thế

Đến HTTP/2, tôi thấy Envoy tỏa sáng hơn.

ProxyRPS đạt đượcp95p99
Envoy~15.2k~12.2ms~20.1ms
HAProxy~14.4k~13.0ms~23.4ms
Nginx~13.8k~14.6ms~25.2ms

Tôi thấy ngay là Envoy đúng là sinh ra cho các bài toán cloud-native, protocol hiện đại. Nó không nhất thiết nhanh nhất mọi lúc, nhưng khi vào đúng bài, chỉ số vận hành rất ấn tượng.

D) gRPC unary và đây là lúc tôi hiểu vì sao service mesh chọn Envoy

gRPC unary benchmark của tôi:

ProxyRPS đạt đượcp95p99
Envoy~10.6k~10.5ms~18.2ms
HAProxy~10.1k~11.4ms~20.6ms
Nginx~9.4k~13.7ms~24.9ms

Ở đây không chỉ là chỉ số độ trễ, mà còn về khả năng tương thích: Envoy hỗ trợ gRPC một cách tối ưu (native support). Và khi triển khai các kiến trúc phức tạp như routing, canary deployment, telemetry hay mTLS, Envoy giúp giảm thiểu việc phải tùy biến các thành phần phụ trợ.

Những cú ngã (để mọi người khỏi tự lừa mình)

Nói đúng ra benchmark lần đầu của tôi khá fail.

  1. Quên tắt access log -> số liệu tụt, CPU tăng, tôi tưởng proxy yếu.
  2. Test backend quá basic -> kết quả đẹp kiểu vô lý, nhìn đã biết không thực tế.
  3. Không tách keep-alive vs short connection -> kết luận bị nhiễu, vì chỉ cần client đổi pattern là kết quả đảo chiều.
  4. Quên tăng ulimit -n -> đến khi concurrency cao, lỗi connect xuất hiện, tôi suýt đổ thừa proxy.

Nên tại sao những bài như thế này tôi khá là thích viết và chia sẻ vì sẽ giúp được nhiều anh em và tôi luôn nghĩ là: Benchmark không khó. Khó là làm sao để benchmark không nói dối mình.

Sau tất cả đúc kết được gì?

hạ tầng thì bên tôi đã dựng rồi nhưng mà nếu tôi chỉ được chọn 1 con cho gateway public phục vụ không quá lớn (như của tôi là nội bộ và một vài đối tác chiến lược) ngay từ ban đầu, tôi sẽ chọn:

HAProxy cho edge gateway

Vì:

  • REST keep-alive: chỉ số p99 ổn định, RPS cao, mức tiêu thụ tài nguyên tối ưu.
  • Webhook short connection: có khả năng chống chịu tốt hơn trước các tác vụ handshake liên tục.
  • Vận hành: cấu hình minh bạch, ít overhead features, hạn chế các lỗi phát sinh ngoài dự kiến.

Nhưng tôi cũng không phủ nhận:

Envoy cho internal gRPC/mesh-ish

Vì:

  • HTTP/2/gRPC vào đúng bài thì rất đẹp
  • Traffic management + telemetry + dynamic config: Envoy đúng hệ sinh thái

Và:

Nginx là lựa chọn rất hợp lý nếu team đã quen

Nếu hệ của bạn có nhiều static/caching thì Nginx vẫn là một lựa chọn cực kỳ tin cậy, đặc biệt khi đội ngũ đã có kinh nghiệm vận hành từ trước.

Lời kết

Cuối cùng, gateway không phải nơi để thể hiện đẳng cấp công nghệ. Gateway là nơi để người dùng không phải nghĩ về nó – đột nhiên nghĩ ra câu này ưng thật :))

Nếu mọi người muốn, tôi sẽ viết thêm một phần phụ lục:

  • config tối thiểu fair cho Nginx/HAProxy/Envoy
  • lệnh chạy wrk2/h2load/ghz
  • template ghi kết quả để share nội bộ

Mấy cái này là benchmark fail trước mà có được đấy nhưng bài cũng dài rồi. Viết nữa mọi người đọc cũng mệt, mong bài viết giúp được ít nhiều mọi người nhé.