後REST時代
當我在AWS工作時,我們常做的事是設計一個服務或者一款APP的資料層和它的控制層。舉例,假定資料庫像RDS服務一樣。那麼在app的控制層中你去建立,配置,備份,啟動,停止和刪除資料庫。資料層主要內容是SQL語句,連線池和RDBMS包
非常有趣的是我們需要去注意的一點是控制層可以非常好的匹配RESTFUl風格的API,但是資料層就不是這樣了。在資料庫當中REST並非屬於必要,(但是DynamoDB資料庫的資料層是非常嵌合RESTFUL)。
我在想模式能否是這樣,當你在控制層去刪除和建立物件時,控制層可以很好嵌合大多數RESTFUL風格的API。資料層卻完全不一樣。要不是因為REST和控制層像是天造地設一樣合適,我還以為不論什麼想要替換掉REST都將從資料層開始。
RESTful 缺陷我們想超越 REST 的原因可能有哪些?下面我列出了一些:
延遲
建立和銷燬一個 HTTP 連線的每一個操作都不是沒有代價的。雖然為了減小這種代價努力了幾十年,但是它依然存在。
比如說兩個我身邊的朋友建立的訊息服務的例子: Amazon SQS 和 MQ. SQS 已經運行了十多年, 每秒處理百萬級的訊息,而且如果你的訊息傳送者和接收者能合理平衡的話,可以做到出奇的快。甚至我聽說過訊息還沒有傳送就已經被接受的例子。其實是長輪詢的接收者在傳送端銷燬 PutMessage 的 HTTP 連線之前就已經收到訊息。一方面,它沒有使用 HTTP,而是用了 TCP/IP 長連線和它自己的報文協議。所以可以得到驚訝的傳送和接收延遲。但是另一方面,你的訊息吞吐量受限於關閉這些連線的“message broker”所能處理的連線數。很多選擇 MQ 的人的原因相信他們這麼做的因為是不想用 RESTful 介面。
耦合自然情況下,大部分 REST 請求是同步的。也就是說, 你呼叫一個請求得等著結果返回。現在 (使用HTTP術語)你的請求有可能會返回202 Accepted,在這種情況下,您可能希望傳送一個 URI 作為 webhook 回撥地址,或者可以響應中獲取一個可以拉取資訊的 URI。但是在所有這種情況下, 耦合是非常緊密的。 你必須維護一些請求的狀態直到呼叫方處理完它,不管是立刻或者要等一會兒。
這是很糟糕的情況。特別是在微服務中一個請求方以超過服務方可以處理的頻率呼叫時,一些不想看到的情況就會出現。
短生命週期(Short life)· 舉例來說,citizen-ship 應用 ,它可能需要花費數週時間來編排大量的服務,偶爾還需要人工互動,但是它在處理一些請求上是毫秒級的,這樣的情況讓一個執行緒等待某件事發生的想法就變得荒謬了。
關於 GraphQL 。GraphQL 的存在主要是為了處理這樣的一種情況,即一個客戶端需要組合多種型別的資訊來完成其工作。例如,一個手機應用程式就是基於 GraphQL 來構建一個資訊豐富的顯示器。由於 RESTful 風格的介面在處理單一資源的時候的優勢,這可能就會導致大量請求的浪費。GraphQL 可以讓你在單個請求的多個資源中任意選擇欄位。從上面可以推測,當伺服器端響應一些簡單的請求的時候,這個時候你只需要使用 GraphQL 去組裝資訊然後完成請求的響應就可以了。
我瞭解到大量的客戶端開發人員都喜歡 GraphQL ,這似乎看起來它在程式設計的世界裡有一席之地。但是我並沒有看到 GraphQL 改變了我們的處理方式。首先,由於受限於 GraphQL 的語義的限制,這將不能讓我們像客戶端開發人員一樣組裝任意的查詢去得到一個很好的效果。(公平的講,SQL 也是一樣的。)無論如何,在我們使用 GraphQL 去讓同步的 API 執行的更有效率的時候,我看到了 GraphQL 便捷的特性。
關於 RPC 的話。這些天,我想我一定是指 gRPC 。長久的經歷讓我見證了一代又一代的 RPC 框架悲慘地失敗。它們是脆弱的而且需要大量的配置還不能達到預期的效能。對我來說 ,能看到 RESTful 風格的 API 成功的更緊密地耦合起來真的很難 。但是我的觀點不一定是正確的。
Post-REST: 訊息和事件處理 · 這種方法已經普及,我的意思是在我所使用的雲基礎架構中已普及。其中的想法是你得到一個請求,校驗之,也許對其進行一些計算,然後你把它放到佇列(或匯流排,或流,或任何你想要稱之的名稱),那麼忘記這些事情吧,它們不是你的問題了。 ¶
請求處理的下一階段是由讀取佇列的服務實現,並將答覆路由回原始請求者或將其傳遞給另一個服務階段。現在為了使這個可工作,所以問題佇列必須快速(這些天裡它們是的),可擴充套件(它們目前是的),非常非常耐用(它們目前是的)。
這裡有很多優勢:首先,瞬態查詢激增不再是問題了。此外,一旦你擁有一個訊息流,你就可以進行扇出和過濾,彙編和子集以及各種其他有用的操作,而勿須干擾上游訊息源的操作。
Post-REST: Orchestration· 這涉及到工作流程領域了,這是我ofollow,noindex" target="_blank">近期一直在努力研究的 的事情。 其中“工作流程”是指跟蹤具有多個步驟的計算狀態的服務,其中任何一個步驟可能需要任意長時間,可能會失敗,可能需要重試,並且其行為和輸出會影響後續輸出步驟的選擇及其行為。¶
越來越多(例如)Lambda函式,不再是提供請求和返回響應,而是在提供輸入,等待其完成,並將其輸出路由到更下游的工作流上下文中執行。
Post-REST: 持久連線· 回到之前的幾段,我談到了MQ訊息代理如何工作,維護了一堆固定的網路連線,並在它們之間來回提取位元組。不難相信,有很多場景可以很好地適應此資料和執行的流動方式。
現在,我們已經在半路上了。例如,SQS客戶端通常使用“長輪詢”(通常約30秒)來接收訊息。這意味著,他們請求訊息,如果沒有,伺服器不會說“沒有”,它會掛起該連線一段時間,如果有訊息收到,則將它們傳送給呼叫者。 如果你有一堆執行緒(可能在多個主機上)在長輪詢SQS佇列,你可以獲得大吞吐量和低延遲,並真正降低使用HTTP開銷。
接下來的兩步也很容易預見。第一步是已經廣泛部署的HTTP/2,它允許你在單個網路連線中複用多個HTTP請求。明智地使用之後,它可以為你帶來使用永久連線的一些好處。但它仍然與TCP密切相關,這有一些不幸的副作用,在此我不會對其深入探討,部分原因是這不是我所深刻理解的事物。但我希望看到諸多應用程式和服務可以從HTTP/2進化中獲得很好的收益;在某些程度上,因為就客戶端而言,他們仍在生成和響應與之前完全一致的HTTP請求。
之後的下一步是QUIC(Q uick U DP I nternet C onnections,快速UDP網際網路連線),它放棄了TCP而使用UDP,同時保留了HTTP語義。這已經在很多Google產品上投入使用。我個人認為這是一個非常重要的事情; HTTP如此成功的原因之一是它的連線是短時的,因此在工作時受到破壞的可能性要小得多。這非常棒,因為設計一種可以處理連線斷開的應用程式級協議是非常困難的。在HTTP的世界中,你同時需要處理的多數情況是一些失敗的請求,而連線斷開只是可能發生此問題的原因之一。UDP通過沒有真正的連線使連線斷開問題消失了。
當然,沒有免費的午餐。如果你正在使用UDP,你就不會在TCP中獲得TC,我說的是T ransmission C ontrol,它負責打包和重組以及校驗和檢查、流控以及載入其他超級有用的東西。但從我看到的證據判斷,QUIC做得足夠好,足以完全支援HTTP語義,所以再一次,想要繼續使用與2005年相同的舊的XMLHttpRequest呼叫的應用程式可以愉快地保持不變了。
未來!·對於我來說似乎是不可避免的使用持久連線,特別是在高吞吐量高彈性雲原生應用程式的場景中,我們將看到對持久連線,編排和基於訊息/事件的邏輯的依賴性的穩定增長。如果你還沒有使用這些東西,那麼現在是開始學習的好時機。
但我敢打賭,在可預見的未來,所有服務請求的很大一部分將具有(近似)HTTP語義,而對於大多數控制平面和相當多的資料平面,REST 仍然提供了一種很好的分解複雜的方法問題,它的極端簡單性和彈性意味著如果你想設計網路應用程式,你仍然需要學習這種思考方式。