Menu
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Đang tải...

WebSocket cho real-time apps

API and Technical Fundamentals cho BA Bài 30/60

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn đang là BA cho một dự án ứng dụng gọi xe ở TP.HCM. Sản phẩm cần một tính năng: khi tài xế di chuyển, vị trí của họ phải nhảy mượt trên bản đồ của khách hàng theo thời gian thực. Bạn viết user story rất gọn: "Là hành khách, tôi muốn thấy xe đang đến gần để biết còn bao lâu nữa". Nghe đơn giản, nhưng khi ngồi vào bàn với đội kỹ thuật, lập trình viên hỏi ngay: "Vị trí cập nhật mỗi giây — chị muốn dùng WebSocket hay polling?". Nếu bạn ngơ ngác ở câu hỏi này, bạn sẽ mất quyền kiểm soát cuộc thảo luận, và tệ hơn, bạn sẽ không hiểu tại sao chi phí hạ tầng, độ trễ, hay trải nghiệm người dùng lại phụ thuộc vào lựa chọn đó.

WebSocket là một trong những công nghệ "nền tảng" mà BA hiện đại buộc phải nắm — không phải để code, mà để hiểu khi nào nó là lựa chọn đúng, nó thay đổi yêu cầu hệ thống thế nào, và nó đặt ra những ràng buộc gì cho thiết kế tính năng. Suốt 29 bài trước, chúng ta đã làm việc với mô hình HTTP request–response: client hỏi, server trả lời, rồi kết nối đóng lại. Mô hình này tuyệt vời cho phần lớn nghiệp vụ, nhưng nó có một điểm chí mạng: server không thể tự nói chuyện với client. Bài này sẽ giúp bạn hiểu rõ "real-time bidirectional" (hai chiều, thời gian thực) là gì, vì sao HTTP truyền thống không kham nổi, và WebSocket lấp khoảng trống đó ra sao.

Khái niệm cốt lõi

Vấn đề của mô hình request–response

Trong HTTP truyền thống, mọi cuộc trò chuyện đều do client khởi xướng. Client gửi một request, server xử lý và gửi lại một response, sau đó kết nối kết thúc. Server hoàn toàn bị động — nó chỉ "mở miệng" khi được hỏi. Đây là mô hình "kéo" (pull): muốn dữ liệu mới, client phải chủ động đi lấy.

Điều này tạo ra hai loại tình huống mà HTTP xử lý rất vụng:

  • Server cần chủ động đẩy dữ liệu xuống client: ví dụ một tin nhắn chat mới đến. Server biết có tin nhắn, nhưng không có cách nào "gõ cửa" client để báo. Nó phải chờ client tự hỏi.
  • Dữ liệu thay đổi liên tục, độ trễ thấp: ví dụ vị trí xe cập nhật mỗi giây, hay giá cổ phiếu nhảy từng tích tắc. Client muốn cập nhật tức thì chứ không phải đợi mình hỏi xong mới biết.

Polling — giải pháp chắp vá và cái giá của nó

Cách "lách" phổ biến nhất khi chỉ có HTTP là polling: client cứ vài giây lại gửi một request hỏi "Có gì mới không?". Nếu hỏi mỗi 3 giây, một người dùng mở app trong 10 phút sẽ tạo ra 200 request — phần lớn trong số đó server trả về "Không có gì mới". Đó là lãng phí băng thông, lãng phí tài nguyên server, và vẫn có độ trễ tới vài giây (chi tiết về Webhooks vs Polling sẽ được phân tích kỹ ở một bài riêng; ở đây ta chỉ cần thấy polling không phải lời giải tốt cho real-time).

WebSocket là gì

WebSocket là một giao thức (protocol) cho phép mở một kết nối hai chiều, lâu dài (persistent), liên tục giữa client và server. Một khi kết nối được thiết lập, cả hai bên đều có thể gửi dữ liệu cho nhau bất cứ lúc nào, không cần hỏi trước. Đây gọi là full-duplex — giống cuộc gọi điện thoại, cả hai cùng nói và nghe được, khác hẳn bộ đàm (half-duplex, mỗi lúc chỉ một người nói).

Vài đặc điểm cốt lõi BA cần ghi nhớ:

  • Bắt đầu bằng một cú "bắt tay" HTTP: WebSocket tận dụng chính HTTP để mở kết nối. Client gửi một request đặc biệt với header Upgrade: websocket. Nếu server đồng ý, nó trả về status code 101 Switching Protocols, và từ đó kết nối "nâng cấp" từ HTTP sang WebSocket. Đây là lý do WebSocket dùng được trên hạ tầng web sẵn có.
  • URL bắt đầu bằng ws:// hoặc wss://: tương tự http://https://. wss là phiên bản mã hóa (secure), luôn được khuyến nghị cho production.
  • Kết nối được giữ mở: không như HTTP đóng kết nối sau mỗi response, WebSocket giữ "đường dây" mở liên tục. Server có thể "push" dữ liệu xuống bất kỳ lúc nào.
  • Truyền theo "message": dữ liệu đi qua WebSocket dưới dạng các thông điệp (thường là chuỗi text như JSON, hoặc dữ liệu nhị phân), nhẹ hơn nhiều so với việc dựng lại toàn bộ header HTTP cho mỗi lần trao đổi.

Khi nào dùng WebSocket, khi nào không

Đây là phần BA cần khắc cốt ghi tâm. WebSocket không phải để thay thế HTTP/REST. Nó là công cụ cho một lớp bài toán cụ thể:

  • Hợp với WebSocket: chat, thông báo real-time, live tracking (vị trí, giao hàng), bảng giá tài chính/crypto, dashboard cập nhật liên tục, chơi game nhiều người, công cụ cộng tác (kiểu Google Docs nhiều người sửa cùng lúc), đấu giá trực tuyến.
  • Không cần WebSocket: lấy danh sách sản phẩm, đăng nhập, gửi form, tải hồ sơ khách hàng — những nghiệp vụ một-lần, request–response truyền thống là đủ và đơn giản hơn.
Một nguyên tắc thực dụng: chỉ chọn WebSocket khi server thực sự cần chủ động đẩy dữ liệu xuống client mà không thể đoán trước thời điểm, hoặc khi tần suất cập nhật quá cao để polling kham nổi. Nếu không, dùng REST cho nhẹ đầu cả hệ thống lẫn đội vận hành.

Tình huống thực tế

Ví dụ 1: Tính năng chat trong app giao đồ ăn (GrabFood / ShopeeFood)

Bối cảnh: Một startup giao đồ ăn ở Hà Nội muốn thêm chat giữa khách và tài xế, thay vì để hai bên gọi điện. Đội product giao cho BA viết spec.

Diễn giải: Ban đầu nhóm kỹ thuật định làm bằng polling — app khách hỏi server mỗi 2 giây "có tin nhắn mới không". Với 30.000 đơn hàng đang hoạt động vào giờ cao điểm trưa, mỗi đơn có 2 thiết bị (khách + tài xế) cùng polling, server phải xử lý khoảng 30.000 × 2 ÷ 2 = 30.000 request mỗi giây chỉ để kiểm tra tin nhắn — trong khi 95% các lần đều trả về "rỗng". Khi BA ngồi cùng kiến trúc sư, họ chuyển sang WebSocket: mỗi thiết bị giữ một kết nối mở, server đẩy tin nhắn xuống đúng người nhận ngay khi có. Tải request giảm hàng chục lần, độ trễ tin nhắn từ "đến 2 giây" xuống còn dưới 100ms.

Bài học rút ra: BA không cần biết viết WebSocket, nhưng cần biết đặt câu hỏi "với quy mô X người dùng đồng thời, polling tạo ra bao nhiêu tải vô ích?". Chính con số đó là lập luận để chọn WebSocket, và cũng là thứ bạn đưa vào tài liệu để bảo vệ quyết định trước ban lãnh đạo.

Ví dụ 2: Live tracking đơn hàng của một sàn TMĐT

Bối cảnh: Một sàn thương mại điện tử ở Đông Nam Á (giả định kiểu Tiki/Lazada) muốn cho khách xem shipper đang ở đâu trên bản đồ, vị trí cập nhật mỗi giây khi shipper sắp đến.

Diễn giải: Yêu cầu nghiệp vụ ở đây có một sắc thái quan trọng mà BA phải nắm: vị trí chỉ cần real-time trong giai đoạn "đang giao", không phải suốt vòng đời đơn hàng. Nếu để WebSocket mở từ lúc đặt hàng đến lúc nhận, hệ thống phải gánh hàng triệu kết nối nằm im vô ích. BA viết spec rõ: kết nối WebSocket chỉ được mở khi đơn chuyển sang trạng thái "shipper đang trên đường", và đóng lại khi giao xong. Đồng thời BA định nghĩa "tần suất cập nhật" là 1 giây — con số này ảnh hưởng trực tiếp đến chi phí và độ mượt, nên phải được chốt rõ chứ không để mơ hồ.

Bài học rút ra: Với real-time, BA phải đặc tả ba thứ thường bị bỏ sót: khi nào kết nối được mở, khi nào đóng, và tần suất dữ liệu cập nhật. Thiếu ba thứ này, dev sẽ tự suy diễn và spec dễ "vỡ" lúc đẩy lên quy mô lớn.

Ví dụ 3: Dashboard giá crypto của một sàn giao dịch Việt Nam

Bối cảnh: Một sàn giao dịch tài sản số muốn dashboard hiển thị giá BTC, ETH nhảy liên tục theo thị trường, cùng với sổ lệnh (order book) cập nhật từng mili-giây.

Diễn giải: Đây là ca "real-time bắt buộc" rõ ràng nhất. Giá có thể đổi hàng chục lần mỗi giây; polling là không tưởng. Sàn dùng WebSocket để server đẩy mọi biến động giá xuống tất cả client đang xem. BA ở đây cần làm việc với đội kỹ thuật về một câu hỏi tinh tế: điều gì xảy ra khi client mất kết nối giữa chừng? (ví dụ người dùng đi vào thang máy mất sóng). Spec phải mô tả hành vi reconnect (tự kết nối lại) và cách hiển thị trạng thái "đang mất kết nối, giá có thể không chính xác" để tránh người dùng giao dịch dựa trên dữ liệu cũ — một rủi ro pháp lý thật sự với sản phẩm tài chính.

Bài học rút ra: Real-time đi kèm rủi ro mới mà mô hình request–response không có: trạng thái "dữ liệu cũ một cách âm thầm". BA giỏi là người lường trước và đặc tả rõ cách hệ thống ứng xử khi kết nối gián đoạn.

Hướng dẫn từng bước

Khi bạn — với vai trò BA — cần phân tích và đặc tả một tính năng real-time, hãy đi theo trình tự sau:

  • Xác định bản chất luồng dữ liệu: Hỏi "Server có cần chủ động đẩy dữ liệu xuống client không?" và "Dữ liệu thay đổi nhanh tới mức nào?". Nếu cả hai đều "có/cao", WebSocket là ứng viên sáng giá. Nếu không, đừng phức tạp hóa — REST là đủ.
  • So sánh nhanh với polling: Ước lượng số người dùng đồng thời và tần suất cập nhật. Tính thử lượng request vô ích mà polling tạo ra. Con số này vừa giúp ra quyết định, vừa là dữ liệu thuyết phục stakeholder.
  • Đặc tả vòng đời kết nối: Ghi rõ ba mốc — kết nối mở khi nào (sự kiện nào kích hoạt), đóng khi nào, và tần suất dữ liệu đẩy xuống. Đây là phần BA hay quên nhất.
  • Định nghĩa cấu trúc message: WebSocket truyền các message, thường là JSON. Hãy đặc tả các loại event: ví dụ { "type": "location_update", "lat": ..., "lng": ... }, { "type": "new_message", ... }. Việc dùng trường type để phân loại event là pattern phổ biến, giúp client xử lý đúng từng loại.
  • Đặc tả kịch bản mất kết nối: Mô tả hành vi reconnect, có hiển thị trạng thái kết nối cho người dùng không, và dữ liệu bị bỏ lỡ trong lúc rớt mạng được xử lý ra sao (bỏ qua, hay đồng bộ lại?).
  • Xác định ràng buộc hạ tầng cùng đội kỹ thuật: WebSocket giữ kết nối lâu dài nên ăn tài nguyên server khác hẳn REST. Hỏi đội DevOps về giới hạn số kết nối đồng thời, và liệu load balancer/CDN hiện tại có hỗ trợ WebSocket không (nhiều cấu hình mặc định chặn hoặc tự đóng kết nối lâu).
  • Viết acceptance criteria đo được: Ví dụ "Tin nhắn xuất hiện ở thiết bị người nhận trong vòng tối đa 500ms kể từ khi gửi", hay "Khi mất mạng 5 giây rồi có lại, client tự reconnect và đồng bộ trạng thái".

Lỗi thường gặp & mẹo

  • Lạm dụng WebSocket cho mọi thứ: Sai lầm phổ biến nhất. Thấy "real-time nghe sang" nên dùng WebSocket cả cho việc tải danh sách sản phẩm. Hậu quả là hệ thống phức tạp không cần thiết, khó debug, tốn tài nguyên. Mẹo: mặc định dùng REST, chỉ chuyển sang WebSocket khi có lý do rõ ràng về push hoặc tần suất.
  • Quên đặc tả vòng đời kết nối: Spec chỉ nói "real-time" mà không nói khi nào mở/đóng. Dev sẽ giữ kết nối mãi, hệ thống "ngốn" tài nguyên và sập khi lên quy mô. Mẹo: luôn trả lời được ba câu — mở khi nào, đóng khi nào, tần suất bao nhiêu.
  • Bỏ qua kịch bản mất kết nối: Mạng di động ở Việt Nam rớt sóng là chuyện thường (thang máy, hầm gửi xe, vùng phủ sóng yếu). Nếu spec không mô tả reconnect, trải nghiệm sẽ tệ và có thể gây rủi ro (như ví dụ giá crypto). Mẹo: coi "mất kết nối" là một trạng thái hợp lệ cần thiết kế, không phải ngoại lệ hiếm gặp.
  • Nhầm WebSocket với Webhook: Hai khái niệm nghe gần giống nhưng khác hẳn. WebSocket là kênh hai chiều giữa client (thường là trình duyệt/app) và server, giữ mở liên tục. Webhook là server gọi server qua HTTP một chiều khi có sự kiện (sẽ học ở bài riêng). Mẹo: WebSocket cho giao tiếp real-time với người dùng cuối; Webhook cho tích hợp giữa các hệ thống backend.
  • Không tính chi phí và giới hạn hạ tầng: Mỗi kết nối WebSocket chiếm một "slot" trên server. Một triệu người dùng online nghĩa là một triệu kết nối mở — đòi hỏi kiến trúc rất khác. Mẹo: luôn hỏi đội kỹ thuật về giới hạn kết nối đồng thời trước khi cam kết quy mô với stakeholder.
  • Giả định mọi mạng/firewall đều thông WebSocket: Một số mạng doanh nghiệp hoặc proxy cũ chặn kết nối WebSocket. Mẹo: với sản phẩm B2B, hỏi xem có cần phương án dự phòng (fallback) khi WebSocket bị chặn không.

Bài tập thực hành

  • Phân loại tình huống: Cho 6 tính năng sau, hãy đánh dấu cái nào nên dùng WebSocket, cái nào dùng REST, và viết một câu lý do cho mỗi cái: (a) thông báo "đơn hàng đã được duyệt" hiện ngay trên app; (b) tải lịch sử mua hàng của khách; (c) bảng điểm trận đấu bóng đá cập nhật trực tiếp; (d) đổi mật khẩu; (e) phòng chat hỗ trợ khách hàng; (f) xuất báo cáo doanh thu ra Excel.
  • Viết đặc tả vòng đời kết nối: Với tính năng "live tracking shipper" ở Ví dụ 2, hãy viết ra: kết nối mở khi nào, đóng khi nào, tần suất cập nhật, và cấu trúc JSON của một message location_update.
  • Thiết kế kịch bản mất kết nối: Cho dashboard giá crypto, hãy mô tả bằng lời (3–5 bước) điều gì xảy ra khi người dùng mất mạng 10 giây rồi có lại: client làm gì, hiển thị gì cho người dùng, và dữ liệu trong lúc mất mạng được xử lý ra sao.
  • Lập luận chọn công nghệ bằng con số: Giả sử app của bạn có 50.000 người dùng online, mỗi người polling mỗi 3 giây. Tính số request mỗi giây mà polling tạo ra, rồi viết một đoạn ngắn (3–4 câu) thuyết phục stakeholder tại sao nên chuyển sang WebSocket.

Tóm tắt

WebSocket sinh ra để giải quyết đúng một khoảng trống mà HTTP request–response không lấp được: giao tiếp hai chiều, thời gian thực, kết nối lâu dài giữa client và server. Nó bắt đầu bằng một cú bắt tay HTTP (status 101 Switching Protocols), dùng URL ws:// hoặc wss://, rồi giữ kết nối mở để hai bên đẩy message cho nhau bất cứ lúc nào — full-duplex như một cuộc gọi điện thoại.

Là BA, bạn không cần code WebSocket, nhưng bạn cần: nhận diện khi nào một tính năng thực sự cần real-time, biết so sánh nó với polling bằng con số cụ thể, và quan trọng nhất là đặc tả đủ ba thứ hay bị bỏ sót — khi nào mở kết nối, khi nào đóng, tần suất cập nhật — cộng thêm kịch bản mất kết nối. Hãy nhớ nguyên tắc vàng: mặc định dùng REST cho nhẹ, chỉ chọn WebSocket khi server thật sự cần chủ động "gõ cửa" client hoặc khi tần suất cập nhật vượt khả năng kham nổi của polling. Nắm chắc điều này, bạn sẽ giữ được thế chủ động trong mọi cuộc thảo luận kỹ thuật về các tính năng chat, tracking, hay dashboard thời gian thực.