34 điểm bởi GN⁺ 2024-12-26 | 5 bình luận | Chia sẻ qua WhatsApp

Server-Sent Events (SSE) bị đánh giá thấp

  • Hầu hết lập trình viên đều biết về WebSockets, nhưng SSE là một lựa chọn thay thế đơn giản hơn và thường bị bỏ qua.
  • SSE thiết lập một kênh giao tiếp một chiều từ máy chủ đến máy khách qua HTTP.
  • Khác với kết nối hai chiều của WebSockets, SSE duy trì một kết nối HTTP mở để gửi cập nhật từ máy chủ đến máy khách.

Vì sao SSE bị đánh giá thấp

  • Sự phổ biến của WebSocket: Khả năng giao tiếp song công hoàn toàn của WebSockets làm lu mờ cách tiếp cận đơn giản của SSE.
  • Nhận thức về các hạn chế: Tính chất một chiều có thể trông như một hạn chế, nhưng là đủ cho nhiều trường hợp sử dụng.

Những điểm mạnh chính của SSE

  1. Đơn giản trong triển khai

    • Tận dụng giao thức HTTP tiêu chuẩn, loại bỏ sự phức tạp của việc quản lý kết nối WebSocket.
  2. Tương thích hạ tầng

    • Hoạt động trơn tru với hạ tầng HTTP hiện có:
      • bộ cân bằng tải
      • proxy
      • tường lửa
      • máy chủ HTTP tiêu chuẩn
  3. Hiệu quả tài nguyên

    • Tiêu thụ tài nguyên thấp hơn so với WebSockets:
      • tính chất một chiều
      • sử dụng kết nối HTTP tiêu chuẩn
      • không cần duy trì socket liên tục
  4. Tự động kết nối lại

    • Hỗ trợ tích hợp sẵn của trình duyệt:
      • xử lý ngắt kết nối
      • tự động thử kết nối lại
      • trải nghiệm thời gian thực có độ bền cao
  5. Ngữ nghĩa rõ ràng

    • Mẫu giao tiếp một chiều đảm bảo:
      • phân tách mối quan tâm rõ ràng
      • luồng dữ liệu trực quan
      • logic ứng dụng được đơn giản hóa

Ứng dụng thực tiễn

  • bảng tin thời gian thực và cập nhật mạng xã hội
  • giá cổ phiếu và dữ liệu tài chính
  • thanh tiến trình và giám sát tác vụ
  • streaming log máy chủ
  • chỉnh sửa cộng tác (cho phần cập nhật)
  • bảng xếp hạng game
  • hệ thống theo dõi vị trí

Ví dụ triển khai

Phía máy chủ (Flask)
  • Tuyến /stream xử lý kết nối SSE.
  • generate_random_data() liên tục tạo ra các sự kiện đã được định dạng.
  • Kiểu MIME text/event-stream báo hiệu giao thức SSE.
  • stream_with_context duy trì application context của Flask.
Phía máy khách (JavaScript)
  • Đối tượng EventSource quản lý kết nối SSE.
  • Trình xử lý onmessage xử lý các sự kiện nhận được.
  • onerror xử lý các vấn đề kết nối.
  • Trình duyệt tự động xử lý việc kết nối lại.

Hạn chế và điểm cần cân nhắc

  1. Giao tiếp một chiều

    • Chỉ theo hướng từ máy chủ đến máy khách
    • Giao tiếp từ máy khách đến máy chủ cần các yêu cầu HTTP riêng biệt
  2. Hỗ trợ trình duyệt

    • Được hỗ trợ tốt trên các trình duyệt hiện đại
    • Có thể cần polyfill trên các trình duyệt cũ
  3. Định dạng dữ liệu

    • Chủ yếu hỗ trợ dữ liệu dạng văn bản
    • Dữ liệu nhị phân cần được mã hóa (ví dụ: Base64)

Thực tiễn tốt nhất

  • Xử lý lỗi

    • Xử lý lỗi kết nối bằng eventSource.onerror.
  • Quản lý kết nối

    • Dọn dẹp kết nối khi hoàn tất.
  • Chiến lược kết nối lại

    • Thiết lập số lần thử lại tối đa và triển khai logic kết nối lại.

Ví dụ thực tế: Cách ChatGPT triển khai

  • Các mô hình ngôn ngữ lớn (LLM) hiện đại sử dụng SSE để cung cấp phản hồi dạng streaming.
  • Các mẫu chính:
    • trả về header content-type: text/event-stream
    • streaming các khối dữ liệu được phân tách bằng \r\n\r\n

Kết luận

  • SSE mang lại một giải pháp thanh lịch cho giao tiếp thời gian thực giữa máy chủ và máy khách.
  • Tính đơn giản, hiệu quả và khả năng tích hợp với hạ tầng hiện có khiến nó trở thành lựa chọn phù hợp cho nhiều ứng dụng.
  • WebSockets vẫn hữu ích cho giao tiếp hai chiều, nhưng SSE mang đến một giải pháp tập trung và phù hợp hơn cho các kịch bản streaming dữ liệu một chiều.

5 bình luận

 
eususu 2024-12-27

Tôi đã thực sự dùng SSE khi triển khai OpenAI bằng REST.
Tôi chắc chắn sẽ áp dụng nó trong những tình huống cần giao tiếp một chiều.

 
galadbran 2024-12-27

SSE thường không bị các thiết bị bảo mật chặn như WAF hay hệ thống bảo mật thông minh, nhưng tôi khá hay gặp trường hợp không stream được theo từng ký tự xuống dòng. Kiểu như ở lớp trung gian (on-premise) nó nhận hết toàn bộ phản hồi rồi mới gửi ra một lần.

 
savvykang 2024-12-27

Thật đáng tiếc khi OpenAPI không hỗ trợ SSE.

 
alska1039 2024-12-26

Đây thực sự là một cách rất tốt để xây dựng giao tiếp hai chiều trong môi trường NAT.

 
GN⁺ 2024-12-26
Ý kiến Hacker News
  • Mercure là một giao thức mở dựa trên SSE, được dùng như giải pháp thay thế cho các giải pháp dựa trên WebSockets. Mercure hoạt động xoay quanh một hub độc lập duy trì kết nối SSE liên tục với client, đồng thời cung cấp một HTTP API đơn giản để ứng dụng máy chủ và client có thể sử dụng. Mercure bổ sung các tính năng như cơ chế xác thực dựa trên JWT, đăng ký nhiều chủ đề trên một kết nối duy nhất, ghi lại sự kiện và tự động điều chỉnh trạng thái khi xảy ra sự cố mạng

  • Nhược điểm lớn của SSE là có giới hạn số kết nối tối đa nếu không dùng HTTP/2. Đây có thể là vấn đề khi mở nhiều tab vì giới hạn trên mỗi trình duyệt khá thấp

  • Trong CLI của Doppler, SSE được dùng để triển khai tính năng tự động khởi động lại. SSE nhận sự kiện từ máy chủ, lấy thông tin bí mật mới nhất và đưa chúng vào tiến trình ứng dụng. Lý do chọn SSE thay vì WebSockets là để không thêm phụ thuộc bổ sung vào ứng dụng Golang. Để xử lý vấn đề timeout HTTP, họ phải gửi các sự kiện "ping" ngắt quãng

  • Tính một chiều của SSE có thể trông như một hạn chế, nhưng trong nhiều trường hợp là đủ dùng. Các hạn chế chính của SSE là chỉ hỗ trợ văn bản và giới hạn kết nối của trình duyệt trên HTTP/1.1. Nếu dùng HTTP/2 trở lên thì giới hạn kết nối không còn là vấn đề. Nếu hiệu năng là yếu tố quan trọng, có thể dùng fetch và ReadableStream để chọn một giải pháp linh hoạt hơn và ít overhead hơn

  • Vì SSE đơn giản, nhiều lập trình viên không dùng triển khai phù hợp mà lại phân tích các khối dữ liệu bằng biểu thức chính quy. Điều này có thể gây vấn đề vì SSE hỗ trợ comment trong stream

  • Data-star.dev là một thư viện frontend tập trung vào việc stream phản hồi hypermedia qua SSE. Nó được phát triển bằng Go và NATS ở phía backend, đồng thời tương thích với mọi triển khai SSE

  • SSE không hề bị đánh giá thấp. Trên thực tế, nó đang được Open AI dùng cho streaming completion. Việc triển khai SSE trong codebase ReactJS khá khó khăn, và vào thời điểm đó Axios không hỗ trợ nên phải dùng fetch gốc

  • Khi triển khai SSE trong một dự án web, nếu mở hơn 6 tab thì website ngừng hoạt động. Firefox tính kết nối SSE vào giới hạn tối đa 6 kết nối mỗi host, khiến các request bổ sung bị chặn

  • SSE bị đánh giá thấp khi nó hoạt động tốt. Trong dự án đang làm hiện tại, có nhiều khó khăn do vấn đề xác thực và vấn đề keep-alive của tunnel. Đây không phải lỗi của giao thức, nhưng rất khó tìm ra cách giải quyết