กือบปีที่แล้ว เราเพิ่มฟีเจอร์ตาม RFC ทุกประการ — แล้วมันก็ล่มกลางโปรดักชัน เรา rollback, ขุดหาสาเหตุ แล้วก็เจอ สปอยล์: ไม่ใช่ DNS ผิด แต่เราลืมไปว่า port เป็นทรัพยากรที่มีจำกัด*
ต้องการพร็อกซีมือถือส่วนตัวและเร็วหรือไม่?สร้างพร็อกซีมือถือได้ทันที!
เราเพิ่ม SOCKS5 UDP ASSOCIATE (RFC 1928) เต็มรูปแบบเข้าไปใน proxy server ของ iProxy.online. ผ่านไปไม่กี่วัน DNS resolve ไม่ได้ tunnel หลุด บริการต่าง ๆ timeout แบบสุ่ม เรา rollback แล้วเริ่มไล่หาสาเหตุ ต้นตอคือ ephemeral port exhaustion บน Linux — UDP association แต่ละตัวยึด port ไว้คนละพอร์ต จนพอร์ตทั้งระบบหมดเกลี้ยง แก้ได้ด้วยการปรับแค่สอง config แต่กว่าจะหาเจอปัญหาใช้เวลานานกว่ามาก
SOCKS5 ตามมาตรฐาน RFC 1928 รองรับสาม command: CONNECT (tunnel TCP), BIND (รับ TCP ขาเข้า) และ UDP ASSOCIATE (relay UDP datagram) ผู้ให้บริการ proxy ส่วนใหญ่ทำแค่ CONNECT อย่างเดียว UDP ASSOCIATE ยากกว่า — แต่จำเป็นสำหรับ real-time อย่าง VoIP, เกมออนไลน์, DNS-over-UDP และ QUIC
หลักการทำงาน:
Client เปิด TCP control connection ไปยัง SOCKS5 server
Client ส่ง UDP ASSOCIATE request ผ่าน TCP connection นี้
Server จอง UDP socket เฉพาะ บน ephemeral port แล้วตอบกลับด้วย address กับ port number
Client ส่ง UDP datagram ไปที่ relay port นั้น server forward ไปยังปลายทางแล้ว relay response กลับมา
Association คงอยู่ จนกว่า TCP control connection จะปิด หรือ session timeout
UDP association ทุกตัวยึด ephemeral port แยกกันคนละพอร์ต นี่คือจุดสำคัญ
แล้วกับดักอยู่ตรงนี้ UDP เป็น connectionless ไม่มี FIN ไม่มี RST จะรู้ได้ยังไงว่า client ใช้งานเสร็จแล้วเพื่อจะปล่อย port คืน?
รอ TCP control connection ปิด — สัญญาณตาม RFC แต่ client อาจเปิดค้างไว้ได้ไม่จำกัด
Idle timeout ถ้าไม่มี datagram เข้ามาภายใน X วินาที ก็ตัดทิ้ง แต่ถ้า timeout สูงเกินไป socket จะกองพะเนินเทินทึก
เราตั้ง timeout แบบใจกว้าง แถมไม่ได้จำกัดจำนวน association ต่อ client เลย ผลก็คือ socket กองเต็ม
ที่ iProxy.online เราให้บริการโครงสร้าง mobile proxy ใน 100+ ประเทศ ผ่านผู้ให้บริการมือถือกว่า 600 ราย โดยเปลี่ยนมือถือ Android จริง ๆ ให้กลายเป็น proxy server ถ้าสนใจแนวคิดนี้ คู่มือ สร้างเครือข่าย proxy 4G ของเราอธิบายสถาปัตยกรรมแบบละเอียด Backend SOCKS5 server ของเรารองรับ connection พร้อมกันหลายหมื่น
เมื่อเกือบปีที่แล้ว เราตัดสินใจเปิด UDP ASSOCIATE เต็มรูปแบบ — ให้ครบตาม RFC และเปิดโอกาสให้ใช้งานที่คู่แข่งส่วนใหญ่ทำไม่ได้: proxy VoIP, game traffic, QUIC protocol ต่าง ๆ โค้ดถูกต้อง เทสผ่าน เราก็ปล่อยขึ้นโปรดักชัน
การสร้างโครงสร้าง proxy ระดับนี้หมายความว่าทุกการตัดสินใจเรื่อง protocol มีผลกระทบจริง ที่ iProxy.online มือถือ Android แต่ละเครื่องทำงานเป็น mobile proxy server อิสระ — รองรับ SOCKS5, HTTP และตอนนี้ UDP เต็มรูปแบบ — จัดการผ่าน dashboard เดียว หรือ Telegram bot ก็ได้ อยากลองดูว่าระบบทำงานยังไงก่อนอ่านเรื่องที่เราทำพัง? ทดลองใช้ฟรี 48 ชั่วโมง — ไม่ต้องใส่บัตรเครดิต
ผ่านไปไม่กี่วัน production server เริ่มมีอาการแปลก ๆ ที่ดูไม่เกี่ยวกันเลย:
ไม่ใช่ค่อย ๆ พังนะ — มันตกหน้าผา ทุกอย่างปกติดีหลายชั่วโมง แล้วจู่ ๆ หลายบริการก็ล่มพร้อมกันบน host เดียวกัน เรา rollback UDP ASSOCIATE แล้วเริ่มขุดหาสาเหตุ
สัญชาตญาณแรกผิดหมด เราเช็ค DDoS, memory leak, disk I/O อิ่ม, CPU สูง — ทุกอย่างปกติ health check ระดับ application เขียวหมดจนกระทั่งวินาทีที่ทุกอย่างตาย
จุดเปลี่ยนมาจาก system metric ระดับต่ำที่ทีมส่วนใหญ่ไม่เคยดู:
node_sockstat_UDP_inuse ไต่ขึ้นไปหลายหมื่น server ปกติตัวเลขนี้อยู่แค่หลักร้อย ของเราพุ่งเกิน 20K
ICMP Type 3 Code 3 (port unreachable) พุ่งสูงขึ้น นี่คือ kernel บอกว่า "จัดสรร source port สำหรับ UDP packet ขาออกไม่ได้แล้ว"
เช็คด้วยมือก็ยืนยัน:
ss -u state all | wc -l
# 28,431
cat /proc/net/sockstat
# UDP: inuse 28419
Ephemeral port range บน Linux ค่าเริ่มต้นคือ 32768–60999 — ประมาณ 28,000 พอร์ต เราใช้หมดเกือบทุกพอร์ต
คำนวณง่าย ๆ Linux มี ephemeral port จำนวนจำกัด — ประมาณ 28K ตามค่าเริ่มต้น UDP ASSOCIATE แต่ละตัวกิน 1 พอร์ต association พร้อมกันหลายร้อยตัว + cleanup ช้า = พอร์ตหมด
พอ ephemeral port หมด ทุกอย่างบน server ที่ต้องเปิด UDP socket ใหม่จะล้มเหลว รวมถึง DNS — ทุก DNS query ขาออกต้องการ ephemeral source port เพื่อส่ง request ไปยัง port 53 name resolution ตาย แล้วทุกอย่างบน server ก็พังตาม ทั้ง ๆ ที่ไม่เกี่ยวกับ DNS เลยสักนิด
ลำดับการล่ม:
Port allocation → UDP ASSOCIATE แต่ละตัวเรียก bind() ด้วย port 0 ขอให้ kernel จัดสรร ephemeral port ถัดไป
Port สะสม → port ค้างเปิดอยู่จนกว่า TCP จะปิดหรือ idle timeout หมด timeout ที่ตั้งไว้สูง หมายความว่า port สะสมเร็วกว่าที่ถูกปล่อยคืน
Pool หมด → association หลายพันตัว แต่ละตัวยึด port ไว้ pool ทั้งหมดจึงถูกดูดจนแห้ง bind() เริ่ม return EADDRINUSE ทุกครั้ง
ระบบล่มทั้งเครื่อง → DNS query ล้มเหลว (systemd-resolved ก็ต้องการ ephemeral port เหมือนกัน) WireGuard handshake ล้ม NTP ล้ม Syslog-over-UDP ล้มแบบเงียบ ๆ จากนั้น DNS ที่ตายก็ทำให้เกิดการล่มลูกโซ่รอบสอง — ทุกอย่างที่ resolve hostname ก็หยุดทำงาน รวมถึง health check, database connection และ monitoring agent server ดูเหมือน "ล่ม" ทั้ง ๆ ที่ CPU, memory และ disk ปกติดี
HTTP health check ผ่าน — endpoint ยัง listen อยู่ CPU, memory, disk, throughput ปกติ metric ระดับ process ไม่มีอะไรผิดปกติ SOCKS5 process ยังทำงานดี แต่ port pool ของ kernel หมด และไม่มีอะไรใน Grafana dashboard มาตรฐานที่ track ตัวนี้
metric เดียวที่จับได้คือตัวที่เราเพิ่มเข้ามาแบบ "เผื่อไว้": socket counter ระดับ kernel และ ICMP error rate
แก้ด้วยแค่สอง config ใช้เวลา debug นานกว่าเวลาแก้อีก
1. ลด idle timeout ลงอย่างหนัก เราลด idle timeout ของ UDP association จากหลักนาทีเหลือหลักวินาที ถ้าไม่มี datagram ผ่าน relay port ภายในช่วงเวลาสั้น ๆ association จะถูกตัดและ port ถูกปล่อยคืน UDP session ที่ถูกต้องส่วนใหญ่ (DNS query, NTP) เสร็จภายในไม่ถึงวินาที session ที่อยู่นาน (VoIP, เกม) จะรักษา association ไว้ผ่าน traffic ที่ส่งต่อเนื่อง จึงไม่ได้รับผลกระทบ
2. จำกัด association พร้อมกันต่อ client เราจำกัดจำนวน UDP association ที่ client แต่ละรายสามารถเปิดพร้อมกันได้ ป้องกันไม่ให้ user คนเดียว — หรือ client ที่ทำงานผิดปกติ — ผูกขาด port pool ทั้งหมด limit ที่ตั้งเพียงพอสำหรับการใช้งานปกติ แต่หยุดการสะสมแบบไม่มีขีดจำกัด
รวมกันแล้ว UDP_inuse ลดจาก 28K กลับเหลือแค่หลักร้อย เราปล่อย UDP ASSOCIATE ขึ้นอีกครั้งพร้อม limit ใหม่ และทำงานเสถียรมาตั้งแต่ตอนนั้น
ตัวการแก้ไขง่ายมาก — ส่วนที่ยากกว่าคือการสร้างระบบ SOCKS5 UDP ASSOCIATE ที่รองรับ session พร้อมกันหลายหมื่นโดยไม่ดูด resource ระบบจนหมด ถ้าคุณต้องการ mobile proxy ที่มี UDP relay เต็มรูปแบบพร้อม lifecycle management ที่ออกแบบมาตั้งแต่แรก iProxy.online ทำงานบนมือถือ Android จริงผ่าน ผู้ให้บริการ 600+ ราย มี IP rotation ควบคุมแต่ละเครื่องแยกกัน แพ็กเกจเริ่มต้นแค่ $6/เดือน
ถ้าคุณรัน service ที่เปิด UDP socket จำนวนมาก — ไม่ว่าจะเป็น SOCKS5 proxy, game server, VoIP หรือ QUIC relay — เพิ่มตัวนี้เข้าไปในระบบ monitoring:
node_sockstat_UDP_inuse (node_exporter) จำนวน UDP socket ที่เปิดอยู่แบบ real-time server ปกติอยู่หลักร้อย ถ้าใช้ Prometheus metric นี้มีอยู่แล้ว — แค่สร้าง panel กับ alert แนะนำให้ alert เมื่อเกิน 5,000
node_netstat_Icmp_OutDestUnreachs (ICMP Type 3 Code 3, port unreachable) พุ่งขึ้นหมายความว่า kernel ตอบกลับ UDP packet ที่ชนพอร์ตที่ไม่มีใครฟังอยู่ สองสามครั้งต่อนาทีไม่เป็นไร หลายพันครั้งต่อวินาทีคือไฟไหม้
ss -u state all | wc -l — เช็คเร็ว ๆ ระหว่าง incident
cat /proc/net/sockstat — one-liner คลาสสิกที่ไม่ต้องลงอะไรเพิ่ม
ตัวนี้ไม่อยู่ใน dashboard เริ่มต้นส่วนใหญ่ แต่ควรจะอยู่ อ่านเพิ่มเติมเรื่องการดูแลโครงสร้าง proxy ให้แข็งแรงได้ที่คู่มือ เพิ่มความเร็วและความเสถียรของ proxy ของเรา
Port เป็นทรัพยากรจำกัด — ต้องจัดสรรเหมือน budget เราจัดสรร CPU, RAM, disk และ bandwidth แต่ไม่มีใครจัดสรร ephemeral port บน server ที่รับ connection หลายหมื่นพร้อมกัน ~28K port ไม่ได้เยอะเลย ขยาย range ได้ด้วย sysctl -w net.ipv4.ip_local_port_range="1024 65535" แต่แม้แต่ 64K ก็มีจำกัดเมื่อ association แต่ละตัวยึดพอร์ตไว้ไม่มีกำหนด
RFC บอก WHAT แต่ไม่บอก HOW RFC 1928 เขียนขึ้นปี 1996 ตอนที่ server "ยุ่ง" หมายถึงรับแค่หลักร้อย connection มันอธิบายกลไก protocol ได้สมบูรณ์แบบ แต่ไม่ได้พูดถึง port lifecycle management, resource cap หรือ graceful degradation เลย ถ้าคุณ implement protocol ใดก็ตามแบบ scale ให้อ่าน RFC เพื่อความถูกต้อง แล้วออกแบบ resource management ของคุณเองเพิ่มเติม
Kernel metric จับได้ในสิ่งที่ application metric มองไม่เห็น Health check, Prometheus scraper และ HTTP ping ทั้งหมดบอกว่า server ปกติ แต่ kernel รู้ดีกว่า ถ้า monitoring ของคุณไม่มี socket statistics กับ ICMP counter แสดงว่าคุณมีจุดบอดสำหรับปัญหา resource exhaustion ทั้ง class เราเจอ observability gap คล้าย ๆ กันกับ TLS 1.3 failure บนฝูง Android device ของเรา — ต้นตอต่างกัน แต่บทเรียนเดียวกัน
UDP ต้องการ lifecycle management แบบ explicit TCP มี lifecycle ในตัว — connection เปิด, ส่งข้อมูล, ปิดด้วย handshake ชัดเจน port ถูกนำกลับมาใช้หลังจาก TIME_WAIT แต่ UDP ไม่มีอะไรแบบนี้เลย socket จะเปิดค้างจนกว่าจะมีอะไรมาปิดมัน ในสถาปัตยกรรม relay คุณต้องสร้าง lifecycle ขึ้นมาเอง ไม่งั้นก็รับกับการใช้ resource แบบไม่มีขีดจำกัดไป
นี่ไม่ใช่ปัญหาเฉพาะ proxy อะไรก็ตามที่จัดสรร UDP socket ตาม request ของ user สามารถตกหน้าผาเดียวกันได้:
ถ้าคุณรันอะไรพวกนี้แบบ scale — หรือเปิด mobile proxy farm — เช็ค sockstat วันนี้เลย คุณอาจอยู่ใกล้ขอบหน้าผามากกว่าที่คิด
เรา implement SOCKS5 UDP ASSOCIATE ถูกต้องทุกประการ — ครบตาม RFC, ผ่านเทส, deploy ขึ้นจริง แล้วมันก็ทำให้ระบบทั้งหมดล่มแบบที่ monitoring มาตรฐานมองไม่เห็น
สิ่งที่เราถือเป็นกฎเหล็กตั้งแต่ตอนนั้น: ฟีเจอร์ใดก็ตามที่จัดสรร resource ระดับ kernel — port, file descriptor, conntrack entry — ต้องมี lifecycle management และ resource budgeting ตั้งแต่วันแรก ไม่ใช่มาแก้หลังจากล่มรอบแรก
Port เหมือนออกซิเจน ไม่มีใครสนใจมันจนกว่ามันจะหมด
นี่คือ production incident จริงจาก iProxy.online เราสร้างโครงสร้าง mobile proxy ที่เปลี่ยนมือถือ Android ให้เป็น SOCKS5 และ HTTP proxy server ให้บริการใน 100+ ประเทศ ผ่านผู้ให้บริการ 600+ ราย รองรับ UDP ASSOCIATE เต็มรูปแบบ — พร้อม resource management ที่เหมาะสม สร้าง mobile proxy ของคุณเอง →
SOCKS5 UDP ASSOCIATE เป็นหนึ่งในสาม command ตาม RFC 1928 ช่วยให้ client relay UDP datagram ผ่าน SOCKS5 proxy โดยสร้าง UDP socket เฉพาะสำหรับแต่ละ association ต่างจาก CONNECT (tunnel TCP) ตรงที่ UDP ASSOCIATE รองรับ traffic แบบ connectionless — ใช้สำหรับ DNS, VoIP, เกมออนไลน์ และ QUIC protocol
Linux ค่าเริ่มต้นใช้ range 32768–60999 ได้ประมาณ 28,000 พอร์ต เช็ค range ปัจจุบันด้วย cat /proc/sys/net/ipv4/ip_local_port_range และขยายได้ด้วย sysctl -w net.ipv4.ip_local_port_range="1024 65535" จะได้ ~64,000 พอร์ต แม้ขยายแล้วก็ยังมีจำกัดเมื่อรับ UDP relay workload หนัก ๆ
DNS query ขาออกทุกตัวต้องการ ephemeral source port เพื่อส่ง UDP packet ไปยัง port 53 เมื่อ ephemeral port ถูกใช้หมดโดย UDP socket อื่น kernel จัดสรรพอร์ตใหม่ไม่ได้ DNS resolution จึงล่มทั้งระบบ — ทั้ง ๆ ที่ DNS server เองยังทำงานปกติ
ติดตาม node_sockstat_UDP_inuse ใน Prometheus/node_exporter สำหรับจำนวน UDP socket แบบ real-time ใช้ ss -u state all | wc -l หรือ cat /proc/net/sockstat สำหรับเช็คด้วยมือ ตั้ง alert บน ICMP Type 3 Code 3 (port unreachable) ผ่าน node_netstat_Icmp_OutDestUnreachs
ใช่ iProxy.online รองรับ SOCKS5 UDP ASSOCIATE เต็มรูปแบบ พร้อม CONNECT และ HTTP proxy หลังจากเหตุการณ์ในบทความนี้ เราเพิ่ม rate limit ต่อ client และ idle timeout ที่เข้มงวดขึ้นเพื่อป้องกัน port exhaustion ในขณะที่ UDP relay ยังทำงานได้เต็มที่สำหรับ VoIP, เกม และ QUIC traffic
ไม่ว่าคุณจะรัน TURN server, game infrastructure หรือเครือข่าย mobile proxy — การจัดการ ephemeral port เป็นเรื่องสำคัญ iProxy.online ให้คุณใช้ SOCKS5 พร้อม UDP ASSOCIATE ที่พร้อมสำหรับ production ควบคุมผ่าน dashboard และ API ตั้งค่าเสร็จใน 5 นาที บนมือถือ Android เครื่องไหนก็ได้ ทดลองใช้ฟรี 48 ชั่วโมง — ทดสอบกับ workload จริงของคุณ