คู่มือเกมแลค › ต้นเหตุของการส่งซ้ำใน TCP
การส่งซ้ำโดยไม่จำเป็นเพราะความหน่วงพุ่ง Spurious RTO from delay spikes
ID สาเหตุ rt-spurious-delay · ผู้รับผิดชอบหลัก ภายนอก (ภายนอก) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
แพ็กเก็ตยังอยู่ครบและแค่มาถึงช้ามากชั่วครู่ แต่ถ้าความหน่วงนั้นนานกว่า RTO ฝั่งส่งจะตัดสินว่าหายแล้วส่งซ้ำ
ทำไม bufferbloat, โหมดประหยัดพลังงานของ Wi-Fi, การเปลี่ยนสถานะวิทยุของมือถือ หรือ VM ถูกพักการทำงาน ทำให้ความหน่วงพุ่งชั่วขณะหลายร้อย ms → ผลคือ RTO หมดเวลาก่อนจึงส่งซ้ำ แล้วแพ็กเก็ตต้นฉบับก็มาถึงตามมา (ฝั่งรับได้รับซ้ำ) → บนหน้าจอ อาการค้างและกรอเร็วมาจากความหน่วงพุ่งเอง การส่งซ้ำโดยไม่จำเป็นแทบไม่ทำให้ค้างนานขึ้น แค่ดันเมตริกการส่งซ้ำให้สูงจนถูกเข้าใจผิดว่าแพ็กเก็ตหาย
- อาการ
- ค้าง, กรอเร็ว, อินพุตดีเลย์
- ปัจจัย
- ความหน่วง, จิตเตอร์
- ใครเจอ
- เราคนเดียว, ทั้งเซิร์ฟเวอร์
- เกิดเมื่อไร
- สุ่มเป็นครั้งคราว, หลังอยู่เฉย ๆ สักพัก
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก ภายนอก (ภายนอก) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
- งานฝั่งทีมพัฒนาเกม
- ไคลเอนต์ Android 10 ขึ้นไปให้ขอโหมด Wi-Fi ความหน่วงต่ำระหว่างเล่น (Wi-Fi lock แบบ WIFI_MODE_FULL_LOW_LATENCY มีผลเฉพาะเมื่อจอเปิดอยู่และเกมอยู่เบื้องหน้า) เพื่อลดความหน่วงพุ่งจากโหมดประหยัดพลังงาน
- งานฝั่งทีมอินฟรา
- หลีกเลี่ยงอินสแตนซ์แบบ burstable, อย่าลดค่าต่ำสุดของ RTO ต่ำเกินไป, คง F-RTO และ timestamps ไว้ (tcp_frto, tcp_timestamps), ดูเมตริกการส่งซ้ำคู่กับ TCPSpuriousRTOs และ TCPDSACKRecv ของ nstat เพื่อไม่ให้เข้าใจผิดว่าแพ็กเก็ตหาย
- งานฝั่งภายนอก
- แนะนำให้ผู้เล่นใช้ SQM บนเราเตอร์และปิดโหมดประหยัดพลังงานของ Wi-Fi เพื่อลดความหน่วงพุ่งที่ต้นเหตุ
- ตัวเลขที่ควรรู้
- Linux ตรวจจับ RTO ที่ไม่จำเป็นด้วย F-RTO และบางครั้งก็ย้อนการลดอัตราการส่งกลับคืน ตรวจได้จาก TCPSpuriousRTOs (จำนวนครั้งที่ตัดสินว่าเป็น RTO ที่ไม่จำเป็น) และ TCPDSACKRecv (จำนวนครั้งที่ฝั่งรับแจ้งว่า “ได้รับไปแล้ว”) ใน nstat
- บนกราฟ
- พุ่งแบบสุ่มเป็นครั้งคราว · RTT (ปิง), จำนวน RTO ที่ไม่จำเป็น
- จุดที่ต้องดู
- ค่าที่เพิ่มขึ้นของ TcpExtTCPTimeouts (RTO หมดเวลา), TcpExtTCPSpuriousRTOs, TcpExtTCPDSACKRecv และ TcpExtTCPLostRetransmit จากการรัน nstat ทุก 1 นาที ดูไปพร้อมกัน ถ้ามี packet capture ใช้ตัวกรอง Wireshark tcp.analysis.spurious_retransmission
- สัญญาณว่าใช่
- เมื่อ RTO เพิ่ม TcpExtTCPSpuriousRTOs หรือ TcpExtTCPDSACKRecv ก็เพิ่มตาม และในเวลาเดียวกัน RTT พุ่งเป็นหลายร้อย ms ใน capture ฝั่งรับมีทั้งแพ็กเก็ตต้นฉบับและแพ็กเก็ตที่ส่งซ้ำมาถึง
- สัญญาณว่าไม่ใช่
- TcpExtTCPSpuriousRTOs และ DSACK ไม่ขยับ แต่ TcpExtTCPLostRetransmit (แพ็กเก็ตที่ส่งซ้ำก็หายอีก) เพิ่มขึ้น: เป็นแพ็กเก็ตหายจริง ถ้า RTT ไม่พุ่งแต่ DSACK สูงอยู่ตลอด น่าจะเป็น “fast retransmit โดยไม่จำเป็นเพราะแพ็กเก็ตสลับลำดับ”
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
แหล่งอ้างอิง
- RFC 5682: Forward RTO-Recovery (F-RTO): An Algorithm for Detecting Spurious Retransmission Timeouts with TCP IETF
F-RTO: ใช้ ACK ที่มาหลัง RTO แยกแยะว่าเป็น RTO ที่ไม่จำเป็นหรือไม่ - RFC 3481: TCP over Second (2.5G) and Third (3G) Generation Wireless Networks IETF
ความหน่วงพุ่งในเครือข่ายมือถือ (เช่น handover และการกู้คืนลิงก์) ทำให้เกิด TCP timeout และการส่งซ้ำที่ไม่จำเป็น รวมถึงการลด congestion window - RFC 2883: An Extension to the Selective Acknowledgement (SACK) Option for TCP IETF
DSACK: ฝั่งรับแจ้งว่าได้รับซ้ำ ฝั่งส่งจึงรู้ว่ามีการส่งซ้ำโดยไม่จำเป็น - SNMP counter Linux kernel
TcpExtTCPSpuriousRTOs (RTO ที่ไม่จำเป็นซึ่ง F-RTO ตรวจพบ), TcpExtTCPDSACKRecv (จำนวน DSACK ที่ได้รับ), TcpExtTCPLostRetransmit (จำนวนครั้งที่ SACK แจ้งว่าแพ็กเก็ตที่ส่งซ้ำหายอีก) - IP Sysctl Linux kernel
tcp_frto เปิดเป็นค่าเริ่มต้น (เป็นผลดีกับเครือข่ายไร้สายที่ RTT แกว่ง), tcp_timestamps ค่าเริ่มต้น 1 - RFC 6298: Computing TCP's Retransmission Timer IETF
หลักฐานว่าต้องใช้ค่าต่ำสุดของ RTO ที่สูงพอเพื่อกันการส่งซ้ำโดยไม่จำเป็น (แนะนำอย่างน้อย 1 วินาที) - WifiManager Android (Google)
WIFI_MODE_FULL_LOW_LATENCY (API 29, Android 10): Wi-Fi lock แบบความหน่วงต่ำที่มีผลเฉพาะเมื่อเชื่อมต่อ AP อยู่ จอเปิดอยู่ และแอปอยู่เบื้องหน้า - net/ipv4/proc.c Linux kernel
ชื่อตัวนับที่ nstat แสดง: TCPTimeouts, TCPSpuriousRTOs, TCPDSACKRecv, TCPLostRetransmit - net/ipv4/tcp_timer.c Linux kernel
TCPTimeouts เพิ่มขึ้นเมื่อตัวจับเวลาส่งซ้ำ (RTO) หมดเวลา - nstat(8) — Linux manual page iproute2
โดยค่าเริ่มต้น nstat แสดงค่าที่เพิ่มขึ้นนับจากการรันครั้งก่อน - Display Filter Reference: Transmission Control Protocol Wireshark
display filter tcp.analysis.spurious_retransmission
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: ต้นเหตุของการส่งซ้ำใน TCP
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (ค้าง)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง