Chuyện gì xảy ra khi mạng “hắt hơi sổ mũi”?
Anh em làm Dev hay DevOps chắc không lạ gì cảnh: App chạy ở local mượt như nhung, test staging cũng ổn. Thế nhưng, vừa đẩy lên production, khách hàng đã than phiền: “Sao hệ thống quay vòng vòng thế này?”.
Mình từng xử lý một sự cố nhớ đời. Hệ thống microservices đang chạy ổn định thì một con switch tại data center gặp lỗi, gây packet loss khoảng 5%. Ngay lập tức, Service A gọi Service B bị timeout liên tục. Các thread bị block hàng loạt, kéo sập toàn bộ hệ thống theo hiệu ứng domino chỉ trong 10 phút. Lúc đó mình mới thấm thía: Mạng máy tính không bao giờ hoàn hảo.
Trong thực tế, mạng luôn tiềm ẩn độ trễ (latency), mất gói tin (packet loss) hoặc xáo trộn thứ tự (reordering). Nếu ứng dụng không được thiết kế để “sống chung với lũ”, nó sẽ gục ngã ngay khi gặp biến cố nhỏ nhất.
Tại sao ứng dụng lại “ngỏm” khi mạng bất ổn?
Lỗi thường không nằm ở logic nghiệp vụ. Nó nằm ở cách chúng ta quản lý kết nối. Dưới đây là 3 kịch bản phổ biến nhất:
- Timeout mặc định quá dài: Nhiều thư viện để timeout mặc định là 30s hoặc thậm chí là vô hạn. Khi mạng lag, request bị treo, worker bị chiếm dụng hết khiến tài nguyên cạn kiệt.
- Cơ chế Retry “ngây thơ”: Mạng đang nghẽn mà bạn cứ retry liên tục với tần suất cao? Bạn vừa tự tấn công từ chối dịch vụ (DoS) chính hệ thống của mình đấy.
- Thiếu Circuit Breaker: Service hạ nguồn chậm nhưng service phía trên vẫn miệt mài gửi request. Không có bộ ngắt mạch, lỗi sẽ lan rộng ra toàn hệ thống.
Thay vì ngồi cầu nguyện, chúng ta nên chủ động gây lỗi ngay từ khâu kiểm thử (Chaos Engineering). Với Docker, Pumba chính là công cụ thực chiến hiệu quả nhất.
Các phương pháp giả lập lỗi mạng truyền thống
Trước khi có Pumba, dân kỹ thuật thường dùng vài cách thủ công:
- Lệnh
tc(Traffic Control): Công cụ gốc trên Linux. Nó cực mạnh nhưng cú pháp rất khó nhớ. Chỉ cần gõ nhầm một thông số, bạn có thể làm rớt mạng toàn bộ máy host. - Cấu hình Proxy/Gateway: Dùng proxy trung gian để bóp băng thông. Cách này tốn thời gian setup và cực kỳ khó tự động hóa trong quy trình CI/CD.
- Rút dây mạng: Cách này mang tính “vật lý” quá cao, không thể áp dụng cho container hay môi trường cloud.
Pumba – Vũ khí bí mật cho Docker container
Pumba là công cụ Chaos Testing mã nguồn mở dành riêng cho Docker. Nó cho phép bạn thử thách container bằng cách kill, stop hoặc can thiệp trực tiếp vào network interface. Điểm cộng lớn nhất là bạn không cần sửa bất kỳ dòng code nào của ứng dụng.
Pumba chạy dưới dạng một container độc lập. Nó mount vào docker.sock để điều khiển các container khác. Thực chất, Pumba đóng gói lại sức mạnh của tc bằng những câu lệnh đơn giản, dễ hiểu.
Khi cần tính toán subnet nhanh để giới hạn dải IP cho container, mình hay dùng toolcraft.app/vi/tools/developer/ip-subnet-calculator. Nhập CIDR là có ngay network range và số host, rất tiện khi cần cô lập môi trường test network.
1. Cài đặt Pumba nhanh gọn
Bạn không cần cài đặt gì vào máy host. Hãy chạy Pumba trực tiếp bằng Docker để kiểm tra phiên bản:
docker run --rm gaiaadm/pumba pumba --version
2. Giả lập Latency (Độ trễ mạng)
Giả sử bạn có container tên là web_app. Bạn muốn giả lập tình trạng mạng đi ra bị chậm thêm 3000ms (3 giây) trong vòng 5 phút:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
gaiaadm/pumba pumba netem \
--duration 5m \
delay --time 3000 \
web_app
Để thực tế hơn, hãy thêm tham số --jitter. Ví dụ: delay --time 3000 --jitter 500. Lúc này độ trễ sẽ dao động từ 2500ms đến 3500ms, giống hệt môi trường mạng thực.
3. Giả lập Packet Loss (Mất gói tin)
Mất gói tin là cơn ác mộng của giao thức TCP. Nó buộc hệ thống phải retransmit, làm tăng độ trễ khủng khiếp. Để giả lập mất 20% số gói tin:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
gaiaadm/pumba pumba netem \
--duration 3m \
loss --percent 20 \
web_app
4. Giới hạn băng thông (Bandwidth Limit)
Nếu muốn kiểm tra ứng dụng hoạt động ra sao khi mạng yếu như thời dùng modem 2G, hãy dùng lệnh rate:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
gaiaadm/pumba pumba netem \
--duration 5m \
rate --rate 100kbit \
web_app
Kịch bản thực tế: Kiểm tra khả năng tự phục hồi
Mình thường áp dụng Pumba vào quy trình test như sau:
- Khởi động toàn bộ stack (App, Redis, Postgres) bằng Docker Compose.
- Dùng Pumba cắt hoàn toàn kết nối hoặc tạo độ trễ 10 giây cho database.
- Quan sát log: App có báo lỗi rõ ràng không? Connection Pool có bị tràn không? Quan trọng nhất, khi Pumba dừng, app có tự động reconnect hay treo luôn?
Ví dụ, kịch bản tạo mạng chập chờn cho api_service: cứ mỗi 10 giây lại bị lag 500ms trong vòng 2 giây:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
gaiaadm/pumba pumba \
--interval 10s \
netem --duration 2s delay --time 500 api_service
Bài test này giúp mình phát hiện ra nhiều thư viện connection pool giữ “dead connection” vĩnh viễn nếu không cấu hình maxLifetime hoặc idleTimeout chuẩn xác.
Tổng kết
Chúng ta không thể yêu cầu hạ tầng mạng luôn ổn định 100%. Tuy nhiên, bạn hoàn toàn có thể kiểm soát cách ứng dụng phản ứng với sự cố. Pumba giúp bạn xây dựng một hệ thống “lỳ đòn” và bền bỉ hơn.
Đừng đợi đến khi hệ thống thực tế sập mới đi tìm nguyên nhân. Hãy đưa Pumba vào các bài test integration hoặc thử nghiệm trực tiếp trên staging. Chúc anh em có những hệ thống chạy ổn định bất chấp mạng lag!

