Lag ẩn: Hiểu về TCP Retransmissions
Máy chủ Linux của bạn trông có vẻ hoàn hảo trên lý thuyết. CPU nhàn rỗi ở mức 5%, và bạn có hàng gigabyte RAM trống, nhưng ứng dụng lại có cảm giác chậm chạp. Các yêu cầu vốn thường xử lý trong 20ms đột ngột tăng vọt lên 200ms hoặc thậm chí 2 giây. Khi cơ sở dữ liệu và mã nguồn không phải là vấn đề, nút thắt cổ chai có khả năng đang ẩn mình trong ngăn xếp mạng dưới dạng TCP Retransmissions (Truyền lại TCP).
TCP được thiết kế để đảm bảo độ tin cậy. Khi bên gửi truyền một gói tin, nó sẽ đợi một xác nhận (ACK). Nếu ACK đó không đến trước khi thời gian chờ truyền lại (Retransmission Timeout – RTO) kết thúc, bên gửi sẽ giả định gói tin đã biến mất và thử gửi lại. Mặc dù điều này ngăn ngừa mất dữ liệu, nhưng nó lại giết chết hiệu năng. Trên một đường truyền 10Gbps, ngay cả tỷ lệ truyền lại 1% cũng có thể cắt giảm băng thông thực tế của bạn xuống 50% hoặc hơn.
Tôi đã từng thấy các cụm máy chủ có lưu lượng truy cập cao hoạt động chậm chạp chỉ vì một cổng switch mạng bị lỗi hoặc sai lệch MTU. Thông thường, các đội ngũ lãng phí hàng ngày trời để viết lại các truy vấn cơ sở dữ liệu trong khi việc khắc phục thực tế chỉ cần một dòng tinh chỉnh kernel đơn giản.
Thiết lập bộ công cụ chẩn đoán của bạn
Để tìm ra nơi các gói tin đang biến mất, bạn cần một vài tiện ích cốt lõi. Hầu hết các công cụ này đã có sẵn trong hệ thống của bạn, nhưng một số có thể cần cài đặt nhanh.
1. iproute2 (ss và nstat)
Các công cụ ss và nstat đi kèm trong gói iproute2. Đây là tiêu chuẩn trên Ubuntu, CentOS, Debian và Fedora. Nếu bạn có thể chạy ip addr, nghĩa là bạn đã có chúng.
2. Wireshark và TShark
Wireshark rất tuyệt vời để phân tích trên máy tính để bàn, nhưng tshark là phiên bản bạn sẽ sử dụng trên các máy chủ từ xa thông qua giao diện dòng lệnh (CLI). Cài đặt nó bằng trình quản lý gói của bạn:
# Ubuntu / Debian
sudo apt update && sudo apt install tshark -y
# RHEL / CentOS / AlmaLinux
sudo yum install wireshark-cli -y
Phát hiện vấn đề với nstat và ss
Đừng bắt đầu ghi lại các tệp gói tin khổng lồ ngay lập tức. Trước tiên, hãy xác nhận quy mô của vấn đề bằng cách kiểm tra các bộ đếm nội bộ của kernel.
Kiểm tra thống kê tổng quát với nstat
Lệnh nstat lấy các chỉ số trực tiếp từ kernel. Để xem có bao nhiêu phân đoạn đã được truyền lại kể từ lần khởi động máy gần nhất, hãy chạy:
nstat -az TcpRetransSegs
Trong một mạng khỏe mạnh, con số này nên ở mức thấp—lý tưởng là dưới 0,05% tổng số phân đoạn. Để xem tỷ lệ truyền lại hiện tại trong khi bạn chạy thử nghiệm (benchmark), hãy sử dụng lệnh này để làm mới mỗi giây:
nstat -n 1 1
Kiểm tra từng Socket riêng lẻ với ss
Công cụ ss (socket statistics) là sự thay thế hiện đại cho netstat. Nó nhanh hơn đáng kể và tiết lộ trạng thái nội bộ của một kết nối TCP. Sử dụng cờ -i để xem các chi tiết này.
ss -ti
Hãy tìm trường retrans trong kết quả đầu ra. Dưới đây là một ví dụ về một kết nối có vấn đề:
ESTAB 0 0 192.168.1.10:443 1.2.3.4:5678
cubic rto:204 rtt:0.187/0.037 mss:1448 cwnd:10 bytes_retrans:4500 retrans:0/1
Trong retrans:0/1, chữ số đầu tiên hiển thị các lần truyền lại hiện chưa được xác nhận. Chữ số thứ hai là tổng số lần truyền lại cho phiên đó. Nếu bạn thấy bytes_retrans tăng lên hàng megabyte, bạn đã tìm thấy nút thắt cổ chai của mình.
Phân tích nguyên nhân gốc rễ với TShark
Khi bạn đã biết việc truyền lại đang xảy ra, bạn cần xem “hình thái” của sự thất bại đó. Máy chủ không gửi được, hay máy khách không xác nhận được?
Ghi lại vết lưu lượng (Capture)
Ghi lại lưu lượng truy cập trên giao diện đang hoạt động của bạn (như eth0) và lưu vào một tệp. Hãy giữ thời gian ghi ngắn để tránh làm đầy ổ đĩa.
sudo tshark -i eth0 -f "tcp" -w trace.pcap
Lọc các lỗi
Phân tích tệp bằng bộ lọc để làm nổi bật các gói tin gặp sự cố:
tshark -r trace.pcap -Y "tcp.analysis.retransmission"
Nếu bạn thấy một quy luật “Previous segment not captured” (Phân đoạn trước đó không được ghi lại) theo sau là một lần truyền lại, có khả năng một thiết bị phía trên như bộ cân bằng tải hoặc tường lửa đang làm rơi các gói tin trước khi chúng đến được máy chủ của bạn.
Các giải pháp hiệu quả cho các nút thắt cổ chai phổ biến
Sau khi xác định được vấn đề, hãy áp dụng các bản sửa lỗi này dựa trên những gì bạn tìm thấy.
1. Sửa lỗi “Hố đen” MTU
Nếu các lệnh ping nhỏ hoạt động nhưng việc truyền tệp lớn bị dừng ở mức 99%, có khả năng bạn đang gặp lỗi không khớp MTU. Điều này xảy ra khi máy chủ của bạn cố gắng gửi các gói tin 1500 byte, nhưng VPN hoặc đường hầm (tunnel) dọc theo đường truyền chỉ có thể xử lý 1400 byte. Gói tin bị loại bỏ một cách âm thầm.
Kiểm tra: Thử gửi một gói tin lớn không thể phân mảnh.
ping -M do -s 1472 8.8.8.8
Nếu lệnh này thất bại nhưng một lệnh ping tiêu chuẩn vẫn hoạt động, hãy hạ MTU của bạn xuống 1400:
sudo ip link set dev eth0 mtu 1400
2. Khắc phục nút thắt cổ chai bộ đệm Kernel
Khi nstat hiển thị TcpExtTCPBacklogDrop, điều đó có nghĩa là ứng dụng của bạn quá chậm để lấy dữ liệu ra khỏi hàng đợi của kernel. Bộ đệm bị đầy và kernel bắt đầu loại bỏ các gói tin mới.
Tăng giới hạn backlog trong /etc/sysctl.conf để ứng dụng của bạn có thêm không gian xử lý:
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 4096
# Tăng các giá trị này để tránh việc kernel loại bỏ gói tin khi tải cao
Chạy sudo sysctl -p để áp dụng các thiết lập.
3. Chuyển sang Kiểm soát nghẽn BBR
Thuật toán cubic mặc định xử lý việc mất gói tin kém trên các đường truyền khoảng cách xa hoặc bận rộn. BBR (Bottleneck Bandwidth and Round-trip propagation time) của Google thông minh hơn nhiều. Nó bỏ qua các lỗi mất gói nhỏ và tập trung vào băng thông thực tế.
Kích hoạt nó bằng các lệnh sau:
sudo sysctl -w net.core.default_qdisc=fq
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr
Danh sách kiểm tra tóm tắt
Hãy làm theo quy trình này vào lần tới khi bạn cảm thấy mạng bị chậm:
- Chạy nstat để xem các bộ đếm truyền lại tổng quát có đang tăng lên không.
- Sử dụng ss -ti để tìm các địa chỉ IP cụ thể đang gặp khó khăn.
- Ghi lại vết bằng tshark để xem các gói tin có đến sai thứ tự hay không.
- Kiểm tra kích thước MTU nếu kết nối bị treo trong quá trình truyền dữ liệu lớn.
- Kích hoạt BBR nếu bạn đang xử lý lưu lượng truy cập xuyên vùng có độ trễ cao.

