使用 WebSocket

本頁提供相關指引和最佳做法,說明如何在 Cloud Run 上執行 WebSocket 或其他串流服務,以及如何為這類服務編寫用戶端。

Cloud Run 支援 WebSocket 應用程序,無需額外配置。不過,WebSocket 串流是 HTTP 要求,仍須遵守為 Cloud Run 服務設定的要求逾時規定,因此您需要採取下列行動:

雖然 Cloud Run 上的工作階段相依性會盡可能提供相依性,但由於內建負載平衡功能,新的 WebSocket 要求仍有可能連線至不同執行個體。如要解決這個問題,請在執行個體之間同步處理資料

請注意,如果您使用 Cloud Load Balancing,Cloud Run 也支援 WebSocket。

部署範例 WebSocket 服務

使用 Cloud Shell 快速部署採用 WebSockets 的 Cloud Run 範例白板服務: 部署範例

或者,如要手動部署該範例白板服務,請按照下列步驟操作:

  1. 使用 git 指令列工具,在本機複製 Socket.IO 存放區:

    git clone https://github.com/socketio/socket.io.git
    
  2. 進入範例目錄:

    cd socket.io/examples/whiteboard/
    
  3. 使用 Google Cloud CLI 從原始碼建構服務,然後部署新的 Cloud Run 服務:

    gcloud run deploy whiteboard --allow-unauthenticated --source=.
    
  4. 服務部署完成後,請開啟兩個不同的瀏覽器分頁,並前往服務網址。由於用戶端透過 WebSockets 連線至相同執行個體,因此您在一個分頁中繪製的任何內容,都會傳播至另一個分頁 (反之亦然)。

WebSocket 即時通訊範例完整教學課程

如需完整程式碼逐步解說,請參閱「為 Cloud Run 教學課程建構 WebSocket Chat 服務」主題中的其他程式碼範例。

最佳做法

在 Cloud Run 上建立 WebSocket 服務時,最困難的部分是在多個 Cloud Run 執行個體之間同步處理資料。由於執行個體具有自動調度資源和無狀態的特性,加上並行要求逾時的限制,因此這項作業相當困難。

處理要求逾時和用戶端重新連線

在 Cloud Run 中,WebSocket 要求會視為長時間執行的 HTTP 要求。即使您的應用程式伺服器不強制執行任何逾時,它們也會受到 請求逾時 的限制(目前最長為 60 分鐘,預設為 5 分鐘)。

因此,如果用戶端保持連線的時間長於為 Cloud Run 服務設定的必要逾時時間,要求逾時時,用戶端就會中斷連線。

因此,連接到 Cloud Run 的 WebSocket 用戶端應該能夠處理請求逾時或伺服器斷開連接的情況,並重新連接到伺服器。 如要在以瀏覽器為基礎的用戶端中達成此目的,可以使用 reconnecting-websocket 等程式庫,或是在使用 SocketIO 程式庫時處理「disconnect」事件。

使用 WebSocket 時產生的費用

如果 Cloud Run 實例有 any 個開啟的 WebSocket 連接,則該實例被視為活動實例,因此會指派 CPU,並且該服務將按實例計費 計費

最大化並發性

WebSocket 服務通常設計為可同時處理多個連線。由於 Cloud Run 支援 並行連線(每個容器最多 1,000 個連線),如果您的服務能夠使用給定的資源處理負載,Google 建議您將容器的最大並行設定增加到比預設值更高的值。

關於固定式工作階段 (工作階段相依性)

由於 WebSocket 連線是有狀態的,因此在連線的整個生命週期內,用戶端都會保持與 Cloud Run 上同一容器的連線。這自然而然地在單一 WebSocket 連線的上下文中提供了會話黏性。

如要建立多個後續 WebSocket 連線,您可以將 Cloud Run 服務設定為使用工作階段相依性,但這項設定只能盡量提供相依性,因此 WebSocket 要求仍有可能導向不同執行個體。連線至 Cloud Run 服務的用戶端最終可能會由不同執行個體提供服務,這些執行個體不會協調或共用資料。

為解決這個問題,您需要使用外部資料儲存空間,在 Cloud Run 執行個體之間同步處理狀態,下一節將說明這項操作。

在執行個體之間同步處理資料

您需要同步處理資料,確保連線至 Cloud Run 服務的用戶端,透過 WebSockets 連線接收的資料相同。

舉例來說,假設您要使用 WebSocket 建構聊天室服務,並將並行連線數上限設定為 1,000。如果超過 1,000 個使用者同時連接到此服務,他們將由不同的實例提供服務,因此,他們將無法在聊天室中看到相同的訊息。

要同步 Cloud Run 執行個體之間的數據,例如從所有執行個體接收發布到聊天室的訊息,您需要一個外部資料儲存系統,例如資料庫或訊息佇列。

如果您使用 Cloud SQL 等外部資料庫,可以將訊息傳送至資料庫,並定期從資料庫輪詢。不過請注意,容器未處理任何要求時,Cloud Run 執行個體不會有 CPU。如果服務主要處理 WebSocket 要求,只要至少有一個用戶端連線至容器,系統就會為容器分配 CPU。

訊息佇列更適合用於即時同步處理 Cloud Run 容器之間的資料,因為外部訊息佇列無法向每個執行個體「推送」資料。您的服務需要透過與訊息佇列建立連接,從訊息佇列中「拉取」新訊息。

Google 建議您使用外部訊息佇列系統,例如 Redis Pub/Sub (Memorystore) 或 Firestore 即時更新,這些系統可以透過容器實例發起的連線將更新傳遞給所有實例。

使用 Redis 發布/訂閱

WebSocket 聊天室服務架構

您可以從 Memorystore 建立 Redis 執行個體,使用 Redis Pub/Sub 機制。如果您使用 Socket.IO 程式庫進行 WebSocket,可以採用其 Redis 配接器

在這個以 Redis 為基礎的架構中,每個 Cloud Run 執行個體都會與包含接收訊息的 Redis 管道建立長期連線 (使用 SUBSCRIBE 指令)。容器執行個體在管道上收到新訊息後,可以透過 WebSockets 即時傳送給用戶端。

同樣地,當用戶端使用 WebSocket 傳送訊息時,接收訊息的執行個體會將訊息發布至 Redis 管道 (使用 PUBLISH 指令),訂閱這個管道的其他執行個體就會收到這則訊息。

如需完整程式碼逐步解說,請參閱「為 Cloud Run 教學課程建構 WebSocket Chat 服務」主題中的其他程式碼範例。