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

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

mapping ของ NAT/โหลดบาลานเซอร์หมดอายุกลางการเชื่อมต่อ NAT / load balancer mapping expired mid-connection

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

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

ถ้าอุปกรณ์กลางทางลบ mapping (รายการที่บันทึกว่าจะส่งต่อการเชื่อมต่อนี้ไปที่ไหน) ของการเชื่อมต่อที่ idle แพ็กเก็ตถัดไปที่ส่งจะไปไม่ถึง การเชื่อมต่อจะส่งซ้ำวนไปจนหลุด หรืออุปกรณ์ตอบกลับด้วยการปฏิเสธการเชื่อมต่อ (RST) แล้วหลุดทันที

ทำไม การเชื่อมต่อที่ไม่มีแพ็กเก็ตวิ่งอยู่พักหนึ่ง (AFK, อยู่ในล็อบบี้) → ผลคือ NAT ของเราเตอร์, CGNAT ของ ISP, ไฟร์วอลล์, โหลดบาลานเซอร์ หรือ security group บนคลาวด์ลบ mapping ที่ idle → บนหน้าจอ พอกลับมาขยับ การส่งซ้ำต่อเนื่องจนหลุด หรือหลุดทันที

อาการ
หลุด, ค้าง
ปัจจัย
แพ็กเก็ตหาย
ใครเจอ
เราคนเดียว, บางพื้นที่/บาง ISP
เกิดเมื่อไร
หลังอยู่เฉย ๆ สักพัก
ผู้รับผิดชอบ
ผู้รับผิดชอบหลัก พัฒนาไคลเอนต์ (ทีมพัฒนาเกม) · ร่วมกับ พัฒนาเซิร์ฟเวอร์ (ทีมพัฒนาเกม), อินฟราเครือข่าย (ทีมอินฟรา), อินฟราเซิร์ฟเวอร์ (ทีมอินฟรา)
งานฝั่งทีมพัฒนาเกม
ไคลเอนต์: ส่ง heartbeat โดยเว้นช่วงไม่เกินครึ่งหนึ่งของ idle timeout ที่สั้นที่สุด (mapping ในเราเตอร์ของผู้เล่นและ CGNAT ของ ISP จะต่ออายุแน่นอนก็ต่อเมื่อมีแพ็กเก็ตขาออกจากฝั่งใน และเราเปลี่ยน timeout เหล่านั้นไม่ได้ ไคลเอนต์จึงต้องเป็นฝ่ายส่ง), เชื่อมต่อใหม่อัตโนมัติเมื่อหลุด เซิร์ฟเวอร์: ตอบ heartbeat และถ้าไม่ได้รับนานเกินกำหนดให้ปิดการเชื่อมต่อเองก่อน (ลดช่วง TCP keepalive ด้วย socket option เช่น TCP_KEEPIDLE, ตรวจจับให้เร็วด้วย TCP_USER_TIMEOUT), ใช้ session token เพื่อต่อเซสชันเดิม
งานฝั่งทีมอินฟรา
เครือข่าย: รวบรวม idle timeout ของไฟร์วอลล์และโหลดบาลานเซอร์บนเส้นทางแล้วแชร์ให้ทีมพัฒนาเกม, เพิ่มค่าในไฟร์วอลล์และโหลดบาลานเซอร์ของเราถ้าจำเป็น เครื่องเซิร์ฟเวอร์/OS: ตรวจเวลา connection tracking ของ security group บนคลาวด์แล้วแชร์ให้ทีมพัฒนาเกม
ตัวเลขที่ควรรู้
เวลาที่คง TCP mapping ไว้ต่างกันไปตามอุปกรณ์ ตั้งแต่ไม่กี่นาทีถึงหลายชั่วโมง ถ้า security group บนคลาวด์ตั้งให้ติดตามการเชื่อมต่อ อินสแตนซ์ประเภท AWS Nitro v6 จะลบรายการที่ติดตามหลัง 350 วินาทีโดยค่าเริ่มต้น (ประเภทอื่น 5 วัน ดูรายการ “connection tracking ของ security group บนคลาวด์หมดอายุ”) ค่าเริ่มต้นของ TCP keepalive ใน Linux คือ “ตรวจเมื่อ idle ครบ 2 ชั่วโมง” จึงช้ากว่าอุปกรณ์ส่วนใหญ่
บนกราฟ
การเชื่อมต่อหลุดพร้อมกัน · จำนวนครั้งที่หลุด, ระยะเวลา idle ก่อนหลุด
จุดที่ต้องดู
packet capture ฝั่งเซิร์ฟเวอร์ช่วงไม่กี่นาทีสุดท้ายก่อนการเชื่อมต่อหลุด การเชื่อมต่อที่ยังอยู่ดูเวลา idle จาก lastsnd และ lastrcv (ms ที่ผ่านไปนับจากส่งและรับครั้งล่าสุด) ของ ss -ti และดู TcpExtTCPAbortOnTimeout (จำนวนการเชื่อมต่อที่ยกเลิกเพราะตัวจับเวลาหมด) ใน nstat ด้วย
สัญญาณว่าใช่
การเชื่อมต่อที่หลุดทุกรายการมีเวลา idle ก่อนหลุดเกินค่าใกล้เคียงกัน (idle timeout ของอุปกรณ์บนเส้นทาง เช่น 350 วินาทีของ security group บนอินสแตนซ์ AWS Nitro v6) และตั้งแต่แพ็กเก็ตแรกหลัง idle มีแต่การส่งซ้ำโดยไม่มี ACK จนยกเลิก หรือได้ RST กลับมาทันที
สัญญาณว่าไม่ใช่
หลุดระหว่างเล่นด้วยโดยไม่เกี่ยวกับเวลา idle: เป็นสาเหตุอื่น (“เส้นทางเปลี่ยน/เส้นทาง ECMP ที่เสีย”, “ไฟร์วอลล์/connection tracking ทิ้งแพ็กเก็ต”) ถ้าการเชื่อมต่อมี heartbeat วิ่งโดยเว้นช่วงไม่เกินครึ่งหนึ่งของ idle timeout ที่สั้นที่สุด ให้ตัดสาเหตุนี้ออก
วิธีตรวจ
ใช้เครื่องมือฝั่งอินฟรา (ไม่ต้องใช้โค้ดเกม)

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

  1. RFC 5382: NAT Behavioral Requirements for TCP IETF
    คำแนะนำว่า idle timeout ของการเชื่อมต่อใน TCP NAT ต้องไม่น้อยกว่า 2 ชั่วโมง 4 นาที (ตั้งอยู่บนสมมติฐานว่าอุปกรณ์อาจลบเซสชันที่ idle ไปก่อน)
  2. RFC 4787: Network Address Translation (NAT) Behavioral Requirements for Unicast UDP IETF
    NAT mapping ต้องต่ออายุด้วยแพ็กเก็ตขาออกจากฝั่งใน (REQ-6) ส่วนการต่ออายุด้วยแพ็กเก็ตขาเข้าจากฝั่งนอกเป็นทางเลือก (สำหรับ UDP)
  3. Amazon EC2 security group connection tracking AWS
    ค่าเริ่มต้นของ TCP idle tracking timeout คือ 350 วินาทีสำหรับอินสแตนซ์ประเภท Nitro v6 และ 432,000 วินาที (5 วัน) สำหรับประเภทอื่น แนะนำ keepalive ที่ถี่กว่า 5 นาที
  4. IP Sysctl Linux kernel
    tcp_keepalive_time ค่าเริ่มต้น 2 ชั่วโมง
  5. tcp(7) — Linux manual page Linux man-pages
    TCP_KEEPIDLE (เวลา idle ก่อนเริ่ม keepalive), TCP_USER_TIMEOUT (เวลาที่รอข้อมูลที่ยังไม่ได้รับการยืนยันก่อนปิดการเชื่อมต่อ)
  6. RFC 5482: TCP User Timeout Option IETF
    TCP user timeout: ข้อมูลที่ส่งไปยังไม่ได้รับการยืนยันนานเท่าไรจึงจะปิดการเชื่อมต่อ
  7. ss(8) — Linux manual page iproute2
    lastsnd และ lastrcv ใน ss -i: เวลาที่ผ่านไปนับจากส่งและรับครั้งล่าสุด (ms)
  8. SNMP counter Linux kernel
    TcpExtTCPAbortOnTimeout: จำนวนการเชื่อมต่อที่ยกเลิกไปโดยไม่ส่ง RST เพราะตัวจับเวลาของ TCP หมด

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

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

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

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