12/04/2026 18:16น.

Golang The Series EP 131: WebSocket ใน Microservices Architecture
#Go
#Golang
#Microservices
#Microservices Architecture
#WebSocket
ยินดีต้อนรับชาว Gopher ทุกท่านครับ! การสร้าง WebSocket Server ให้ทำงานได้เพียงตัวเดียวนั้นไม่ยาก แต่การทำให้มันทำงานร่วมกับ Microservices อื่นๆ นับสิบหรือนับร้อยตัวได้อย่างไร้รอยต่อ นั่นคือ "ของจริง" ที่วิศวกรซอฟต์แวร์ต้องเผชิญ
ในสถาปัตยกรรมระดับ Enterprise ระบบ WebSocket ของเราจะทำหน้าที่เป็น "Real-time Gateway" หรือ "Notification Hub" กลางที่คอยรับคำสั่งจาก Service ต่างๆ มา Push ข้อมูลให้ถึงมือผู้ใช้ในเสี้ยววินาทีครับ
1. การวางตำแหน่ง WebSocket ในระบบ (Service Topology)
เราควรวาง WebSocket ไว้ตรงไหน? มี 2 รูปแบบที่เป็นมาตรฐานครับ:
- Dedicated Notification Service (แนะนำ): แยกออกมาเป็น Service เฉพาะทางที่มีหน้าที่จัดการ "ท่อเชื่อมต่อ" (Persistent Connections) อย่างเดียว
- ข้อดี: Scale ส่วนที่เป็น Stateful ออกจาก Stateless ได้ง่าย เพราะ WebSocket กิน Memory สูงกว่า API ปกติมาก (เพื่อรักษาท่อ TCP)
- ข้อเสีย: มีความซับซ้อนในการตั้งค่า Network และ Routing เพิ่มขึ้นเล็กน้อย
- Embedded (ฝังใน Business Service): เช่น อยู่ใน chat-service เลย
- ข้อดี: พัฒนาง่ายในช่วงแรก เพราะโค้ดอยู่ที่เดียวกัน
- ข้อเสีย: เมื่อต้อง Scale ระบบ chat-service ทั้งหมดจะถูกดึงทรัพยากรไปใช้กับการรักษา Connection จนอาจกระทบ Logic อื่นๆ
Reviewer's Note: ในระดับ Production ผมแนะนำแบบ Dedicated ครับ เพราะเราสามารถทำ Resource Isolation ได้ชัดเจน ทำให้ระบบมีความเสถียร (Reliability) สูงกว่ามาก
2. ไขปริศนา Authentication ผ่าน API Gateway
ปัญหาที่ Developer เจอบ่อยที่สุดคือ Browser ไม่รองรับการส่ง Custom Header ในคำสั่ง new WebSocket() ทำให้เราส่ง Authorization: Bearer <JWT> แบบปกติไม่ได้
แนวทางแก้โจทย์ Auth ที่เป็นมาตรฐานสากล:
- Ticket-based Auth (ดีที่สุด): * Client เรียก REST API ปกติ (ผ่าน Gateway พร้อม Header) เพื่อขอ "One-time Ticket"
- Server สร้าง Ticket สั้นๆ (อายุ 30-60 วินาที) เก็บไว้ใน Redis และส่งคืนให้ Client
- Client ใช้ Ticket นี้แนบไปกับ Query String ตอนเปิด WebSocket
- WebSocket Service ตรวจสอบ Ticket กับ Redis ถ้าถูกต้องก็ให้ผ่าน
- JWT via Query String: ง่ายแต่เสี่ยง เพราะ Token อาจหลุดไปใน Access Log ของ Gateway หรือ Proxy ได้ (ไม่แนะนำสำหรับข้อมูลที่ความสำคัญสูง)
3. Communication Patterns: เมื่อเพื่อนบ้านอยากคุยด้วย
เมื่อ Order Service ตัดเงินสำเร็จ มันจะสั่งให้ WebSocket Service แจ้งเตือน User ได้อย่างไร? มี 2 ท่ามาตรฐานครับ:
ท่ามาตรฐาน (Standard Practice): ใช้ Message Broker เป็นตัวกลางครับ Order Service แค่ตะโกนบอกว่า "Order #123 เสร็จแล้ว!" ลงใน Topic จากนั้น WebSocket Service ทุกตัวที่ Subscribe อยู่จะได้รับข้อมูล และตรวจสอบว่า User คนนั้นต่ออยู่ที่เครื่องตัวเองไหม (ตามที่เราทำใน EP 130)
4. ตัวอย่างการใช้ gRPC เป็นช่องทางด่วน (Internal Interface)
ใน Go เรานิยมใช้ gRPC เพราะมีประสิทธิภาพสูงและมี Type-safety เราสามารถสร้าง Internal Interface ให้ Service อื่นเรียกใช้ได้ดังนี้:
Go
// ตัวอย่าง Notification Service ที่รับคำสั่งผ่าน gRPC
type notificationServer struct {
pb.UnimplementedNotificationServer
hub *Hub // มาจาก EP 130
}
func (s *notificationServer) PushToUser(ctx context.Context, req *pb.PushRequest) (*pb.PushResponse, error) {
// 1. ตรวจสอบว่า User อยู่ที่เครื่องนี้ไหม
if client, ok := s.hub.GetLocalClient(req.UserId); ok {
client.send <- []byte(req.Message)
return &pb.PushResponse{Status: "Delivered_Locally"}, nil
}
// 2. ถ้าไม่อยู่ ให้ Publish ลง Redis Pub/Sub เพื่อให้ Instance อื่นรับไปทำต่อ
err := s.hub.redisClient.Publish(ctx, "global_notifications", req.Message).Err()
if err != nil {
return nil, status.Errorf(codes.Internal, "Failed to dispatch: %v", err)
}
return &pb.PushResponse{Status: "Dispatched_to_Cluster"}, nil
}
5. Infrastructure: Service Discovery และ Load Balancer
- Service Discovery: ใน Kubernetes เราใช้ Service Name หรือ Headless Service เพื่อให้ Microservices คุยกันเองได้โดยไม่ต้องระบุ IP
- Ingress/Load Balancer: ต้องรองรับโปรโตคอล Upgrade และควรเปิด Session Affinity (Sticky Sessions) เพื่อช่วยให้ User ไม่ต้อง Re-handshake บ่อยเกินจำเป็นเมื่อมีการ Rolling Update ระบบ
- Service Mesh (เช่น Istio): ระวังเรื่องการตั้งค่า Timeout เพราะ Service Mesh มักจะมี Default Timeout ที่สั้น ซึ่งอาจจะตัดท่อ WebSocket ของเราได้ครับ
สรุป
การนำ WebSocket เข้าสู่ Microservices คือการเปลี่ยนจาก "การเชื่อมต่อ" เป็น "การจัดการทิศทางข้อมูล" การใช้ Ticket-based Auth และ Message Broker จะช่วยให้ระบบของคุณมีความปลอดภัยและขยายตัวได้ง่าย (Scalability) ในระยะยาวครับ
ในตอนหน้า (EP 132): เรื่องสำคัญที่สาย Production ห้ามพลาด! Cloud Cost Optimization สำหรับ WebSocket – เราจะจัดการทรัพยากรอย่างไรให้ระบบลื่นไหล แต่ราคาประหยัดที่สุด? เจอกันตอนหน้าครับ!