微服務架構中 API 的開發與治理

前面的文章中有說到微服務的通信方式,Martin Folwer 先生在他對微服務的定義中也提到“每個服務運行在其獨立的進程中,服務與服務間採用 輕量級的通信機制 互相協作(通常是基於 HTTP 協議的 RESTful API)”。

那麼,在各個微服務之間具體怎麼進行輕量級的通信呢?這篇文章就來聊聊微服務 API 開發及治理的幾個方面。

首先需要解釋一下,標題中的“內網環境中 的 API”指的是提供給內網裏的其它微服務調用的 API。與其相對應的是“開放給互聯網 用戶調用的 API”,它們的開發方法大體相同,但治理方法卻不太一樣。例如開放給互聯網用戶調用的 API 需要在 API 網關上加上授權、鑑權、限流、限併發、統計、計費等等功能。

本篇文章分享的是內網環境中的 API 開發及治理。

前兩篇文章鏈接:

Re:重識微服務架構

如何快速搭建一個微服務架構?

API 開發

API 開發,首先考慮的就是該用什麼樣的協議,是 HTTP API 還是 RPC?

我們先來介紹一下這兩種 API 類型:

HTTP API

HTTP API 指的是簡單的基於 HTTP 協議的 API,具體的例子就是 Spring MVC 的 Controller,例如:

“http://127.0.0.1/helloworld/myapi.do”。

 RPC

RPC 就是 Remote Procedure Call,中文名遠程過程調用,在 API 調用的場景下,大多指的是基於 Socket 通信方法的遠程調用(當然,我們也可以使用 HTTP 協議來實現 RPC 調用,例如 gRPC)。Json-RPC 和 Xml-RPC 指的是使用 Json 或 Xml 作爲文本格式的方式傳輸命令和數據。

那麼回到剛纔那個問題,到底要使用 HTTP API 還是 RPC 呢?我們之所要對比 HTTP API 和 RPC,主要是因爲大家都知道 HTTP 簡單,而基於 Socket 的 RPC 性能更好。

這個問題我們糾結了很久,直到後來,想明白了下面兩件事,最終決定在絕大部分場景中使用 HTTP API。

HTTP API 的性能足以支撐大多數項目

通常來講(根據資料),算上序列化的時間,RPC 協議的吞吐量是 HTTP 性能 兩倍(沒有親測),例如 Protobuf、Thrift、Kyro、Dubbo 等等。

這裏面,又以 Thrift 的性能最高。具體的性能測試報告可以參考《RPC 框架性能基本比較測試》。

我們團隊在結合自身技術棧、成本、穩定性、易用性、可維護性、業務場景等等因素綜合考慮後,覺得我們面臨的大多數場景中,HTTP 和 RPC 的性能差別並不是主要問題。

再加上下圖所示的 HTTP 性能測試結果作爲佐證,我們完全可以採用 HTTP API 的方式來進行微服務 API 開發。

再者,當業務發展到一定的程度,如果某些業務功能的性能壓力變大時,我們還是可以使用 RPC 小範圍地進行改造。這也是符合敏捷思想的一個決定。

下圖是對 helloworld 頁面進行 10000 次連續請求的測試結果,總耗時 1.504 秒,平均每個請求耗時 0.15 毫秒。

測試環境:原生 Tomcat7(沒有任何優化)運行在本地虛擬機上

下面是對 helloworld 頁面以 100 併發數進行 10 萬次請求的測試結果,平均每個請求耗時 11.9 毫秒。

測試環境:原生 Tomcat7(沒有任何優化)運行在本地虛擬機上

所以,按照上面的測試結果,HTTP API 方式的性能完全足以支撐絕大多數的微服務 API 開發。讓我們把 RPC 方式留給那些可能出現雙十一業務量的大型互聯網公司去玩。

RESTful API 適用於開放 API 的場景

這是另一個折磨人的問題。相對於 HTTP API,RESTful API 在 HTTP API 的基礎上增加了一些非常抽象晦澀的概念,例如資源(Resource)、表述(REpresentation)、狀態轉移(State Transfer)、統一接口(Uniform Interface)……。

在經歷了一次又一次的折磨,例如“login/logout 是什麼 RESTful 方法?”、“批量刪除該怎麼實現?”、“RESTful 的 resource 究竟該怎麼定義?”之後,越來越感覺這是一個形而上學的問題,太過於抽像。

我們不該盲從於時髦的技術,需要加上技術人的基於自身情況的理性思考。所以,RESTful 雖好,但不是我們團隊的菜。

再者,即使團隊中有些人可以理解並正確地實踐,也很難或者說不可能讓整個團隊來正確地實踐這樣一種方法。

所以,我們在一番掙扎後,選擇了 HTTP API 方式,原來怎麼開發,現在還是怎麼開發,把主要精力放到了 API 的監控和治理上面。

這裏推薦大家看看知乎上的這篇討論 《WEB 開發中,使用 JSON-RPC 好,還是 RESTful API 好?》,幾位大神講得都挺好。

https://www.zhihu.com/question/28570307

API 治理

API 文檔

API 存在的意義在於有人調用它,如果調用方在調用 API 的時候很麻煩,甚至不能正確地調用,那麼團隊內部及團隊之間的溝通成本及配合程度就會大受影響。

我們是通過文檔來溝通的,項目開始的時候還好,但隨着時間的推移,文檔的更新變得不是那麼及時(這其實是個自我辯解的說法,事實是大部分情況下文檔都不更新了),API 變更時,也不容易找出哪些模塊調用了這個 API。

所以,得先解決 文檔不及時更新 的問題。雖然我們可以通過流程管理的方式來強制大家更新文檔,但這對於開發人員來說,顯然是不夠科學或人性化的,因爲變更一個 API,就要在兩個地方進行修改,一是 API 代碼,二是 API 文檔,程序員的思維就得在代碼和文檔之間不斷切換,工作效率必然受影響。

我們就想,能不能只需要在同一個地方修改,如果能做到,API 文檔的更新就沒有那麼麻煩了,於人於已都是好事。

經過調研,我們選擇使用 Swagger 來編寫文檔,按照 Swagger 的規範,在 API 上加一些描述性的 Annotation 就可以了。

通過以上的 Annotation,將自動生成以下在線 API 文檔。

調用方可以在 API 文檔界面填入參數並點擊“Try it out!”按鈕嘗試調用這個 API。這樣,在沒有 API 提供方支持的情況下,即可以自行完成絕大部分的 API 調用,是不是很爽?

調用鏈管理

API 開發出來了,API 文檔也寫好了,接下來就是被調用了。前篇文章講到,通過 Spring Cloud 的 Eureka + Ribbon + Zuul 可以很方便地調用到這些 API。

那麼,如何來追蹤 API 被誰調用了,調用是否出錯及出錯原因,調用鏈路裏各個 API 的性能怎麼樣,是不是存在殭屍 API……這些都是關於 API 治理的問題。

實現這個目標,有一個比較取巧的方法,就是在 Ribbon 的客戶端裏做點文章,在調用 API 之前記錄一下開始時間,API 調用返回後,記錄 API 調用耗時、調用狀態,如果有錯則記錄一下錯誤原因。

如果還想追蹤調用鏈,可以在請求頭裏加上一個調用鏈 ID,這樣就來把調用關係都串連起來。

下邊是我們自己研發的調用鏈管理組件(DCTrace)的幾個效果圖:

查看微服務之間的調用關係,調用性能

查看調用失敗原因

圖形化查看調用關係,太亂 ,下次迭代改進一下 [攤手]

站在技術管理者的角度,可以從調用鏈裏看出來,哪些模塊之間發生了不正當關係 [噗嗤];哪些模塊之間本該有關係的,事實卻沒有;通過對比 Swagger 和調用鏈的 API 清單,找出殭屍 API……

API 測試

使用微服務架構後,API 是每個微服務的 唯一能力出口。由於互聯網行業的快速發展,軟件需求變更變得越來越頻繁,迭代升級的速度變得越來越快。

對於提供方來說,需要保證變更和迭代的過程中,不影響之前承諾的功能(包括正確性、穩定性和性能等)。

對於調用方來說,同樣需要確保自身依賴的 API 能正常使用,不能因爲其它模塊的錯誤而導致自身業務受到影響(包括正確性、穩定性和性能等)。

畢竟,從組織角度來看,系統出錯就是出錯,不管原因是自身導致的還是服務提供方導致的,所以 服務調用方就需要對服務提供方進行管理。

這也就是前幾年契約測試(Pact)方法大行其道的原因。有興趣的朋友可以去看看這種測試方法。

對於 API 白盒測試,推薦使用基於 Java 的 REST-Assured 測試框架,用起來特別方便。

https://github.com/rest-assured/rest-assured

更進一步,基於 HTTP 協議、JSON/XML 報文的規範性,完全可以開發一個 API 測試小工具(暫且叫它 小鷹 吧)來替換 REST-Assured。我們也暫未實踐,只是覺得會很有用,供大家參考。

基礎步驟是:

  • 服務提供方開發 API,並正確書寫 Swagger 文檔。
  • 服務提供方在小鷹的界面上選擇需要測試的 API,並填寫測試參數。(API 清單和參數都可以通過調用 Swagger 的 API 獲取)
  • 服務調用方根據自已的理解,也將對自己有用的服務方提供的 API 配置到小鷹上。
  • 小鷹 7*24 小時爲服務提供方和調用方巡視這些 API,並在異常出現時發送警報。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章