한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

Sách trắng lag game › L8 Socket và giao thức

Thuật toán Nagle + delayed ACK Nagle + delayed ACK (TCP_NODELAY off)

ID nguyên nhân sk-nagle · Phụ trách chính Phát triển server (Đội phát triển game) · Phối hợp Phát triển client (Đội phát triển game)

Mở thẻ gốc có hình minh họa và thí nghiệm →

Thuật toán Nagle (gom gói nhỏ lại để gửi) và delayed ACK (gửi ACK muộn) tác động chồng lên nhau, nên mỗi lần tách một message ra ghi nhiều lần là bị trễ 40–200 ms.

Vì sao Tách message nhỏ ra ghi nhiều lần mà không bật TCP_NODELAY → Dẫn đến Bên gửi chờ ACK, còn bên nhận thì gửi ACK muộn → Trên màn hình Ping đường truyền thấp nhưng mọi thao tác lúc nào cũng ì ạch như nhau, gây trễ thao tác

Triệu chứng
Trễ thao tác
Yếu tố
Độ trễ
Ai gặp phải
Cả server, Chỉ mình tôi
Khi nào
Luôn luôn, Khi làm một thao tác nhất định
Phụ trách
Phụ trách chính Phát triển server (Đội phát triển game) · Phối hợp Phát triển client (Đội phát triển game)
Việc cần làm (Đội phát triển game)
Server: bật TCP_NODELAY, gom message trong một tick rồi ghi một lần; đừng trông vào cách tắt delayed ACK ở bên nhận (TCP_QUICKACK của Linux chỉ giữ được trong chốc lát, Windows thì phải sửa registry trên từng PC) vì game không kiểm soát chắc chắn được. Client: bật TCP_NODELAY, gom message trong một khung hình rồi ghi một lần.
Con số tham khảo
Delayed ACK trên Linux thường là 40 ms (tùy tình huống, tối đa 200 ms). Windows bản cũ là 200 ms, bản hiện nay là 40 ms (template mặc định của Windows Server 2019 là 40 ms). Delayed ACK do OS bên nhận quyết định, nên nếu server bật Nagle mà tách message ra gửi nhiều lần, mỗi message có thể bị trễ 40–200 ms tùy PC bên nhận.
Trên đồ thị
Luôn cao ngay từ đầu · Thời gian phản hồi thao tác (RTT trong game)
Chỗ cần xem
Khoảng cách giữa yêu cầu và phản hồi trong bản bắt gói (packet capture) phía server (tcpdump, Wireshark); code server và client có bật TCP_NODELAY hay không
Đúng nếu
ping đường truyền thấp nhưng giữa các gói nhỏ liên tục có khoảng trống quanh 40 ms (Windows bản cũ là 200 ms), và mỗi khoảng trống kết thúc ngay sau khi ACK của bên kia đến. Bật TCP_NODELAY thì khoảng trống biến mất
Loại trừ nếu
khoảng cách phản hồi gần bằng ping đường truyền. Server game tạo phản hồi chậm → phía xử lý của server (“Hàng đợi message bị dồn ứ”)
Cách kiểm tra
Kiểm tra bằng công cụ hạ tầng (không cần code game)

Nguồn

  1. RFC 9293: Transmission Control Protocol (TCP) IETF
    Nagle giữ lại dữ liệu nhỏ khi còn dữ liệu chưa nhận được ACK; phải tắt được theo từng kết nối; delayed ACK dưới 0,5 giây; vấn đề khi hai cơ chế tác động chồng lên nhau
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    Delayed ACK trên Linux tối thiểu TCP_DELACK_MIN (HZ/25 = 40 ms), tối đa TCP_DELACK_MAX (HZ/5 = 200 ms)
  3. TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft
    Timeout delayed ACK mặc định của Windows được đổi thành 40 ms (công bố năm 2017)
  4. TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft
    Template Server 2019: DelayedAckTimeout 40 ms, MaxSynRetransmissions 2, InitialRto 3000 ms
  5. Design issues - Sending small data segments over TCP with Winsock Microsoft
    TCP trên Windows bản cũ đặt timer delayed ACK 200 ms mỗi khi nhận dữ liệu, còn Nagle bật sẵn theo mặc định, nên gói nhỏ phải chờ ACK; khắc phục bằng TCP_NODELAY

Nguyên nhân nên xem cùng

Cùng tầng: L8 Socket và giao thức

Nguyên nhân ở tầng khác gây cùng triệu chứng (Trễ thao tác)

Xem thẻ gốc có hình minh họa và thí nghiệm