
OAuth和OpenID Connect圖解指南
我們團(tuán)隊(duì)在結(jié)合自身技術(shù)棧、成本、穩(wěn)定性、易用性、可維護(hù)性、業(yè)務(wù)場景等等因素綜合考慮后,覺得我們面臨的大多數(shù)場景中,HTTP 和 RPC 的性能差別并不是主要問題。
再加上下圖所示的 HTTP 性能測試結(jié)果作為佐證,我們完全可以采用 HTTP API 的方式來進(jìn)行微服務(wù) API 開發(fā)。
再者,當(dāng)業(yè)務(wù)發(fā)展到一定的程度,如果某些業(yè)務(wù)功能的性能壓力變大時(shí),我們還是可以使用 RPC 小范圍地進(jìn)行改造。這也是符合敏捷思想的一個(gè)決定。
下圖是對 helloworld 頁面進(jìn)行 10000 次連續(xù)請求的測試結(jié)果,總耗時(shí) 1.504 秒,平均每個(gè)請求耗時(shí) 0.15 毫秒。
測試環(huán)境:原生 Tomcat7(沒有任何優(yōu)化)運(yùn)行在本地虛擬機(jī)上
下面是對 helloworld 頁面以 100 并發(fā)數(shù)進(jìn)行 10 萬次請求的測試結(jié)果,平均每個(gè)請求耗時(shí) 11.9 毫秒。
測試環(huán)境:原生 Tomcat7(沒有任何優(yōu)化)運(yùn)行在本地虛擬機(jī)上
所以,按照上面的測試結(jié)果,HTTP API 方式的性能完全足以支撐絕大多數(shù)的微服務(wù) API 開發(fā)。讓我們把 RPC 方式留給那些可能出現(xiàn)雙十一業(yè)務(wù)量的大型互聯(lián)網(wǎng)公司去玩。
這是另一個(gè)折磨人的問題。相對于 HTTP API,RESTful API 在 HTTP API 的基礎(chǔ)上增加了一些非常抽象晦澀的概念,例如資源(Resource)、表述(REpresentation)、狀態(tài)轉(zhuǎn)移(State Transfer)、統(tǒng)一接口(Uniform Interface)……。
在經(jīng)歷了一次又一次的折磨,例如“l(fā)ogin/logout 是什么 RESTful 方法?”、“批量刪除該怎么實(shí)現(xiàn)?”、“RESTful 的 resource 究竟該怎么定義?”之后,越來越感覺這是一個(gè)形而上學(xué)的問題,太過于抽像。
我們不該盲從于時(shí)髦的技術(shù),需要加上技術(shù)人的基于自身情況的理性思考。所以,RESTful 雖好,但不是我們團(tuán)隊(duì)的菜。
再者,即使團(tuán)隊(duì)中有些人可以理解并正確地實(shí)踐,也很難或者說不可能讓整個(gè)團(tuán)隊(duì)來正確地實(shí)踐這樣一種方法。
所以,我們在一番掙扎后,選擇了 HTTP API 方式,原來怎么開發(fā),現(xiàn)在還是怎么開發(fā),把主要精力放到了 API 的監(jiān)控和治理上面。
API 存在的意義在于有人調(diào)用它,如果調(diào)用方在調(diào)用 API 的時(shí)候很麻煩,甚至不能正確地調(diào)用,那么團(tuán)隊(duì)內(nèi)部及團(tuán)隊(duì)之間的溝通成本及配合程度就會大受影響。
我們是通過文檔來溝通的,項(xiàng)目開始的時(shí)候還好,但隨著時(shí)間的推移,文檔的更新變得不是那么及時(shí)(這其實(shí)是個(gè)自我辯解的說法,事實(shí)是大部分情況下文檔都不更新了),API 變更時(shí),也不容易找出哪些模塊調(diào)用了這個(gè) API。
所以,得先解決 文檔不及時(shí)更新 的問題。雖然我們可以通過流程管理的方式來強(qiáng)制大家更新文檔,但這對于開發(fā)人員來說,顯然是不夠科學(xué)或人性化的,因?yàn)樽兏粋€(gè) API,就要在兩個(gè)地方進(jìn)行修改,一是 API 代碼,二是 API 文檔,程序員的思維就得在代碼和文檔之間不斷切換,工作效率必然受影響。
我們就想,能不能只需要在同一個(gè)地方修改,如果能做到,API 文檔的更新就沒有那么麻煩了,于人于已都是好事。
經(jīng)過調(diào)研,我們選擇使用 Swagger 來編寫文檔,按照 Swagger 的規(guī)范,在 API 上加一些描述性的 Annotation 就可以了。
通過以上的 Annotation,將自動(dòng)生成以下在線 API 文檔。
調(diào)用方可以在 API 文檔界面填入?yún)?shù)并點(diǎn)擊“Try it out!”按鈕嘗試調(diào)用這個(gè) API。這樣,在沒有 API 提供方支持的情況下,即可以自行完成絕大部分的 API 調(diào)用,是不是很爽?
API 開發(fā)出來了,API 文檔也寫好了,接下來就是被調(diào)用了。前篇文章講到,通過 Spring Cloud 的 Eureka + Ribbon + Zuul 可以很方便地調(diào)用到這些 API。
那么,如何來追蹤 API 被誰調(diào)用了,調(diào)用是否出錯(cuò)及出錯(cuò)原因,調(diào)用鏈路里各個(gè) API 的性能怎么樣,是不是存在僵尸 API……這些都是關(guān)于 API 治理的問題。
實(shí)現(xiàn)這個(gè)目標(biāo),有一個(gè)比較取巧的方法,就是在 Ribbon 的客戶端里做點(diǎn)文章,在調(diào)用 API 之前記錄一下開始時(shí)間,API 調(diào)用返回后,記錄 API 調(diào)用耗時(shí)、調(diào)用狀態(tài),如果有錯(cuò)則記錄一下錯(cuò)誤原因。
如果還想追蹤調(diào)用鏈,可以在請求頭里加上一個(gè)調(diào)用鏈 ID,這樣就來把調(diào)用關(guān)系都串連起來。
下邊是我們自己研發(fā)的調(diào)用鏈管理組件(DCTrace)的幾個(gè)效果圖:
查看微服務(wù)之間的調(diào)用關(guān)系,調(diào)用性能
查看調(diào)用失敗原因
圖形化查看調(diào)用關(guān)系,太亂 ,下次迭代改進(jìn)一下 [攤手]
站在技術(shù)管理者的角度,可以從調(diào)用鏈里看出來,哪些模塊之間發(fā)生了不正當(dāng)關(guān)系 [噗嗤];哪些模塊之間本該有關(guān)系的,事實(shí)卻沒有;通過對比 Swagger 和調(diào)用鏈的 API 清單,找出僵尸 API……
使用微服務(wù)架構(gòu)后,API 是每個(gè)微服務(wù)的 唯一能力出口。由于互聯(lián)網(wǎng)行業(yè)的快速發(fā)展,軟件需求變更變得越來越頻繁,迭代升級的速度變得越來越快。
對于提供方來說,需要保證變更和迭代的過程中,不影響之前承諾的功能(包括正確性、穩(wěn)定性和性能等)。
對于調(diào)用方來說,同樣需要確保自身依賴的 API 能正常使用,不能因?yàn)槠渌K的錯(cuò)誤而導(dǎo)致自身業(yè)務(wù)受到影響(包括正確性、穩(wěn)定性和性能等)。
畢竟,從組織角度來看,系統(tǒng)出錯(cuò)就是出錯(cuò),不管原因是自身導(dǎo)致的還是服務(wù)提供方導(dǎo)致的,所以 服務(wù)調(diào)用方就需要對服務(wù)提供方進(jìn)行管理。
這也就是前幾年契約測試(Pact)方法大行其道的原因。有興趣的朋友可以去看看這種測試方法。
對于 API 白盒測試,推薦使用基于 Java 的 REST-Assured 測試框架,用起來特別方便。
https://github.com/rest-assured/rest-assured
更進(jìn)一步,基于 HTTP 協(xié)議、JSON/XML 報(bào)文的規(guī)范性,完全可以開發(fā)一個(gè) API 測試小工具(暫且叫它 小鷹 吧)來替換 REST-Assured。我們也暫未實(shí)踐,只是覺得會很有用,供大家參考。
基礎(chǔ)步驟是:
所以,對于微服務(wù) API 開發(fā),我們
文章轉(zhuǎn)自微信公眾號@InfoQ