คู่มือเกมแลค › ต้นเหตุของการส่งซ้ำใน TCP
MTU black hole (เฉพาะแพ็กเก็ตใหญ่ที่หายซ้ำแล้วซ้ำอีก) PMTU black hole
ID สาเหตุ rt-mtu · ผู้รับผิดชอบหลัก อินฟราเครือข่าย (ทีมอินฟรา) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม)
เปิดการ์ดในฉบับหลักที่มีภาพและการทดลอง →
เมื่อขนาดที่ช่วงกลางทางรับได้เล็กลง แต่ข้อความแจ้งว่า “ใหญ่เกินไป” (ICMP) ถูกบล็อก แพ็กเก็ตใหญ่จะหายไปทุกครั้งไม่ว่าจะส่งซ้ำกี่รอบ
ทำไม ขนาดสูงสุดลดลงในช่วงที่ผ่าน VPN หรืออุโมงค์ (tunnel) และข้อความแจ้งว่าเกินขนาดถูกไฟร์วอลล์บล็อก → ผลคือ ฝั่งส่งไม่รู้สาเหตุ จึงส่งแพ็กเก็ตใหญ่ตัวเดิมซ้ำไปเรื่อย ๆ และ RTO เพิ่มเป็นสองเท่าทุกครั้ง → บนหน้าจอ ปกติไม่มีอาการ แต่ในจังหวะที่มีข้อมูลใหญ่วิ่ง เช่น เปิดกระเป๋า, ไปที่ที่คนเยอะ หรือโหลดตอนเข้าแมพ แพ็กเก็ตเล็กที่ตามมาก็หยุดไปหมด สุดท้ายหลุดหรือโหลดไม่จบ
- อาการ
- ค้าง, หลุด, เข้าเกมไม่ได้/โหลดไม่จบ
- ปัจจัย
- แพ็กเก็ตหาย
- ใครเจอ
- บางพื้นที่/บาง ISP, เราคนเดียว
- เกิดเมื่อไร
- ตอนทำแอ็กชันบางอย่าง, หลังล็อกอิน/หลังปิดปรับปรุง
- ผู้รับผิดชอบ
- ผู้รับผิดชอบหลัก อินฟราเครือข่าย (ทีมอินฟรา) · ร่วมกับ อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา), พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม)
- งานฝั่งทีมพัฒนาเกม
- ถ้าจะลดขนาดจากฝั่งเซิร์ฟเวอร์เอง ให้ตั้งขนาด segment สูงสุดของซ็อกเก็ต (TCP_MAXSEG), แค่ซอยข้อความให้เล็กในโค้ดเกมไม่ช่วยป้องกัน (TCP จะรวมข้อมูลที่จะส่งเป็นก้อนขนาด MSS ใหม่)
- งานฝั่งทีมอินฟรา
- เครือข่าย: ปรับ MSS ที่อุปกรณ์ขอบเครือข่าย (clamping), อนุญาต ICMP แจ้งเกินขนาด (type 3 code 4, fragmentation needed) ที่ไฟร์วอลล์และ network ACL ของคลาวด์ เครื่องเซิร์ฟเวอร์/OS: ตั้งค่า path MTU, ตรวจว่าไฟร์วอลล์ของเซิร์ฟเวอร์และ security group ของคลาวด์ไม่บล็อก ICMP แจ้งเกินขนาด, ใช้ tcp_mtu_probing=1 ของ Linux เป็นตาข่ายรองรับชั้นสุดท้าย
- ตัวเลขที่ควรรู้
- ปกติ 1,500 ไบต์ ถ้าผ่านอุโมงค์จะเหลือราว 1,400 ถ้าแพ็กเก็ตเดิมถูกส่งซ้ำ 5–6 ครั้ง จะหยุดชะงักนานเกิน 10 วินาที
- บนกราฟ
- สูงเฉพาะบางกลุ่ม · RTO และ backoff ต่อการเชื่อมต่อ, จำนวนการหลุดแยกตามพื้นที่/ISP
- จุดที่ต้องดู
- การส่งซ้ำของการเชื่อมต่อที่มีปัญหาจาก packet capture ฝั่งเซิร์ฟเวอร์หรือ bcc tcpretrans -s (แสดง sequence number) และ mss, pmtu, backoff ของการเชื่อมต่อนั้นจาก ss -ti จากเซิร์ฟเวอร์ส่ง ping เล็กกับ ping 1,500 ไบต์ที่เปิด DF (ping -M do -s 1472) ไปยังที่อยู่ของผู้เล่นคนนั้นแล้วเทียบกัน
- สัญญาณว่าใช่
- แพ็กเก็ตที่เต็มขนาด MSS ถูกส่งซ้ำด้วย sequence number เดิมไปเรื่อย ๆ โดยช่วงห่างเพิ่มเป็นสองเท่าทุกครั้ง ส่วนแพ็กเก็ตที่เล็กกว่าผ่านได้ ไม่มี ICMP แจ้งเกินขนาด (ตัวกรอง Wireshark icmp.type == 3 and icmp.code == 4) เข้ามา ping เล็กได้คำตอบ แต่ ping ใหญ่ที่เปิด DF หายเงียบ
- สัญญาณว่าไม่ใช่
- แพ็กเก็ตเล็กก็หายด้วย: เป็นการหายที่ไม่เกี่ยวกับขนาด (“คิวคอขวดล้น”, “เส้นทางเปลี่ยน/เส้นทาง ECMP ที่เสีย”) ถ้า ICMP แจ้งเกินขนาดมาถึงและ pmtu ใน ss -ti ลดลง แปลว่า path MTU discovery ทำงานปกติ
- วิธีตรวจ
- ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)
- รายละเอียดเพิ่มเติม
- tcp_mtu_probing=1 จะตัดสินว่าเป็น black hole แล้วลด MSS เหลือ 1,024 ไบต์ ก็ต่อเมื่อ RTO หมดเวลาต่อเนื่องไปหลายวินาที (เท่ากับ tcp_retries1=3) ระหว่างนั้นจะหยุดชะงัก จึงควรเก็บไว้เป็นตาข่ายรองรับชั้นสุดท้าย และทำ MSS clamping ที่ป้องกันไว้ล่วงหน้าเป็นอันดับแรก
แหล่งอ้างอิง
- RFC 1191: Path MTU discovery IETF
path MTU discovery: แพ็กเก็ตที่ใหญ่เกินจะได้รับแจ้งด้วย ICMP “fragmentation needed and DF set” (type 3 code 4) - RFC 2923: TCP Problems with Path MTU Discovery IETF
ปัญหา PMTU black hole ที่ ICMP ถูกบล็อกจนแพ็กเก็ตใหญ่หายไปเรื่อย ๆ - RFC 4821: Packetization Layer Path MTU Discovery IETF
วิธีที่ชั้น transport ค้นหาขนาดแพ็กเก็ตเองโดยไม่ใช้ ICMP (พื้นฐานของ tcp_mtu_probing ใน Linux) - IP Sysctl Linux kernel
tcp_mtu_probing: 0 ปิด, 1 เฉพาะเมื่อตรวจพบ black hole, 2 ตลอดเวลา (MSS เริ่มต้นคือ tcp_base_mss) tcp_retries1 ค่าเริ่มต้น 3 - net/ipv4/tcp_timer.c Linux kernel
เมื่อการส่งซ้ำจาก RTO ต่อเนื่องครบ tcp_retries1 ครั้ง จะถือว่าตรวจพบ black hole แล้วเปิด MTU probing เพื่อลด MSS - include/net/tcp.h Linux kernel
TCP_BASE_MSS = 1,024 ไบต์ - RFC 6298: Computing TCP's Retransmission Timer IETF
เพิ่ม RTO เป็นสองเท่าทุกครั้งที่ตัวจับเวลาส่งซ้ำหมดเวลา - iptables-extensions(8) — Linux manual page netfilter
TCPMSS --clamp-mss-to-pmtu: เลี่ยงปัญหาแพ็กเก็ตใหญ่ไปไม่ถึงเพราะช่วงที่บล็อก ICMP ด้วยการปรับ MSS ใน SYN - tcp(7) — Linux manual page Linux man-pages
TCP_MAXSEG: ขนาด segment สูงสุดของแพ็กเก็ตขาออก ถ้าตั้งก่อนเชื่อมต่อ MSS ที่แจ้งให้อีกฝั่งทราบก็จะเปลี่ยนด้วย - Network maximum transmission unit (MTU) for your EC2 instance AWS
internet gateway และ VPN ใช้ MTU 1,500, PMTUD ต้องใช้ ICMP type 3 code 4 และถ้า security group หรือ network ACL บล็อกไว้จะรับไม่ได้ - MTU considerations | Cloud VPN Google Cloud
MTU ของ Cloud VPN gateway คือ 1,460 ไบต์, payload MTU ของอุโมงค์ IPv4 คือ 1,406 ไบต์ (ผ่านอุโมงค์แล้วเหลือราว 1,400) - Demonstrations of tcpretrans, the Linux eBPF/bcc version IO Visor
แสดงหนึ่งบรรทัดต่อการส่งซ้ำแต่ละครั้ง และ -s แสดง sequence number ของแพ็กเก็ตที่ส่งซ้ำด้วย - ss(8) — Linux manual page iproute2
mss, pmtu (path MTU) และ backoff (จำนวนครั้งที่ RTO เพิ่มเป็นสองเท่า) ใน ss -i - ping(8) — Linux manual page iputils
-M do เปิด DF และไม่ส่งแพ็กเก็ตที่ใหญ่กว่า path MTU ที่เคอร์เนลรู้, -s คือขนาดข้อมูล (ไม่รวม ICMP header 8 ไบต์) - Display Filter Reference: Internet Control Message Protocol Wireshark
display filter icmp.type และ icmp.code
สาเหตุที่ควรดูประกอบ
ชั้นเดียวกัน: ต้นเหตุของการส่งซ้ำใน TCP
สาเหตุจากชั้นอื่นที่ทำให้เกิดอาการเดียวกัน (ค้าง)
ดูการ์ดในฉบับหลักที่มีภาพและการทดลอง