異步請求 - 響應模式

一些場景下後端的邏輯處理需要以異步(而非同步)的方式進行,通過異步請求 - 響應模式,把邏輯處理與前端進行解耦,同時返回給前端一個邏輯清晰的響應。

產生背景

在當前最常見的應用開發模式下,客戶端應用程序(包括網絡瀏覽器裏的代碼)通常靠遠端的 API 服務提供業務邏輯上的支持,從而提供完整的用戶體驗。API 服務可以是和客戶端應用程序同時開發的,也可以是第三方的服務。大多數 API 調用基於 HTTP(S) 實現,並且遵循 REST 規範;目前移動端也會採用基於 HTTP/2 的 gRPC 協議。

在絕大多數應用場景中,API 設計時以快速響應爲目標,指標上體現爲 100ms 以內。可能導致響應延遲的因素很多,包括:

  1. 應用的託管模式:物理機 / 虛擬機 / 容器及對應的編排方案

  2. 安全組件:流量清洗服務等

  3. client 與 server 的物理距離:如果一箇中國的瀏覽器訪問美國的網站,不考慮 CDN、中間沒有任何路由,數據也要繞一個地球,額外增加 130ms 的延遲;

  4. 網絡基礎設施:中轉路由器的數量、性能(是否有專線)、網絡接入速度、網卡速度等

  5. 當前的網絡負載:如果負載比較高,甚至有網絡擁塞,響應會變慢

  6. 請求報文的大小

  7. 要處理事件的隊列大小

  8. 後端處理請求的耗時

上面提到的任何因素都會增加網絡延遲。一些可以通過對後端服務擴容來緩解,另外一些可能是開發者不可控的部分,比如網絡基礎設施。大多數 API 都能夠在同一個連接上快速響應請求。client 端代碼可以以非阻塞的方式進行 API 同步調用,比較適合 IO 密集型服務。注意:非阻塞看起來有點像異步處理,但阻塞 / 非阻塞、同步 / 異步是完全不同的概念,阻塞 / 非阻塞是線程從網卡讀取 / 發送數據角度的概念,同步 / 異步是服務架構角度 client/server 進行交互相關的概念,網上有很多相關的面試八股,這裏不細說了。

儘管常規的 API 對短請求做了很多優化,在一些業務場景中,後端處理的時間比較長,以秒、分甚至小時作爲計時單位。這類場景下,如果等着任務完成後再響應客戶端的請求,必然會有問題。

爲了解決這類問題,一些架構引入了消息隊列中間件,消息隊列把請求階段和響應階段進行了分離。這類架構的額外收益是可以對請求進行削峯,以避免高峯期服務器被打垮,比如美國和印度每年一次的報稅日。請求 - 響應分離還允許前端和後端 API 能夠獨立進行擴縮容,同時增加了架構的複雜度,因爲 client 接收成功通知也需要異步處理。

在異步請求 - 響應模式下要考量很多個方面,分佈式系統中 Server 間的 REST API 調用存在同樣的問題,一般出現在微服務架構中。

解決方案

最簡單的解決方案是 HTTP 輪詢。在 client 端 (瀏覽器 / 安卓 / iOS / 小程序等) 代碼中我們只能輪詢,因爲 client 端基本上無法提供回調接口,也很難使用長連接。即便理論上回調是可支持的,額外的庫依賴或服務依賴使得技術方案極其複雜,讓人望而卻步。

使用 HTTP 輪詢的規範如下:

注意:API 服務在創建長任務之前,應當校驗請求的合法性和即將執行的操作的合理性。如果請求不合理,應當立即返回 400(Bad Request)

一個典型的工作流如下圖所示:

  1. client 發送一個請求,接收到狀態碼爲 HTTP 202 (Accepted) 的響應;

  2. client 持續對狀態查詢接口發起 HTTP GET 請求,任務狀態爲執行中,所以返回 HTTP 200;

  3. 在某個時間點,任務執行完成,查詢接口返回 HTTP 302 (Found),並重定向到對應的資源;

  4. client 從資源 URL 獲取任務的執行結果;

問題和注意事項

BZBxaM

什麼時候(不)使用該模式

該模式適合的場景有:

  1. client 端代碼很難提供回調接口,或者使用長鏈接代價過高。比如網絡瀏覽器、移動端 app;

  2. 服務端調用只支持 HTTP 協議,且由於防火牆 Server 端無法發起回調;

  3. 服務端需要兼容比較舊的系統,無法使用現代的回調技術,比如 WebSocket 或 Webhook。

該模式不適合的場景有:

  1. 有現成通知機制的服務;

  2. 響應必須以實時流的方式返回給 client,比如 SSE;

  3. client 必須從多個服務獲取結果,對每個結果的延遲比較敏感。這時可以考慮 Service Bus 模式;

  4. 可使用持久化連接技術,比如 WebSockets 或 SignalR,client-server 可藉助這些技術實現雙向通信;

  5. 網絡防火牆允許開放一些端口,接收異步回調或 webhooks;

例子

  1. 調度框架:比如大數據調度框架 YARN、容器編排工具 Kubernetes;

  2. 支付場景:需要先對 transaction 進行持久化,再扔到隊列裏,由 worker 撿起任務執行;

  3. 大量數據的下載

有一些比較典型的數據量大但不適用異步的場景,比如推廣搜中的廣告召回等;

還有一些場景處於模糊地帶,比如大數據計算,從早期基於 Hive/Spark 的異步計算,逐漸演變到 Clickhouse 的同步計算,大大提升了用戶體驗。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/YkOoLbH2P2HheQxomGsbNQ