本頁面提供在 Cloud Run 上執行 WebSocket 或其他串流服務,以及為這類服務編寫用戶端的指引和最佳做法。
Cloud Run 支援 WebSocket 應用程式,且不需要額外設定。不過,WebSockets 串流是 HTTP 要求,仍會受到為 Cloud Run 服務設定的要求逾時限制,因此您需要執行以下操作:
- 將要求逾時時間增加至您希望 WebSocket 串流保持開啟的最長時間,例如 60 分鐘。
- 確保客戶能夠重新連線。
- 建議您使用工作階段相依性,讓用戶端盡可能重新連線至相同的例項。
- 請勿啟用 HTTP/2 端對端。
雖然 Cloud Run 上的工作階段相依性可提供最佳相依性,但由於內建負載平衡功能,新的 WebSocket 要求仍可能連線至不同的執行個體。如要解決這個問題,您需要在執行個體之間同步處理資料。
請注意,如果您使用Cloud Load Balancing,Cloud Run 也支援 WebSocket。
部署 WebSockets 服務範例
使用 Cloud Shell 快速部署使用 WebSockets 的白板服務範例,並搭配 Cloud Run:部署範例
或者,如果您想手動部署範例白板服務,請按照下列步驟操作:
使用 git 指令列工具在本機複製 Socket.IO 存放區:
git clone https://github.com/socketio/socket.io.git
前往範例目錄:
cd socket.io/examples/whiteboard/
使用 Google Cloud CLI 從原始碼建構服務,部署新的 Cloud Run 服務:
gcloud run deploy whiteboard --allow-unauthenticated --source=.
服務部署完成後,請開啟兩個不同的瀏覽器分頁,然後前往服務網址。由於用戶端會透過 WebSockets 連線至相同的執行個體,因此您在一個分頁中繪製的任何內容都會傳播至其他分頁 (反之亦然)。
WebSocket 即時通訊範例完整教學
如需完整的程式碼示範,請參閱「為 Cloud Run 建構 WebSocket 聊天服務」一文,瞭解其他程式碼範例。
最佳做法
在 Cloud Run 上建立 WebSockets 服務最困難的部分,就是在多個 Cloud Run 執行個體之間同步處理資料。由於執行個體的自動調度資源和無狀態特性,以及並行處理和要求逾時的限制,因此這項工作相當困難。
處理要求逾時和用戶端重新連線
WebSocket 要求會在 Cloud Run 中視為長時間執行的 HTTP 要求。即使應用程式伺服器未強制執行任何逾時,這些要求仍會受到要求逾時 (目前最多為 60 分鐘,預設為 5 分鐘) 的影響。
因此,如果用戶端連線時間超過為 Cloud Run 服務設定的必要逾時時間,要求會在逾時時中斷用戶端的連線。
因此,如果要求逾時或伺服器中斷連線,連線至 Cloud Run 的 WebSockets 用戶端應處理重新連線至伺服器的作業。您可以在瀏覽器用戶端中使用 reconnecting-websocket 等程式庫,或在使用 SocketIO 程式庫時處理「斷線」事件,以達到這個目的。
使用 WebSocket 時產生的帳單費用
有任何開放式 WebSocket 連線的 Cloud Run 執行個體會視為處於活動狀態,因此會分配 CPU,並以「以執行個體為基礎」的計費方式收費。
盡量提高並行性
WebSocket 服務通常設計用於同時處理多個連線。由於 Cloud Run 支援並行連線 (每個容器最多 1000 個),如果您的服務能夠透過指定資源處理負載,Google 建議您將容器的並行設定上限提高至高於預設值的值。
關於固定式工作階段 (工作階段相依性)
由於 WebSocket 連線具有狀態,因此在連線的整個生命週期中,用戶端都會與 Cloud Run 上的相同容器保持連線。這麼做自然會在單一 WebSocket 連線的情況下提供工作階段黏性。
如要使用多個 WebSocket 連線和後續連線,您可以設定 Cloud Run 服務使用工作階段相依性,但這會提供盡力相依性,因此 WebSocket 要求仍可能會結束於不同的例項。連線至 Cloud Run 服務的用戶端可能會由不協調或共用資料的不同執行個體提供服務。
為避免這種情況,您必須使用外部資料儲存空間,在 Cloud Run 執行個體之間同步狀態,詳情請參閱下一節。
在執行個體之間同步處理資料
您需要同步處理資料,確保連線至 Cloud Run 服務的用戶端會從 WebSockets 連線接收相同的資料。
舉例來說,假設您使用 WebSocket 建構聊天室服務,並將並行作業數上限設定設為 1000
。如果有超過 1000
位使用者同時連線至這項服務,系統會透過不同的例項提供服務,因此他們無法在聊天室中看到相同的訊息。
如要在 Cloud Run 執行個體之間同步處理資料 (例如接收所有執行個體在聊天室中發布的訊息),您需要使用外部資料儲存系統,例如資料庫或訊息佇列。
如果您使用 Cloud SQL 等外部資料庫,可以將訊息傳送至資料庫,並定期從資料庫輪詢。不過,請注意,當容器未處理任何要求時,Cloud Run 執行個體不會有 CPU。如果您的服務主要處理 WebSocket 要求,只要有至少一個用戶端連線至容器,容器就會分配 CPU。
訊息佇列可更有效地在 Cloud Run 容器之間即時同步處理資料,因為外部訊息佇列無法針對每個執行個體處理「推送」資料。您的服務必須建立與訊息佇列的連線,才能「提取」訊息佇列中的新訊息。
Google 建議您使用外部訊息佇列系統,例如 Redis Pub/Sub (Memorystore) 或 Firestore 即時更新,這些系統可透過容器執行個體啟動的連線,將更新內容傳送至所有執行個體。
使用 Redis Pub/Sub
您可以使用 Redis Pub/Sub 機制,透過 Memorystore 建立 Redis 執行個體。如果您使用的是 WebSocket 的 Socket.IO 程式庫,可以使用其 redis 轉接器。
在這個以 Redis 為基礎的架構中,每個 Cloud Run 執行個體都會與包含已接收訊息的 Redis 管道建立長時間執行的連線 (使用 SUBSCRIBE
指令)。容器執行個體在頻道上收到新訊息後,即可透過 WebSocket 即時傳送至客戶端。
同樣地,當用戶端使用 WebSocket 發出訊息時,接收訊息的執行個體會將訊息發布至 Redis 管道 (使用 PUBLISH
指令),而訂閱此管道的其他執行個體也會收到這則訊息。
如需完整的程式碼示範,請參閱「為 Cloud Run 建構 WebSocket 聊天服務」一文,瞭解其他程式碼範例。