SSE 繫結特定後端prod,後端prod優雅升級的相容

matengfei發表於2025-01-24

使用 Server-Sent Events(SSE)的 Go 服務在 Kubernetes (k8s) 上部署時,重點在於確保客戶端的連線能夠繫結到特定的後端 Pod,並在升級和更新時能夠優雅地處理。以下是針對你的需求的實現思路:


1. 客戶端與單個 Pod 的繫結

為了保證客戶端連線到一個固定的 Pod,可以使用 Session AffinitySticky Sessions

  • Session Affinity (基於IP)

    • Kubernetes 的 Service 預設是無狀態的,即負載均衡器會將流量隨機分發到後端 Pod。
    • 配置 Service 的 SessionAffinityClientIP,這樣 Kubernetes 會基於客戶端的 IP 地址,將流量始終分發到同一個 Pod。
    apiVersion: v1
    kind: Service
    metadata:
      name: sse-service
    spec:
      selector:
        app: sse-app
      sessionAffinity: ClientIP
      ports:
        - port: 80
          targetPort: 8080

    缺點:如果 Pod 因為升級或擴容而銷燬,客戶端會重新被分配到其他 Pod,需要重連。
  • 透過負載均衡器(例如 Ingress/Nginx)實現 Sticky Session: 如果你的應用使用了外部負載均衡器(如 NGINX Ingress Controller),可以透過它支援的 Sticky Session 特性來繫結客戶端和 Pod。例如:

    • 對於 NGINX,可以啟用 nginx.ingress.kubernetes.io/affinity: cookie

2. K8s 的優雅退出與升級

在升級或重啟 Pod 時,SSE 的連線中斷會導致客戶端需要重新連線。為了實現優雅退出和升級,可以做以下操作:

(1) 確保 Pod 優雅退出

  • 配置 Pod 的 preStop 生命週期鉤子,處理服務關閉邏輯:

    • 在 Pod 中配置一個 preStop Hook,通知應用有新的流量即將終止,允許應用清理資源。
    lifecycle:
      preStop:
        exec:
          command: ["/bin/sh", "-c", "sleep 10"]  # 模擬10秒的延遲關閉

  • 配置 terminationGracePeriodSeconds,確保 Pod 有足夠時間完成清理:

    spec:
      terminationGracePeriodSeconds: 30

(2) 啟用 Kubernetes 的滾動更新

透過 Deployment 配置滾動更新策略,確保升級時服務的可用性:

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1
    maxSurge: 1


3. 客戶端是否需要重連?

  • 重連的必要性:如果 Pod 被銷燬或者負載均衡器將流量切到其他 Pod,客戶端連線會中斷,因此需要支援自動重連邏輯。

  • 實現自動重連

    • 在客戶端的 SSE 程式碼中實現斷線重連(一般使用 EventSourceonerrorsetTimeout 機制):
      const connectSSE = () => {
        const eventSource = new EventSource('https://your-sse-url');
      
        eventSource.onmessage = (event) => {
          console.log('Message:', event.data);
        };
      
        eventSource.onerror = (error) => {
          console.error('Error:', error);
          eventSource.close();
          // 斷線後嘗試重連
          setTimeout(connectSSE, 3000); // 延遲 3 秒重連
        };
      };
      
      connectSSE();

  • 減小重連影響:在服務端實現連線恢復機制,比如透過快取(Redis)儲存客戶端的狀態,重連後快速恢復狀態。


4. 總結

  • 客戶端繫結單 Pod
    • 優先使用 Kubernetes 的 SessionAffinity 或者外部負載均衡器的 Sticky Session 特性。
  • 優雅退出與升級
    • 使用 preStop 鉤子和滾動更新策略,避免客戶端頻繁重連。
  • 自動重連機制
    • 在客戶端實現斷線重連邏輯,同時在服務端快取狀態,減少重連對服務的影響。

這樣既能實現客戶端與單個 Pod 的繫結,也能在升級和退出時最大程度減少對客戶端的影響。如果還有其他需求或細節,歡迎繼續討論!

相關文章