Phần 26 đo bộ đệm ổ cắm và kết luận rằng không bộ đệm nào chữa được mất gói. Bài này đo xem mất gói lấy đi bao nhiêu.

Thông lượng và cwnd theo độ trễ và tỷ lệ mất gói

Bảng

Cùng chương trình, cùng máy, đổi điều kiện đường truyền bằng tc netem. Ba lần đo mỗi điều kiện, mỗi lần 6–12 giây liên tục, đồng thời đọc cwnd từ ss -ti:

Đường truyền Thông lượng (MB/s) cwnd lớn nhất cwnd lúc kết thúc
0 ms, mất 0% 10.403 / 10.435 / 10.337 3.779–4.812 y nguyên
20 ms, mất 0% 155,3 / 148,7 / 150,4 6.232–6.836 y nguyên
20 ms, mất 0,1% 65,5 / 46,3 / 52,1 6.046–7.466 361–727
20 ms, mất 1% 8,5 / 1,1 / 1,9 46–136 10–26
20 ms, mất 3% 0,8 / 0,6 / 0,6 14–203 5–11

Độ trễ một mình đã lấy 69 lần

Dòng thứ hai không có gói nào bị mất. Máy không đổi, đường truyền không đổi, phần mềm không đổi. Chỉ mỗi thời gian đi về.

10.403 xuống 150 MB/s — 69 lần.

Lý do nằm ở một giới hạn duy nhất: TCP chỉ cho phép một lượng dữ liệu nhất định đang bay mà chưa được báo nhận. Lượng đó là cửa sổ tắc nghẽn. Sau khi gửi đầy cửa sổ, bên gửi phải chờ ACK, và ACK mất một vòng khứ hồi.

thong luong toi da = cua so / vong khu hoi

Không cách nào lách. Muốn nhanh hơn thì cửa sổ phải lớn hơn, và cửa sổ lớn hơn cần bộ nhớ ở cả hai đầu — đúng phần mà tcp_rmem/tcp_wmem của phần 26 giới hạn.

Rồi mất 1% gói lấy thêm 40 lần nữa

Tỷ lệ mất Thông lượng So với không mất
0% ~150 MB/s
0,1% ~55 MB/s 3× chậm hơn
1% ~4 MB/s 40× chậm hơn
3% ~0,7 MB/s 210× chậm hơn

Mất một phần nghìn số gói làm thông lượng còn một phần ba.

Nói lại lần thứ hai vì nó là câu đáng nhớ nhất của bài: mất gói không làm mất 1% dữ liệu — nó làm sập cửa sổ tắc nghẽn.

Câu "chỉ mất có 1% thôi" trong một báo cáo sự cố là một trong những câu nguy hiểm nhất, vì nó nghe như một sai số nhỏ trong khi nó là nguyên nhân của việc mọi thứ chậm đi 40 lần.

Cột cwnd giải thích toàn bộ

Không mất gói: cwnd leo đều tới 6.232–6.836 gói rồi ở nguyên đó. Không có gì kéo nó xuống.

Mất 1%: cwnd không bao giờ vượt quá 136 và kết thúc ở 10–26 gói.

Cơ chế của CUBIC (và của Reno trước nó): mỗi lần phát hiện mất gói thì cắt đôi cửa sổ, rồi tăng lại từ từ. Với vòng khứ hồi 20 ms và mất gói cứ vài trăm gói một lần, cửa sổ không bao giờ có đủ thời gian yên ổn để lớn lên.

Kết quả là một trạng thái cân bằng ở mức rất thấp — 10 gói, khoảng 14 KB đang bay. Chia cho 20 ms ra đúng khoảng 0,7 MB/s như đo được.

Dòng 0,1% cho thấy quá trình đó đang diễn ra: cwnd lớn nhất vẫn tới 6.046–7.466, nhưng lúc kết thúc chỉ còn 361–727. Cửa sổ leo lên được rồi bị đánh sập, nhiều lần, và trung bình theo thời gian thấp hơn nhiều so với đỉnh.

Đó cũng là lý do đo thông lượng bằng một lần truyền ngắn cho kết quả rất nhiễu: kết quả phụ thuộc vào việc gói bị mất rơi vào đầu hay cuối. Ở lần đo đầu tiên tôi truyền 8 MB và nhận được 8,1 rồi 37,1 rồi 26,0 MB/s cho cùng một điều kiện — dải bốn lần. Chỉ khi chuyển sang đo theo thời gian, các con số mới ổn định.

Nghĩa là gì trong thực tế

Băng thông không phải thứ bạn thiếu. Một đường 10 Gbps giữa hai châu lục với 1% mất gói cho khoảng vài chục Mbps. Mua thêm băng thông không đổi được gì; sửa mất gói mới đổi.

Kiểm tra mất gói trước khi tinh chỉnh bất cứ thứ gì:

ss -tin dst <dia-chi> | grep -oE 'retrans:[0-9/]*|rtt:[0-9.]*|cwnd:[0-9]*'
netstat -s | grep -iE 'retransmit|segments retransmited'

cwnd nhỏ (dưới vài trăm) trên một kết nối đang truyền nhiều dữ liệu là dấu hiệu rõ ràng nhất. Nó nói rằng vấn đề nằm ở đường truyền, không nằm ở ứng dụng.

Nguồn mất gói thường không phải cáp hỏng. Trong trung tâm dữ liệu, mất gói gần như luôn là hàng đợi tràn ở một cổng chuyển mạch hoặc ở chính card mạng:

ip -s link show eth0 | grep -A1 -E 'RX|TX'    # cot dropped, overrun
ethtool -S eth0 2>/dev/null | grep -iE 'drop|discard|error' | grep -v ': 0$'

Đổi thuật toán tắc nghẽn

Máy tôi đo chỉ có renocubic:

cat /proc/sys/net/ipv4/tcp_available_congestion_control
cat /proc/sys/net/ipv4/tcp_congestion_control    # cubic

BBR — có trong nhân từ 4.9, cần nạp mô-đun — dùng cách tiếp cận khác hẳn: nó ước lượng băng thông và vòng khứ hồi thay vì coi mọi mất gói là dấu hiệu tắc nghẽn. Trên đường truyền có mất gói ngẫu nhiên (không do tắc nghẽn), khác biệt rất lớn.

modprobe tcp_bbr
sysctl -w net.ipv4.tcp_congestion_control=bbr

Tôi không đo được BBR — mô-đun không có sẵn trong nhân của môi trường thử nghiệm. Nên tôi không đưa ra con số nào cho nó; chỉ ghi rằng đây là chỗ đáng thử khi bảng trên khớp với triệu chứng của bạn.

Giới hạn của phép đo này

tc netem bỏ gói ngẫu nhiên và độc lập. Mất gói thật thường đến theo cụm — hàng đợi tràn thì tràn liên tục vài mili giây — và TCP phản ứng với cụm khác với phản ứng với mất rải rác.

Độ trễ cũng là hằng số, không có biến thiên. Biến thiên độ trễ làm bộ hẹn giờ truyền lại kém chính xác và thêm một lớp xấu nữa.

Cả hai đều làm số liệu thật tệ hơn bảng trên, không tốt hơn.

Thử ba mươi giây

Xem kết nối đang truyền nhiều dữ liệu nhất của bạn có bị co cửa sổ không:

ss -tin state established 2>/dev/null | \
  paste - - 2>/dev/null | \
  grep -oE 'cwnd:[0-9]+|rtt:[0-9.]+|retrans:[0-9]+/[0-9]+|bytes_sent:[0-9]+' | \
  paste - - - - 2>/dev/null | head -10

echo "--- goi bi bo o card mang ---"
ip -s link show 2>/dev/null | grep -B1 -A2 'RX:' | grep -A1 'RX:' | tail -1

Một kết nối có cwnd dưới 100 mà đang gửi hàng megabyte là kết nối đang bị mất gói. Đừng chỉnh bộ đệm, đừng đổi thư viện — đi tìm chỗ gói bị rơi.

Phần sau: DNS — đo chi phí tra tên và chỗ nó âm thầm chậm.