Khi bộ đệm gửi và nhận nhỏ, lúc lưu lượng dồn thành burst, gói UDP nhận về sẽ bị bỏ, còn việc gửi qua TCP bị chặn vì bộ đệm hết chỗ.
Vì sao SO_SNDBUF và SO_RCVBUF để mặc định hoặc quá nhỏ → Dẫn đến Khi có burst hoặc khi thread nhận dừng một chút, bộ đệm nhận UDP bị tràn và gói bị bỏ; TCP phải chờ vì bộ đệm gửi hết chỗ → Trên màn hình Dịch chuyển tức thời (mất gói UDP) hoặc tua nhanh (TCP phải chờ)
Phụ trách chính Hạ tầng server (Đội hạ tầng) · Phối hợp Phát triển server (Đội phát triển game)
Việc cần làm (Đội phát triển game)
Đặt kích thước bộ đệm (SO_SNDBUF, SO_RCVBUF) trong code cho phù hợp với lưu lượng; lưu ý với TCP, tự đặt kích thước sẽ tắt cơ chế tự điều chỉnh kích thước của Linux; không đặt quá lớn vì dữ liệu cũ sẽ dồn trong bộ đệm và làm tăng độ trễ; không để thread nhận bị dừng.
Việc cần làm (Đội hạ tầng)
Điều chỉnh giới hạn của kernel (rmem_max, wmem_max; kích thước đặt trong code cũng không vượt được giá trị này) và giá trị mặc định (rmem_default), giám sát bộ đếm tràn bộ đệm (RcvbufErrors).
Con số tham khảo
Bộ đệm nhận UDP mặc định trên Linux khoảng 208 KB. Ngay cả gói nhỏ cũng chiếm bộ nhớ kernel nhiều hơn kích thước thật rất nhiều, nên chỉ vài chục đến vài trăm gói là đầy. Với server nhận 100.000 gói mỗi giây, thread nhận chỉ cần dừng vài ms là bộ đệm tràn.
Trên đồ thị
Thỉnh thoảng vọt lên bất chợt · Số lần tràn bộ đệm nhận UDP (UdpRcvbufErrors)
Chỗ cần xem
Mức tăng UdpRcvbufErrors trong nstat -az và skmem trong ss -uamn (rb là kích thước bộ đệm nhận, d là số gói bị bỏ vì không đưa được vào socket); với TCP, xem trong skmem của ss -tm bộ nhớ chờ gửi (w) đã chạm kích thước bộ đệm gửi (tb) chưa
Đúng nếu
UdpRcvbufErrors (hoặc d của socket) tăng vào lúc có burst hoặc thread nhận bị dừng, và rb ở gần giá trị mặc định (khoảng 208 KB). Với TCP, w dính sát tb và send bị chặn
Loại trừ nếu
bộ đếm không đổi mà vẫn mất gói → vấn đề ở tầng NIC (“Ring buffer không đủ”) hoặc trên đường mạng
Cách kiểm tra
Kiểm tra bằng công cụ hạ tầng (không cần code game)
Nguồn
socket(7) — Linux manual pageLinux man-pages Giá trị mặc định của SO_RCVBUF và SO_SNDBUF là rmem_default và wmem_default, giới hạn trên là rmem_max và wmem_max; kernel nhân đôi giá trị được đặt
include/net/sock.h (Linux v6.18)Linux kernel Bộ đệm socket mặc định được định nghĩa bằng dung lượng của 256 gói 256 byte tính cả overhead của sk_buff (SKB_TRUESIZE(256)×256); frame nhỏ cũng bị tính bằng sk_buff+MTU (khoảng 208 KB là giá trị tính trên x86-64)
IP SysctlLinux kernel tcp_rmem, tcp_wmem: tự đặt SO_RCVBUF hoặc SO_SNDBUF sẽ tắt cơ chế tự điều chỉnh kích thước của socket đó
net/ipv4/udp.c (Linux v6.12)Linux kernel Khi hàng đợi nhận UDP vượt kích thước bộ đệm socket, gói bị bỏ ngay và RcvbufErrors tăng
ss(8) — Linux manual pageiproute2 skmem của -m: rb là kích thước bộ đệm nhận, tb là kích thước bộ đệm gửi, w là bộ nhớ chờ gửi, d là số gói bị bỏ trước khi vào socket