How Postman Engineering handles a million concurrent connections
Bài tóm tắt Postman 2020 3. Quy mô lớn Độ khó: Trung bình
Postman · 2020 · 3. Quy mô lớn · Độ khó: Trung bình — bài gốc
Bối cảnh
- Service Sync là một trong những service đầu tiên của Postman: đồng bộ mọi hoạt động trên client với server qua WebSocket theo kiểu pub/sub. Ban đầu chỉ lo giao dịch DB (ví dụ cập nhật collection), dần ôm thêm việc thông báo cho mọi người đang xem. Nhiều team cùng sửa code, mọi thay đổi phải phối hợp: một "microservice" đã thành monolith.
- 2019: 11 triệu user, gần 1 triệu kết nối đồng thời lúc đỉnh. Vấn đề:
- Mỗi lần deploy Sync là ngắt mọi client. Một triệu socket kết nối lại làm tài nguyên server suy giảm, gây ngắt thêm: đợt dâng có thể đoán trước nhưng mất 6–8 giờ mới hồi.
- Mọi team phải tự học cách xử lý mất kết nối, kết nối lại, hoà giải xung đột dữ liệu.
Thay đổi chính
- Bước 1–2 (từ 10/2019): xin đồng thuận của tổ chức qua các buổi review (lợi ích cho mọi team phụ thuộc: không còn phải xử lý mất kết nối); hai tháng tìm "unknown unknowns" với các bên liên quan.
- Bước 3: Bifrost, hai phần:
- Gateway công khai: đầu cuối của mọi kết nối WebSocket, Fastify (thay Sails vốn dùng cho service khác) và fork
socketio-adapter, Redis (ElastiCache) làm broker trung tâm, tách node đọc/ghi. Tự viết thay vì mua gateway thương mại để giữ logic nghiệp vụ tích luỹ nhiều năm và kiểm soát cả handshake. Ít khi phải deploy. - API riêng: chuyển message realtime thành lời gọi HTTP tới service nội bộ theo luật nghiệp vụ, deploy độc lập và thường xuyên. Theo bài: "thành phần đơn giản, logic phức tạp".
- Gateway công khai: đầu cuối của mọi kết nối WebSocket, Fastify (thay Sails vốn dùng cho service khác) và fork
- Bước 4: chưa có test tự động cho WebSocket nên test tay mọi tính năng; có proof of concept cuối 1/2020.
- Bước 5: chuyển dần bằng service bootstrap. Mọi client gọi "Godserver" lúc khởi động để lấy cấu hình và quyền; nó tăng dần phần traffic sang Bifrost, không cần cập nhật client. Các team chuyển service của mình trong vài tuần.
- Bước 6: scale ra, không scale lên: nhiều máy nhỏ thay vì máy to (client không cần nhiều băng thông, mỗi máy ít kết nối thì vùng ảnh hưởng nhỏ); autoscale theo load factor tự định nghĩa kết hợp CPU và bộ nhớ, phi tuyến.
- Còn lại: Redis broker vẫn là điểm hỏng chung; gateway chịu được khoảng 10 lần mức đồng thời hiện tại; tiếp tục tách Sync.
Vì sao
- Giữ kết nối bền chung process với logic hay deploy thì mỗi lần deploy là một đợt thundering herd tự gây ra; tách lớp giữ kết nối (ít đổi) khỏi lớp logic (đổi thường xuyên) bỏ được nguyên nhân (Hot partition và thundering herd, Realtime và fan-out).
- Tách theo nhịp thay đổi là bước đầu để chia nhỏ tiếp một service đã phình (Monolith và microservices — đi và quay lại).
Bài học cho SWE
- Tầng giữ kết nối realtime nên mỏng, ổn định, ít deploy; logic để ở tầng sau có thể deploy tự do.
- Một service bootstrap mà mọi client gọi lúc khởi động là công cụ rollout dần không cần phát hành client mới.
- Kết nối bền nhiều mà băng thông thấp: scale bằng nhiều máy nhỏ và metric autoscale riêng.
Liên quan
Realtime và fan-outMonolith và microservices — đi và quay lạiHot partition và thundering herdMigration không downtime
#WebSocket gateway#Pub/sub#Redis#Fastify#Socket.io adapter#Reconnect storm#Monolith#Horizontal scaling#Custom autoscaling metric
Được nhắc tới trong
Chủ đề (4)
Công ty (1)
Bài tóm tắt (2)