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

คู่มือเกมแลค › ต้นเหตุของการส่งซ้ำใน TCP

thin stream กู้คืนช้า Thin streams fall back to RTO

ID สาเหตุ rt-thin · ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)

เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →

ถ้าส่งแพ็กเก็ตเล็ก ๆ ห่าง ๆ แบบเกม RTO จะมาถึงก่อนที่ “แพ็กเก็ตที่ตามมา 3 ตัว” จะครบ เมื่อหายเท่ากัน จึงหยุดนานกว่าการส่งข้อมูลปริมาณมากอยู่มาก

ทำไม แพ็กเก็ตห่างกันราว 100 ms แพ็กเก็ตที่ยังไม่ได้รับ ACK (in-flight) จึงมีอยู่ไม่กี่ตัว → ผลคือ กว่า duplicate ACK จะครบ 3 ตัวต้องใช้เวลาเกิน 300 ms จึงเป็น RTO (ปิง + 200 ms) ที่ทำงานก่อน ถ้าหายต่อเนื่องก็เพิ่มเป็นสองเท่าทุกครั้ง → บนหน้าจอ แพ็กเก็ตหายครั้งเดียวค้างราว 0.3 วินาที ถ้าตัวที่ส่งซ้ำหายอีก จะค้างเกือบ 1 วินาทีแล้วตามด้วยอาการกรอเร็ว

อาการ
ค้าง, กรอเร็ว
ปัจจัย
แพ็กเก็ตหาย, การหยุดชะงัก
ใครเจอ
เราคนเดียว, ทั้งเซิร์ฟเวอร์
เกิดเมื่อไร
สุ่มเป็นครั้งคราว
ผู้รับผิดชอบ
ผู้รับผิดชอบหลัก พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาไคลเอนต์ (ทีมพัฒนาเกม)
งานฝั่งทีมพัฒนาเกม
เซิร์ฟเวอร์: เปิด TCP_NODELAY (ถ้าเปิด Nagle ไว้ จะไม่มีแพ็กเก็ตที่ตามมาให้ RACK ใช้ตัดสิน), ส่งแพ็กเก็ตเรียลไทม์ด้วยการส่งซ้ำที่ทำเองบน UDP ไคลเอนต์: เปิด TCP_NODELAY, ส่งแพ็กเก็ตเรียลไทม์แบบเดียวกับเซิร์ฟเวอร์ (UDP)
งานฝั่งทีมอินฟรา
ใช้ RACK-TLP (ค่าเริ่มต้นของ Linux รุ่นใหม่), ใช้ tcp_thin_linear_timeouts เพื่อไม่ให้ RTO ที่เกิดต่อเนื่องเพิ่มเป็นสองเท่า
ตัวเลขที่ควรรู้
ถ้าแพ็กเก็ตห่างกัน 100 ms และปิง 60 ms กว่าจะถึง fast retransmit ใช้เวลาราว 360 ms (จนแพ็กเก็ตที่ตามมา 3 ตัวมาถึงและการยืนยันกลับมา) ส่วน RTO ประมาณ 260 ms ถ้าใช้ RACK จะส่งซ้ำทันทีที่การยืนยันของแพ็กเก็ตถัดไปกลับมา ที่ราว 160 ms ถ้าแพ็กเก็ตห่างกันเกิน 200 ms RACK ก็ไม่เร็วกว่า RTO
บนกราฟ
ขาดช่วงแล้วมารวดเดียว · ปริมาณที่รับต่อการเชื่อมต่อ, จำนวนครั้งที่ RTO หมดเวลา
จุดที่ต้องดู
เทียบค่าที่เพิ่มขึ้นของ TcpExtTCPTimeouts (RTO หมดเวลา), TcpExtTCPFastRetrans (fast retransmit), TcpExtTCPLossProbes และ TcpExtTCPLossProbeRecovery (TLP) ใน nstat และดู rto กับ backoff ของการเชื่อมต่อเกมด้วย ss -ti ตรวจค่า net.ipv4.tcp_recovery, tcp_early_retrans และ tcp_sack ของเซิร์ฟเวอร์ด้วย
สัญญาณว่าใช่
ในบรรดาการส่งซ้ำ RTO หมดเวลามากกว่า fast retransmit และเห็นการเชื่อมต่อเกมที่ backoff มากกว่า 0 (กำลังเจอ RTO) บ่อย ระหว่างที่หยุด ปริมาณที่รับเป็น 0 พอกู้คืนได้ข้อมูลก็ทะลักมาพร้อมกัน
สัญญาณว่าไม่ใช่
การส่งข้อมูลปริมาณมากบนเซิร์ฟเวอร์เดียวกันก็หยุดนานพอกัน: เป็นปัญหาแพ็กเก็ตหายที่ไม่เกี่ยวกับรูปแบบการเชื่อมต่อ ถ้ากระจุกที่การเชื่อมต่อที่ไม่มี SACK หรือ timestamps น่าจะเป็น “อุปกรณ์กลางทางตัด TCP option ทิ้ง”
วิธีตรวจ
ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
รายละเอียดเพิ่มเติม
เดิม Linux เคยมีตัวเลือกส่งซ้ำเมื่อได้ duplicate ACK เพียง 1 ตัวสำหรับ thin stream (tcp_thin_dupack) แต่ถูกถอดออกในปี 2017 ปัจจุบัน RACK ทำหน้าที่นั้นแทน ถ้าเปิด Nagle อยู่ (ปิด TCP_NODELAY) ระหว่างรอการยืนยันของแพ็กเก็ตที่หาย TCP จะไม่ส่งแพ็กเก็ตใหม่ด้วย RACK จึงไม่มีแพ็กเก็ตที่ตามมาให้ใช้ตัดสิน และต้องรอจนถึง RTO

แหล่งอ้างอิง

  1. Thin-streams and TCP Linux kernel
    thin stream ที่ส่งห่าง ๆ แบบเกม fast retransmit ทำงานได้ไม่ดี จึงต้องพึ่ง timeout ที่ยาว เกณฑ์คือแพ็กเก็ตที่ยังไม่ได้รับ ACK (in-flight) น้อยกว่า 4 ตัว
  2. RFC 5681: TCP Congestion Control IETF
    ทำ fast retransmit เมื่อได้รับ duplicate ACK ตัวที่สาม
  3. RFC 8985: The RACK-TLP Loss Detection Algorithm for TCP IETF
    RACK ตัดสินการหายจากการที่แพ็กเก็ตซึ่งส่งทีหลังส่งถึงแล้ว เวลารอของ TLP คือ 2·SRTT (ถ้ามีแพ็กเก็ตที่ยังไม่ได้รับการยืนยันเพียงตัวเดียว จะบวกเวลาเผื่อ delayed ACK)
  4. include/net/tcp.h Linux kernel
    TCP_RTO_MIN 200 ms, เกณฑ์ thin stream (แพ็กเก็ต in-flight น้อยกว่า 4 ตัว) และการลองใหม่แบบ linear 6 ครั้ง
  5. tcp: remove thin_dupack feature Linux kernel
    ลบ thin_dupack ในเดือนมกราคม 2017 (Linux 4.11) พร้อมคำอธิบายว่า RACK ทำหน้าที่นั้นแทน
  6. IP Sysctl Linux kernel
    tcp_thin_linear_timeouts: ถ้าเป็น thin stream RTO จะไม่เพิ่มเป็นสองเท่าในช่วงสูงสุด 6 ครั้งแรก (ปิดเป็นค่าเริ่มต้น)
  7. tcp(7) — Linux manual page Linux man-pages
    TCP_NODELAY ปิดอัลกอริทึม Nagle
  8. net/ipv4/proc.c Linux kernel
    ชื่อตัวนับที่ nstat แสดง: TCPTimeouts, TCPFastRetrans, TCPLossProbes, TCPLossProbeRecovery
  9. net/ipv4/tcp_timer.c Linux kernel
    TCPTimeouts เพิ่มขึ้นเมื่อตัวจับเวลาส่งซ้ำ (RTO) หมดเวลา
  10. SNMP counter Linux kernel
    TcpExtTCPFastRetrans (การส่งซ้ำขณะที่ไม่ได้อยู่ในสถานะ Loss), TcpExtTCPLossProbes (ส่ง TLP) และ TcpExtTCPLossProbeRecovery (กู้คืนการหายด้วย TLP)
  11. ss(8) — Linux manual page iproute2
    rto (ms) และ backoff (จำนวนครั้งที่ RTO เพิ่มเป็นสองเท่า) ใน ss -i

สาเหตุที่ควรดูประกอบ

ชั้นเดียวกัน: ต้นเหตุของการส่งซ้ำใน TCP

สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (ค้าง)

ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง