Chương 22. Chọn Cách Giao Tiếp Đúng
Từ chương 17 đến chương 21, ta đã đi qua khá nhiều cách giao tiếp:
- HTTP/API.
- Queue.
- Pub/Sub.
- Event Streaming.
- Webhook.
- Polling.
- SSE.
- WebSocket.
Nếu nhìn riêng từng món, chúng đều có vẻ hợp lý.
Nhưng khi thiết kế hệ thống thật, câu hỏi không phải là:
> Công nghệ nào hay nhất?
Câu hỏi đúng hơn là:
> Với việc này, bên nào cần nói với bên nào, cần kết quả nhanh đến đâu, có được xử lý sau không, có bao nhiêu bên cần biết, và nếu lỗi thì sao?
Chọn cách giao tiếp đúng không bắt đầu từ tên công nghệ.
Nó bắt đầu từ bản chất của việc cần làm.
Ví dụ AI Judge:
Học viên nộp bài
-> cần trả response nhanh
-> tạo job chấm nền
-> worker gọi Gemini
-> lưu kết quả
-> frontend biết kết quả
-> learning/notification/analytics cùng phản ứng
Trong một luồng này, ta có thể dùng nhiều cách giao tiếp:
Frontend -> Backend: HTTP API
Backend -> Worker: Queue
Worker -> Gemini: HTTP API
GradingCompleted -> nhiều bên: Pub/Sub/Event
Frontend xem kết quả: Polling hoặc SSE
Không có một công cụ duy nhất giải quyết mọi thứ.
Thiết kế tốt là biết đặt từng công cụ vào đúng chỗ.
---
22.1. Câu hỏi đầu tiên: có cần kết quả ngay không?
Đây là câu hỏi quan trọng nhất.
Nếu bên gọi cần kết quả ngay để tiếp tục, thường dùng HTTP/API hoặc một kiểu request/response tương tự.
Ví dụ:
Frontend cần đăng nhập.
Frontend cần lấy danh sách bài học.
Admin cần xem chi tiết đơn.
Backend cần lấy payment_url để redirect user.
Những việc này cần câu trả lời ngay.
Client -> API -> Response
Nhưng nếu việc lâu và không cần kết quả cuối ngay, đừng bắt request chờ.
Ví dụ:
Chấm bài AI 90 giây.
Tạo báo cáo 2 phút.
Resize video.
Gửi email hàng loạt.
Đồng bộ CRM.
Khi đó:
HTTP nhận yêu cầu
-> tạo job
-> đưa vào queue
-> trả job_id
Một câu nhớ nhanh:
> Cần câu trả lời ngay thì API. Cần làm lâu thì queue.
---
22.2. Câu hỏi thứ hai: đây là việc cần làm hay sự kiện đã xảy ra?
Nếu message có nghĩa:
Hãy làm việc này.
thì nó giống command/job.
Ví dụ:
RunGradingJob
SendEmail
GenerateReport
ResizeImage
SyncCustomerToCrm
Queue thường phù hợp.
Nếu message có nghĩa:
Việc này đã xảy ra.
thì nó là event.
Ví dụ:
OrderPlaced
PaymentSucceeded
GradingCompleted
DeliveryFailed
RefundIssued
Pub/Sub hoặc Event Streaming thường phù hợp nếu nhiều bên cần biết.
Đừng đặt tên event như job.
Không tốt:
SendEmail
UpdateAnalytics
CreateInvoice
Tốt hơn:
OrderPlaced
PaymentSucceeded
GradingCompleted
Rồi consumer tự quyết định gửi email, cập nhật analytics, tạo invoice.
---
22.3. Câu hỏi thứ ba: có bao nhiêu bên cần biết?
Nếu chỉ có một worker cần xử lý một việc:
RunGradingJob(job_123)
dùng queue.
Nếu nhiều bên cùng cần phản ứng với một sự kiện:
GradingCompleted
dùng Pub/Sub hoặc Event Streaming.
Ví dụ:
GradingCompleted
-> Learning cập nhật tiến độ
-> Notification báo học viên
-> Analytics ghi chi phí AI
-> Certificate kiểm tra điều kiện cấp chứng chỉ
Nếu RunGradingJob bị hai worker xử lý cùng lúc, có thể là lỗi.
Nếu GradingCompleted được nhiều consumer xử lý, đó là mục tiêu.
Một câu nhớ:
> Một việc cho một nhóm worker: queue. Một sự kiện cho nhiều bên nghe: Pub/Sub.
---
22.4. Câu hỏi thứ tư: có cần lưu lịch sử và replay không?
Nếu event chỉ cần báo cho các bên hiện tại xử lý, Pub/Sub bền có thể đủ.
Nếu event cần trở thành lịch sử để:
- Consumer mới đọc lại.
- Rebuild read model.
- Tính lại analytics.
- Rebuild search index.
- Lưu vào data lake.
- Replay sau khi sửa bug.
thì nghĩ đến Event Streaming.
Ví dụ:
ProductUpdated
-> search index cập nhật
Nếu index hỏng và bạn muốn đọc lại toàn bộ lịch sử product event để rebuild, event streaming hữu ích.
Ví dụ AI Judge:
GradingCompleted
Ban đầu chỉ cần notification và learning update.
Pub/Sub có thể đủ.
Sau này muốn phân tích:
- Mỗi lớp tốn bao nhiêu chi phí AI.
- Rubric nào gây lỗi nhiều.
- Thời gian chấm trung bình theo model.
- Điểm trung bình theo assignment.
Lúc đó event stream lịch sử có giá trị hơn.
Nhưng nếu chưa cần replay, đừng vội Kafka.
---
22.5. Câu hỏi thứ năm: client cần cập nhật trạng thái kiểu gì?
Khi frontend cần biết một việc đã xong, có vài lựa chọn.
Nếu đơn giản:
Polling
Frontend hỏi định kỳ.
Ví dụ:
GET /grading-jobs/{id}
Nếu muốn server đẩy một chiều:
SSE
Ví dụ server báo:
grading_completed
Nếu cần hai chiều realtime:
WebSocket
Ví dụ chat, game, collaborative editor.
Một câu nhớ:
> Job status thường bắt đầu bằng polling. Cần mượt hơn thì SSE. Cần hai chiều realtime thật thì WebSocket.
---
22.6. Câu hỏi thứ sáu: đây là server-to-server callback không?
Nếu một hệ thống ngoài cần báo lại cho backend của ta, thường dùng webhook.
Ví dụ:
Payment Gateway -> Backend: payment_succeeded
Delivery Provider -> Backend: delivery_failed
GitHub -> CI System: push event
AI Judge Service -> Main App: grading_completed
Webhook nghĩa là:
> Bên kia làm xong hoặc có sự kiện, rồi gọi HTTP về endpoint của ta.
Webhook cần:
- Verify signature.
- Idempotency.
- Log raw event.
- Trả response nhanh.
- Retry/DLQ nếu xử lý sau.
- Reconciliation nếu nghiệp vụ quan trọng.
Không dùng WebSocket cho chuyện này.
Webhook là server gọi server.
WebSocket là client-server giữ kết nối realtime hai chiều.
---
22.7. Một bản đồ quyết định nhanh
| Nhu cầu | Lựa chọn thường hợp | |---|---| | Cần dữ liệu ngay để hiển thị | HTTP API | | Cần thực hiện command ngắn | HTTP API | | Việc lâu, xử lý sau | Queue | | Một job chỉ một worker xử lý | Queue | | Một sự kiện nhiều bên cần biết | Pub/Sub | | Event quan trọng không được mất | Durable Pub/Sub + outbox | | Cần lưu lịch sử/replay | Event Streaming | | Frontend kiểm tra job xong chưa | Polling | | Frontend nhận update một chiều | SSE | | Client-server realtime hai chiều | WebSocket | | Hệ thống ngoài báo lại cho ta | Webhook | | Dữ liệu đọc tổng hợp từ nhiều service | Read model, có thể build bằng event | | Analytics từ nhiều sự kiện | Event Streaming hoặc event pipeline |
Bảng này không thay thế suy nghĩ.
Nó chỉ giúp ta không chọn sai quá sớm.
---
22.8. Ví dụ 1: nộp bài AI
Yêu cầu:
Học viên nộp bài.
Bài cần chấm bằng AI.
Chấm mất khoảng 90 giây.
Học viên cần xem kết quả khi xong.
Learning, Notification, Analytics cũng cần biết.
Thiết kế hợp lý:
Frontend -> Backend:
HTTP POST /submissions
Backend:
tạo Submission
tạo GradingJob(PENDING)
enqueue RunGradingJob
trả 202 Accepted + job_id
Worker:
lấy job từ queue
gọi Gemini API
lưu kết quả
phát GradingCompleted
Frontend:
polling GET /grading-jobs/{id}
hoặc SSE nhận grading_completed
Consumers:
Learning nghe GradingCompleted
Notification nghe GradingCompleted
Analytics nghe GradingCompleted
Ở đây:
- HTTP dùng để nhận request và đọc trạng thái.
- Queue dùng cho việc chấm lâu.
- Pub/Sub dùng cho nhiều bên phản ứng sau khi chấm xong.
- Polling/SSE dùng cho frontend.
- Database lưu trạng thái thật.
Không nên:
Frontend POST /submit
-> Backend chờ Gemini 90 giây
-> Backend cập nhật learning, gửi email, analytics trong cùng request
Vì request quá lâu và quá nhiều việc phụ dính vào nhau.
---
22.9. Ví dụ 2: thanh toán đơn hàng
Yêu cầu:
Khách checkout.
Cần tạo payment.
Payment gateway sẽ báo kết quả.
Order, Accounting, Notification cần biết khi thanh toán thành công.
Thiết kế hợp lý:
Frontend -> Backend:
POST /checkout
Backend:
tạo Order
tạo PaymentIntent qua Payment Gateway
trả payment_url
Payment Gateway:
gọi webhook /webhooks/payment
Backend webhook:
verify signature
lưu event/payment state
phát PaymentSucceeded
Consumers:
Ordering cập nhật Order = PAID
Accounting ghi doanh thu
Notification gửi biên nhận
Frontend có thể:
Polling GET /orders/{id}
hoặc được redirect về trang kết quả
hoặc nhận SSE/WebSocket notification nếu có
Không nên tin frontend nói:
Tôi thanh toán rồi.
Trạng thái payment phải đến từ webhook đã verify hoặc query provider để đối soát.
---
22.10. Ví dụ 3: gửi email xác nhận
Yêu cầu:
Sau khi user đăng ký, gửi email chào mừng.
Nếu hệ thống nhỏ:
RegisterUserUseCase
-> tạo user
-> enqueue SendWelcomeEmail
Queue là đủ.
Nếu nhiều bên cũng cần biết user mới:
UserRegistered
-> Email
-> Analytics
-> CRM
-> Recommendation
Pub/Sub hợp hơn.
Email consumer có thể tạo job:
UserRegistered
-> enqueue SendWelcomeEmail
Không cần Event Streaming nếu không cần replay lịch sử user event.
Nếu sau này analytics cần phân tích toàn bộ hành vi user, event stream có thể xuất hiện.
---
22.11. Ví dụ 4: dashboard realtime
Yêu cầu:
Admin muốn xem số đơn, doanh thu, lỗi payment gần realtime.
Nếu cập nhật mỗi 30 giây là đủ:
Polling
Nếu muốn server đẩy số liệu mỗi vài giây:
SSE
Nếu dashboard có tương tác hai chiều phức tạp:
WebSocket
Dữ liệu phía sau có thể đến từ:
Events -> analytics/read model -> dashboard API/SSE
Không nên để dashboard trực tiếp kéo dữ liệu nặng từ nhiều service mỗi giây nếu có nhiều admin mở cùng lúc.
---
22.12. Ví dụ 5: chat
Yêu cầu:
Hai người nhắn tin realtime.
Typing indicator.
Online/offline.
Read receipt.
WebSocket thường phù hợp.
Luồng:
Client A -> WebSocket -> Server: message
Server -> lưu message DB
Server -> WebSocket -> Client B: message mới
Nếu nhiều server:
Pub/Sub backend để fanout đến server đang giữ connection
Nhưng message vẫn cần lưu database.
WebSocket chỉ là kênh realtime.
Nó không thay thế storage.
---
22.13. Ví dụ 6: cập nhật search index
Yêu cầu:
Khi product thay đổi, search index phải cập nhật.
Nếu đơn giản:
ProductUpdated
-> Search consumer cập nhật index
Pub/Sub bền có thể đủ.
Nếu cần rebuild index từ lịch sử event:
Product events stream
-> replay để build lại index
Event Streaming hữu ích.
Search index là read model, không phải nguồn sự thật.
Nếu index lỗi, có thể rebuild từ database hoặc replay event nếu lịch sử đủ.
---
22.14. Đừng dùng HTTP cho mọi thứ
HTTP dễ hiểu nên rất dễ bị lạm dụng.
Ví dụ xấu:
Order API
-> Payment API
-> Accounting API
-> Notification API
-> Analytics API
-> CRM API
Tất cả nằm trên đường request checkout.
Hậu quả:
- Request chậm.
- Một service phụ lỗi làm luồng chính lỗi.
- Retry khó.
- Timeout dây chuyền.
- Debug khó.
Cách tốt hơn:
Checkout làm phần cần thiết ngay.
Các phản ứng phụ đi qua event/queue.
HTTP nên dùng cho câu hỏi hoặc command cần kết quả ngay.
Không nên dùng để kéo mọi việc phụ vào cùng một request.
---
22.15. Đừng dùng Queue cho mọi thứ
Queue cũng dễ bị lạm dụng.
Ví dụ xấu:
LoginRequest -> Queue -> Worker -> LoginResult
Login cần kết quả ngay.
Queue làm trải nghiệm kỳ quặc.
Hoặc:
GET product detail -> Queue
Không hợp.
Queue dùng cho việc nền, không dùng cho truy vấn dữ liệu trực tiếp.
Một câu nhớ:
> Queue tốt cho "làm sau", không tốt cho "trả lời ngay".
---
22.16. Đừng dùng Pub/Sub để giấu luồng nghiệp vụ
Pub/Sub giúp giảm coupling, nhưng cũng có thể làm luồng khó lần theo.
Ví dụ:
EventA -> Handler1 -> EventB -> Handler2 -> EventC -> Handler3
Không ai nhìn được toàn bộ checkout flow.
Nếu luồng dài và quan trọng, có thể cần:
- Workflow/Saga rõ.
- Event catalog.
- Trace theo correlation_id.
- Dashboard trạng thái.
- Documentation luồng.
Pub/Sub không thay thế thiết kế use case.
Nó chỉ là cách các phần phản ứng với sự kiện.
---
22.17. Đừng dùng Event Streaming quá sớm
Event Streaming mạnh, nhưng không nhẹ.
Nếu hệ thống chỉ có:
- Vài job nền.
- Một vài event.
- Không cần replay.
- Không có analytics lớn.
- Team chưa vận hành broker.
thì Kafka hoặc streaming platform có thể quá sớm.
Bắt đầu bằng:
Database + Queue + Outbox + Pub/Sub bền đơn giản
có thể đủ tốt.
Khi thật sự cần:
- Nhiều consumer.
- Lịch sử event.
- Replay.
- Data pipeline.
- Analytics realtime.
lúc đó Event Streaming đáng giá hơn.
---
22.18. Đừng dùng WebSocket khi Polling đủ
WebSocket nghe có vẻ hiện đại.
Nhưng nó kéo theo:
- Connection lâu dài.
- Reconnect.
- Heartbeat.
- Auth theo channel.
- Scale nhiều server.
- Pub/Sub backend.
- Monitoring connection.
Nếu việc chỉ là:
Job xong chưa?
Polling mỗi 3-5 giây thường đủ.
Nếu muốn mượt hơn, SSE là bước giữa tốt.
WebSocket nên dành cho:
- Chat.
- Collaboration.
- Game.
- Presence.
- Tương tác hai chiều realtime thật.
---
22.19. Một luồng có thể dùng nhiều cách giao tiếp
Đừng cố ép toàn bộ hệ thống dùng một kiểu.
Ví dụ đặt bánh:
Frontend -> API:
HTTP POST /orders
Backend -> Payment:
HTTP để tạo payment_url
Payment Gateway -> Backend:
Webhook báo payment succeeded
Backend:
publish PaymentSucceeded
Consumers:
Ordering, Accounting, Notification nghe event
Notification:
enqueue SendEmail
nếu user online, gửi SSE/WebSocket signal
Frontend:
polling hoặc SSE để thấy trạng thái order
Mỗi đoạn có bản chất khác nhau.
Vì vậy mỗi đoạn có công cụ khác nhau.
Kiến trúc tốt không phải là dùng ít tên công nghệ nhất.
Kiến trúc tốt là mỗi đoạn dùng đúng công cụ cho nhu cầu của nó.
---
22.20. Luôn hỏi về lỗi
Chọn giao tiếp đúng phải hỏi:
> Nếu bên kia lỗi thì sao?
Với HTTP:
- Timeout bao lâu?
- Retry không?
- Có idempotency không?
- Có fallback không?
Với Queue:
- Retry mấy lần?
- DLQ ở đâu?
- Job có idempotent không?
- Backlog tăng thì sao?
Với Pub/Sub:
- Event có mất không?
- Consumer fail thì sao?
- Event trùng thì sao?
- Lag có được đo không?
Với Webhook:
- Verify signature chưa?
- Provider retry thì sao?
- Event đến sai thứ tự thì sao?
- Có reconciliation không?
Với SSE/WebSocket:
- Mất connection thì sao?
- Client bỏ lỡ event thì đồng bộ lại thế nào?
- Có API lấy state hiện tại không?
Một thiết kế giao tiếp chưa nói về lỗi là thiết kế chưa xong.
---
22.21. Luôn hỏi về nguồn sự thật
Trong hệ thống nhiều cách giao tiếp, dễ bị mờ nguồn sự thật.
Ví dụ:
Payment status thật nằm ở đâu?
Order status thật nằm ở đâu?
Grading result thật nằm ở đâu?
Notification đã đọc thật nằm ở đâu?
Realtime message không nên là nguồn sự thật duy nhất.
Queue message không nên là nguồn sự thật duy nhất nếu job cần trạng thái.
Event stream có thể là lịch sử, nhưng trạng thái hiện tại thường vẫn cần read model/database.
Hãy luôn trả lời:
> Nếu mọi connection mất, mọi consumer restart, user mở lại sau 1 giờ, hệ thống đọc trạng thái thật từ đâu?
Câu trả lời thường là:
Database hoặc read model bền vững.
---
22.22. Luôn hỏi về độ trễ chấp nhận được
Không phải mọi thứ cần realtime.
Ví dụ:
Payment confirmation: càng nhanh càng tốt, vài giây.
AI grading: vài phút có thể chấp nhận tùy sản phẩm.
Analytics dashboard: chậm 1-5 phút có thể ổn.
Email marketing: chậm 30 phút có thể ổn.
Typing indicator: cần rất nhanh nhưng mất cũng không sao.
Độ trễ quyết định công cụ.
Nếu chậm vài giây được:
Polling/Queue/Eventual consistency
Nếu phải gần realtime một chiều:
SSE/PubSub
Nếu phải hai chiều:
WebSocket
Nếu phải đúng ngay trong cùng thao tác:
HTTP/API + transaction cục bộ
---
22.23. Luôn hỏi về độ quan trọng
Cùng là message, nhưng mức quan trọng khác nhau.
Ví dụ:
PaymentSucceeded
Không được mất.
Cần outbox, durable broker, idempotency, reconciliation.
UserTyping
Mất cũng không sao.
Có thể dùng Pub/Sub tạm thời hoặc WebSocket signal.
Analytics event
Tùy hệ thống, có thể mất một ít hoặc cần rất chắc.
Không nên dùng cùng một mức độ bảo đảm cho mọi thứ.
Việc quan trọng cần bền và có đối soát.
Việc tạm thời cần nhanh và nhẹ.
---
22.24. Luôn hỏi về scale
Một lựa chọn đúng ở 100 user có thể sai ở 1 triệu user.
Polling mỗi 5 giây với 100 user:
20 request/giây
Ổn.
Polling mỗi 1 giây với 1 triệu user:
1.000.000 request/giây
Không ổn.
WebSocket với 1.000 connection khác WebSocket với 1 triệu connection.
Queue với 100 job/ngày khác queue với 1 triệu job/giờ.
Event streaming chỉ đáng khi volume và nhu cầu dữ liệu xứng đáng.
Đừng thiết kế quá lớn từ đầu, nhưng cũng đừng bỏ qua con số.
---
22.25. Bảng so sánh tổng hợp
| Cách | Dùng khi | Tránh khi | Rủi ro chính | |---|---|---|---| | HTTP/API | Cần kết quả ngay, query, command ngắn | Việc lâu, nhiều phản ứng phụ | Timeout, retry, gọi dây chuyền | | Queue | Việc lâu, retry, kiểm soát concurrency | Cần response ngay | Backlog, duplicate, job kẹt | | Pub/Sub | Một event nhiều bên nghe | Luồng đơn giản một consumer | Khó debug, event mất nếu không bền | | Event Streaming | Cần lịch sử, replay, analytics | Hệ thống nhỏ, không cần replay | Vận hành, schema, lag, replay sai | | Webhook | Server ngoài báo lại | Frontend realtime | Giả mạo, duplicate, sai thứ tự | | Polling | Client kiểm tra trạng thái đơn giản | Cần realtime cao, user cực lớn | Tốn request | | SSE | Server push một chiều | Cần hai chiều liên tục | Connection lâu, proxy buffering | | WebSocket | Hai chiều realtime | Chỉ job status đơn giản | Scale connection, reconnect, auth |
---
22.26. Bảng quyết định theo câu hỏi
| Câu hỏi | Nếu câu trả lời là có | Thường chọn | |---|---|---| | Người gọi cần câu trả lời ngay? | Có | HTTP/API | | Việc mất lâu? | Có | Queue | | Chỉ một worker nên xử lý? | Có | Queue | | Nhiều bên cần biết một sự kiện? | Có | Pub/Sub | | Cần đọc lại lịch sử event? | Có | Event Streaming | | Bên ngoài cần gọi báo về? | Có | Webhook | | Frontend chỉ cần kiểm tra job status? | Có | Polling | | Server cần đẩy update một chiều? | Có | SSE | | Client/server nói chuyện liên tục hai chiều? | Có | WebSocket | | Message không được mất? | Có | Durable broker + outbox | | Message có thể trùng? | Gần như luôn có | Idempotency |
---
22.27. Một checklist trước khi chốt thiết kế
Trước khi chọn cách giao tiếp, hãy hỏi:
- Ai là bên gửi?
- Ai là bên nhận?
- Đây là command, query, job hay event?
- Có cần response ngay không?
- Có thể xử lý sau không?
- Có bao nhiêu consumer?
- Có cần lưu lịch sử không?
- Có cần replay không?
- Có cần realtime UI không?
- Một chiều hay hai chiều?
- Nếu message mất thì hậu quả gì?
- Nếu message trùng thì sao?
- Nếu xử lý chậm thì sao?
- Nếu bên nhận down thì sao?
- Nguồn sự thật nằm ở đâu?
- Trạng thái hiện tại đọc từ đâu?
- Có cần retry, DLQ, reconciliation không?
- Có cần idempotency không?
- Có cần observability gì?
Nếu trả lời được, chọn công cụ sẽ dễ hơn rất nhiều.
---
22.28. Tóm tắt bằng một câu chuyện
Hãy lấy một hệ thống học online có AI Judge.
Học viên nộp bài:
HTTP API
Chấm bài mất 90 giây:
Queue
Worker gọi Gemini:
HTTP API ra external provider
Chấm xong:
GradingCompleted event
Learning, Notification, Analytics cùng cần biết:
Pub/Sub
Analytics muốn phân tích lịch sử:
Event Streaming nếu scale đủ lớn
Frontend cần xem trạng thái:
Polling trước, SSE nếu muốn mượt hơn
AI Judge tách service riêng báo về Main App:
Webhook hoặc event integration
Chat giữa học viên và mentor:
WebSocket
Cùng một sản phẩm, nhiều cách giao tiếp cùng tồn tại.
Đó là bình thường.
Quan trọng là mỗi cách nằm đúng chỗ.
---
22.29. Kết luận của chương
Chọn cách giao tiếp đúng là một kỹ năng kiến trúc rất quan trọng.
Không có công cụ nào thắng mọi trường hợp.
HTTP/API rõ ràng và trực tiếp, nhưng không nên ôm việc lâu.
Queue giúp xử lý nền, retry và kiểm soát concurrency, nhưng làm hệ thống bất đồng bộ hơn.
Pub/Sub giúp nhiều bên phản ứng với một sự kiện, nhưng cần idempotency và observability.
Event Streaming mạnh khi cần lịch sử và replay, nhưng không nên dùng quá sớm.
Webhook rất hợp cho server-to-server callback, nhưng phải verify và xử lý trùng.
Polling đơn giản và đủ tốt trong nhiều trường hợp.
SSE hợp với server push một chiều.
WebSocket hợp với realtime hai chiều thật sự.
Thông điệp quan trọng nhất:
> Đừng hỏi "nên dùng công nghệ nào?". Hãy hỏi "việc này cần giao tiếp theo kiểu nào?".
Khi hiểu bản chất của việc cần làm, lựa chọn công nghệ sẽ bớt mơ hồ hơn rất nhiều.
Và khi chọn đúng cách giao tiếp, hệ thống không chỉ chạy được, mà còn dễ debug, dễ mở rộng, dễ vận hành, và dễ giải thích cho người khác.