คู่มือเกมแลค › L8 ซ็อกเก็ตและโปรโตคอล
อัลกอริทึม Nagle + delayed ACK Nagle + delayed ACK (TCP_NODELAY off)
ID สาเหตุ sk-nagle · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
อัลกอริทึม Nagle ที่รวบรวมแพ็กเก็ตเล็กก่อนส่ง กับ delayed ACK ที่ส่ง ACK ช้า ทำงานประกบกัน ทุกครั้งที่เขียนข้อความแบ่งเป็นหลายส่วนจึงดีเลย์ 40–200 ms
ทำไม เขียนข้อความเล็ก ๆ แบ่งเป็นหลายส่วนโดยไม่ได้เปิด TCP_NODELAY → ผลคือ ฝั่งส่งรอ ACK ส่วนฝั่งรับส่ง ACK ช้า → บนหน้าจอ ปิงต่ำ แต่ทุกการกระทำตอบสนองช้าสม่ำเสมอ: อินพุตดีเลย์
อาการ อินพุตดีเลย์
ปัจจัย ความหน่วง
ใครเจอ ทั้งเซิร์ฟเวอร์, เราคนเดียว
เกิดเมื่อไร ตลอดเวลา, ตอนทำแอ็กชันบางอย่าง
ผู้รับผิดชอบ ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
งานฝั่งทีมพัฒนาเกม เซิร์ฟเวอร์: เปิด TCP_NODELAY, รวบรวมข้อความในหนึ่งทิกแล้วเขียนครั้งเดียว, อย่าพึ่งวิธีปิด delayed ACK ฝั่งรับ (TCP_QUICKACK ของ Linux มีผลแค่ชั่วครู่ ส่วน Windows ต้องแก้ registry ทีละเครื่อง) เพราะเกมควบคุมได้ไม่แน่นอน ไคลเอนต์: เปิด TCP_NODELAY, รวบรวมข้อความในหนึ่งเฟรมแล้วเขียนครั้งเดียว
ตัวเลขที่ควรรู้ delayed ACK ของ Linux ปกติอยู่ที่ 40 ms (สูงสุด 200 ms แล้วแต่สถานการณ์) Windows รุ่นเก่าใช้ 200 ms ส่วนรุ่นปัจจุบันใช้ 40 ms (เทมเพลตเริ่มต้นของ Windows Server 2019 คือ 40 ms) OS ฝั่งรับเป็นผู้กำหนด delayed ACK ถ้าเซิร์ฟเวอร์เปิด Nagle ไว้แล้วส่งข้อความแบ่งเป็นหลายส่วน ก็อาจดีเลย์ครั้งละ 40–200 ms แล้วแต่ PC ที่รับ
บนกราฟ สูงตลอดตั้งแต่แรก · เวลาตอบสนองของแอ็กชัน (RTT ในเกม)
จุดที่ต้องดู ช่วงห่างระหว่างคำขอกับการตอบกลับใน packet capture ฝั่งเซิร์ฟเวอร์ (tcpdump, Wireshark) และตรวจว่าโค้ดเซิร์ฟเวอร์และไคลเอนต์เปิด TCP_NODELAY หรือไม่ สัญญาณว่าใช่ ปิงต่ำ แต่มีช่วงว่างราว 40 ms (Windows รุ่นเก่า 200 ms) ระหว่างแพ็กเก็ตเล็กซ้ำ ๆ และช่วงว่างนั้นจบทันทีที่ ACK จากอีกฝั่งมาถึง เปิด TCP_NODELAY แล้วหายไป สัญญาณว่าไม่ใช่ ช่วงห่างการตอบกลับใกล้เคียงปิง: ไม่ใช่สาเหตุนี้ ถ้าเซิร์ฟเวอร์เกมสร้างการตอบกลับช้า น่าจะเป็นฝั่งการประมวลผลของเซิร์ฟเวอร์ (“ข้อความสะสมในคิว”) วิธีตรวจ ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
แหล่งอ้างอิง RFC 9293: Transmission Control Protocol (TCP) IETF Nagle จะเก็บข้อมูลเล็ก ๆ ไว้ก่อนเมื่อมีข้อมูลที่ยังไม่ได้รับ ACK, ต้องปิดได้เป็นรายการเชื่อมต่อ, delayed ACK น้อยกว่า 0.5 วินาที, ปัญหาเมื่อทั้งสองทำงานประกบกัน include/net/tcp.h (Linux v6.12) Linux kernel delayed ACK ของ Linux ต่ำสุด TCP_DELACK_MIN (HZ/25 = 40 ms), สูงสุด TCP_DELACK_MAX (HZ/5 = 200 ms) TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft เปลี่ยนไทม์เอาต์ delayed ACK เริ่มต้นของ Windows เป็น 40 ms (ประกาศปี 2017) TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft เทมเพลต Server 2019: DelayedAckTimeout 40 ms, MaxSynRetransmissions 2, InitialRto 3000 ms Design issues - Sending small data segments over TCP with Winsock Microsoft TCP ของ Windows รุ่นเก่าตั้งตัวจับเวลา delayed ACK 200 ms เมื่อได้รับข้อมูล และ Nagle เปิดเป็นค่าเริ่มต้น แพ็กเก็ตเล็กจึงต้องรอ ACK, แก้ด้วย TCP_NODELAY
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: L8 ซ็อกเก็ตและโปรโตคอล
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (อินพุตดีเลย์)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง