การดู : 0

12/04/2026 18:16น.

Golang The Series EP.138: Monitoring Latency & Performance – รีดความเร็ว WebSocket ให้ลื่นระดับเทพ

Golang The Series EP.138: Monitoring Latency & Performance – รีดความเร็ว WebSocket ให้ลื่นระดับเทพ

#Superdev Academy

#Performance Optimization

#Latency

#WebSocket

#Golang

รีดความเร็วระดับมิลลิวินาที ให้ระบบลื่นไหลไม่มีสะดุด

 

ยินดีต้อนรับชาว Gopher ทุกท่านครับ! ในโลกของระบบ Real-time คำถามที่ว่า "Server รับคนได้กี่คน?" นั้นเป็นเพียงแค่ปริมาณ แต่สิ่งที่ตัดสินว่าระบบของคุณ "เจ๋ง" จริงหรือไม่คือ "Latency" หรือความหน่วงครับ

ลองจินตนาการว่าคุณกำลังเล่นแอปเทรดหุ้น หรือแอปแชทที่ส่งข้อความไปแล้วต้องรอ 1-2 วินาทีกว่าอีกฝ่ายจะเห็น นั่นไม่ใช่ประสบการณ์ WebSocket ที่ดีครับ วันนี้เราจะมาสวมวิญญาณนักปรับแต่ง (Tuner) เพื่อมองหา "ความช้าที่มองไม่เห็น" และกำจัดมันให้สิ้นซากครับ

 

1. การวัด Latency: เลิกเชื่อค่า Average (เฉลี่ย) ได้แล้ว!

หนึ่งในความผิดพลาดที่ร้ายแรงที่สุดของ Developer คือการดูแค่ Average Latency เพราะค่าเฉลี่ยจะกลบปัญหาที่เกิดขึ้นกับผู้ใช้บางกลุ่มไปจนหมด สิ่งที่เราต้องโฟกัสคือ Percentiles ($P_{95}, P_{99}$):

  • Average ($P_{50}$): ค่ากลางๆ ที่คนส่วนใหญ่เจอ
  • $P_{95}$: 95% ของผู้ใช้ได้รับข้อมูลภายในเวลานี้ (เริ่มเห็นปัญหา)
  • $P_{99}$: 1% ของผู้ใช้ที่โชคร้ายที่สุดเจอความช้าเท่าไหร่? (นี่คือ Tail Latency ที่มักเกิดจาก GC หรือ Network Congestion)

Superdev Tip: หาก $P_{50}$ ของคุณอยู่ที่ 20ms แต่ $P_{99}$ พุ่งไปที่ 2,000ms แสดงว่าระบบคุณมีอาการ "สะอึก" (Spike) ซึ่งมักเกิดจาก Stop-the-world ของ Garbage Collector หรือการติด Lock (Mutex) นานเกินไปครับ

 

2. เจาะลึกจุดที่ทำให้เกิดความล่าช้า (The Bottlenecks)

Latency ใน WebSocket ไม่ได้มาจากโค้ด Go อย่างเดียว แต่มันคือผลรวมของ 3 ปัจจัย:

  1. Network Latency: ระยะทางทางกายภาพ (Speed of Light) แก้ได้ด้วยการขยับ Server ไปใกล้ User (Edge Computing/AWS Global Accelerator)
  2. OS/Stack Latency: การจัดการ Context Switching ของ OS และ TCP Buffer ที่ไม่เหมาะสม
  3. Application Latency:
    • Lock Contention: การใช้ sync.Mutex ในจุดที่มี Traffic หนาแน่นจน Goroutines ต้องเข้าแถวรอ
    • Garbage Collection (GC): การจอง Memory พร่ำเพรื่อจน Go ต้องหยุดทำงานเพื่อกวาดขยะ

 

3. กลยุทธ์การ Optimization ฉบับ Go Expert

A. ลดการจองหน่วยความจำด้วย sync.Pool

การสร้าง Object (เช่น Buffer สำหรับอ่านข้อความ) ใหม่ทุกครั้งที่ส่งข้อความคือ "ภาระ" ของระบบครับ เราควรนำของเก่ามาใช้ใหม่ (Reuse)

 

Go
var bufferPool = sync.Pool{
    New: func() any {
        // จอง Buffer ขนาด 4KB เตรียมไว้
        return make([]byte, 4096)
    },
}

func handleMessage(conn *websocket.Conn) {
    buf := bufferPool.Get().([]byte)
    defer bufferPool.Put(buf) // คืนเข้า Pool เมื่อใช้เสร็จ

    _, message, _ := conn.ReadMessage()
    copy(buf, message)
    // ประมวลผลต่อโดยไม่สร้างภาระให้ GC
}

 

B. ปรับแต่ง TCP Stack (TCP_NODELAY)

โดยปกติ TCP จะใช้ Nagle's Algorithm เพื่อรอรวมข้อมูลชิ้นเล็กๆ เป็นก้อนใหญ่ก่อนส่ง (เพื่อประหยัด Bandwidth) แต่สำหรับ WebSocket มันคือ "ยาพิษ" เพราะทำให้ข้อมูลดีเลย์

  • Solution: ตรวจสอบว่า Library ของคุณเปิด SetNoDelay(true) หรือยัง (ใน Go net package จะเปิดให้เป็น Default อยู่แล้ว แต่ถ้าผ่าน Proxy/Load Balancer ต้องเช็คจุดนั้นด้วยครับ)

C. ย้ายจาก JSON ไปเป็น Binary (Protobuf)

JSON กิน CPU ในการ Serialize/Deserialize สูงมาก และมีขนาดใหญ่ (Verbose) การเปลี่ยนมาใช้ Protocol Buffers (Protobuf) จะช่วยลดขนาด Packet ลงได้ 30-70% ซึ่งหมายถึง Latency ที่ลดลงในระดับ Network ด้วยครับ

 

4. Monitoring แบบ End-to-End ด้วย Tracing

ถ้า Server บอกว่าประมวลผลเสร็จใน 5ms แต่ User บ่นว่าช้า? ปัญหาระหว่างทางคือสิ่งที่คุณต้องพิสูจน์ครับ

เราใช้ OpenTelemetry (OTel) ในการฉีด Trace ID เข้าไปใน WebSocket Handshake:

  • คุณจะเห็นทันทีว่าข้อมูลค้างอยู่ที่ Load Balancer นานเท่าไหร่
  • ค้างอยู่ที่ Redis (Pub/Sub) นานเท่าไหร่
  • และออกไปถึงหน้าจอ User เมื่อไหร่

การเห็นภาพแบบ Timeline จะทำให้คุณเลิก "เดา" แล้วเริ่ม "แก้" ได้ถูกจุดครับ

 

5. การจูน Write Buffer และ Flush Strategy

ในระบบที่มีการส่งข้อความถี่มาก (เช่น กราฟหุ้น) การส่งออกไปทีละข้อความ (Write) จะทำให้เกิด System Call บ่อยจน CPU Peak

  • Tuning: ใช้การทำ Write Coalescing (รวมข้อความสั้นๆ ในช่วงเวลาไม่กี่มิลลิวินาทีแล้วส่งออกไปทีเดียว) เพื่อลดจำนวน System Call โดยไม่กระทบต่อความรู้สึก Real-time ของผู้ใช้

 


 

สรุป

Monitoring & Performance Optimization ไม่ใช่การตั้งค่าครั้งเดียวแล้วจบ แต่เป็นงานฝีมือที่ต้องอาศัยข้อมูล (Data-driven) การทำให้ระบบเร็วขึ้น 100ms อาจดูเหมือนน้อยในเชิงตัวเลข แต่มันคือความต่างระหว่าง "แอปที่ให้ความรู้สึกติดขัด" กับ "แอปที่ลื่นไหลระดับเทพ" ครับ

ในตอนหน้า (EP.139): เราจะขยับไปดูเคสที่ท้าทายที่สุดคือ Best Practices สำหรับ Mobile & Low-bandwidth Environment — เมื่อเน็ตมือถือของ User ไม่เป็นใจ (3G/4G หรือเน็ตแกว่ง) เราจะทำอย่างไรให้ WebSocket ยังทำงานได้เสถียร! ห้ามพลาดครับ