2018年Openapi Specification發(fā)布了3.0版本
圖片來源:https://swagger.io/
當你在考慮單個產(chǎn)品的API表現(xiàn)形式時,首先會選擇一種具體的API風格,常見的有RPC(Remote Procedure Call)和ROA(the Rest-Oriented Architecture)兩種模式,然后針對復(fù)雜的數(shù)據(jù)結(jié)構(gòu)你會考慮使用什么樣的序列化協(xié)議,常見的包括Json/Xml/WSDL/Hessian等,用于封裝傳輸數(shù)據(jù)。但涉及到不同的產(chǎn)品時,在具體選型時考慮的問題可能就不太一樣了。

gRPC示意圖
圖片來源:https://www.grpc.io/docs/guides/
雖然RESTful設(shè)計風格曝光率很高,但并不是所有云服務(wù)商都選擇了完全遵循RESTful,例如AWS和阿里云RPC風格反而占了大多數(shù),Google和Azure則RESTful居多。
Restful API的優(yōu)勢是HTTP具備更好的易用性,讓異構(gòu)系統(tǒng)更容易集成,且開發(fā)執(zhí)行效率比較高,面向資源要求也比較高。而RPC API可以使用更廣泛的框架和方案,技術(shù)層面更底層也更為靈活,設(shè)計起來相對簡單,掌握起來有一定門檻,架構(gòu)上更加復(fù)雜。

RESTful與RPC模式對比
不同的團隊根據(jù)實際情況和業(yè)務(wù)形態(tài)可能選擇不同的方案,那云服務(wù)作為一個整體應(yīng)該強制統(tǒng)一好還是隨意選擇好?如果強制統(tǒng)一風格,有些適合RESTful風格的服務(wù)非要使用RPC的話,看起來就會比較丑陋,如果只是一個過程化的服務(wù)調(diào)用,往RESTful資源化設(shè)計方向去靠會比較困難。但如果不強制使用統(tǒng)一風格,會造成針對API的體系化支持會更加復(fù)雜,例如為兼容兩種風格SDK的自動化支持需要兩套代碼。
通常RESTful風格對API設(shè)計者的要求是比較高的,主要的難點在于面向資源設(shè)計要求開發(fā)者事先做好規(guī)劃,將后端數(shù)據(jù)模型與API服務(wù)模型相匹配。所以RESTful API的開發(fā)者應(yīng)該是熟知系統(tǒng)整體實體關(guān)系模型的,很難想象一個不懂后臺業(yè)務(wù)的新手能設(shè)計出合理的API來。那么是不是RPC風格API就不需要面向資源設(shè)計了呢?從實踐中來看,并不是!RPC風格的API也需要資源模型來支持,在下一節(jié)中會重點分析。
所以,對于云服務(wù)商來說,選擇API風格時要考慮幾個問題:? ??
選定了具體設(shè)計模式后,就要努力做到統(tǒng)一,避免多種模式混雜帶來管理成本的上升。如果確實有必要兩種方式都支持(例如阿里云就同時支持RPC和ROA),就需要在技術(shù)上做好充分的準備。
用戶使用API來訪問云服務(wù),本質(zhì)上是想通過對某種云資源執(zhí)行特定的操作來完成一個業(yè)務(wù)動作。Restful API需要面向資源設(shè)計眾所周知,那為什么RPC接口在云服務(wù)場景下也需要有資源模型呢?
RPC形式的API組織形態(tài)是領(lǐng)域和行為(對象和方法),隨著時間的推移,API越來越多最終形成一個龐大的集合。以阿里云為例,對外開放的OpenAPI數(shù)量已經(jīng)達到10000多個,涵蓋了接近200個不同的產(chǎn)品。因為開發(fā)者必須單獨學(xué)習(xí)每個API,耗時又容易出錯,如果沒有一個脈絡(luò)的理解起來比較困難。如果有一套標準的資源模型,API就可以按照資源模型的維度分類組織,用戶使用起來也會有跡可循,體驗上會更好,否則面對如此多的API一點點學(xué)習(xí)無疑是個痛苦的過程。
另外,云服務(wù)并非單個服務(wù)的簡單排列,它是多個體系的橫向整合,總體對外呈現(xiàn)出有機連接。隨著云計算的發(fā)展,企業(yè)客戶對對云服務(wù)的要求不斷提高。最典型的就是當企業(yè)客戶大規(guī)模開始上云后,對虛擬化的云產(chǎn)品提出了各種管理需求,例如鑒權(quán)、編排、彈性伸縮等。

企業(yè)客戶對云服務(wù)的管理需求
以最常用的鑒權(quán)功能為例,客戶創(chuàng)建了一組云服務(wù)器來跑業(yè)務(wù),運維人員需要有重啟服務(wù)器的權(quán)限,其他角色人員則不需要此類權(quán)限,針對RestartServer這么一個API就需要進行權(quán)限控制了。權(quán)限在云平臺中一般是中心式管理的,單獨的云產(chǎn)品不需要分別管理。如果統(tǒng)一處理鑒權(quán),就需要知道當前API正在操作什么資源,與此相關(guān)的資源有哪些(例如與服務(wù)器有關(guān)的資源包括磁盤、網(wǎng)卡、網(wǎng)絡(luò)等關(guān)聯(lián)資源),然后針對所有相關(guān)資源逐一鑒權(quán)才能確認API操作是否可行。
上面提到的資源有兩個關(guān)鍵點,一是要有統(tǒng)一的資源模型,便于云產(chǎn)品對特定的API進行鑒權(quán),二是要明確資源關(guān)系,當出現(xiàn)資源依賴的時候,需要關(guān)聯(lián)鑒權(quán)。在Google的API Guide中就明確提到需要資源關(guān)系,可以看出資源關(guān)系不僅僅是用來做API設(shè)計建模的,它對于平臺功能的實現(xiàn)也有至關(guān)重要的作用。不了解資源關(guān)系,有可能把多個資源封裝到一個API中,使用和變更都很痛苦,即便后期發(fā)現(xiàn)了問題再補救拆開,由于很多用戶已經(jīng)在使用了,要付出的開發(fā)成本和溝通成本也是極大的,甚至成為不可能。所以清晰的資源模型有利于梳理清楚API體系。

定義清晰的實體關(guān)系圖有助于設(shè)計出更為完整的API
而且,明確的資源模型對于構(gòu)建云上運維管理基礎(chǔ)設(shè)施至關(guān)重要,例如可以通過對資源打Tag來對資源進行分類管理(參考阿里云資源Tag),分組授權(quán)(參考阿里云資源組),資源審計(參考阿里云CloudConfig),類似開源軟件Terraform這樣的編排工具,由于有資源模型會更容易接入和使用。
所以,統(tǒng)一的資源模型對云服務(wù)的幫助是巨大的:
既然有這么多好處,那么眾多的云產(chǎn)品在實際設(shè)計API的時候能否堅持以資源為中心,充分考慮到上下游的需求就變成一個很大的挑戰(zhàn)了。
確定了設(shè)計模式和資源模型后,是時候進入到API設(shè)計細節(jié)了。諸如API名稱、參數(shù)名、屬性名稱、數(shù)據(jù)格式、錯誤碼之類的信息,看起來根本不是問題。單個產(chǎn)品問題還不大,只要保證內(nèi)部風格一致即可,如果考慮到云服務(wù)多產(chǎn)品對外的整體體驗,就有必要考慮以下問題:
上述問題都是實際研發(fā)過程中要注意的,要全部羅列的話遠不止這些。API的用詞描述是云服務(wù)展現(xiàn)給外部用戶的第一印象,絕非隨意寫就。對人員有一定規(guī)模,內(nèi)部有多條產(chǎn)品線的組織來說,如何協(xié)調(diào)組織的各個部分對外具有統(tǒng)一的體驗是個很大挑戰(zhàn)。
回顧下HTTP協(xié)議,最廣為認知的是對HTTP Mehod的約定,使用9個單詞就完成了對基本動作的規(guī)范,為開發(fā)者提供了清晰的思維模型:

Http Method 類型圖片來源:https://tools.ietf.org/html/rfc7231
同樣,在HTTP Header里面也對瀏覽器信息、語言、網(wǎng)絡(luò)連接屬性等做了詳細的規(guī)定,這樣開發(fā)者在使用HTTP服務(wù)的時候都有一個大致的約定,在關(guān)鍵信息上面不會有偏差,保障了異構(gòu)系統(tǒng)的接口一致性。
因此云服務(wù)在管理API時應(yīng)該考慮一些具體的規(guī)范,對命名規(guī)則、標準詞匯、最佳實踐模式、錯誤碼等信息都有明確的規(guī)定,同時用系統(tǒng)化、平臺化的手段來管理API,確保不走偏。設(shè)計風格不是云服務(wù)API設(shè)計中致命的問題,但是它關(guān)乎云服務(wù)外表形象,不可不察。
API是后端服務(wù)的外部表達,是服務(wù)就有可能出現(xiàn)問題,無論這個問題是可預(yù)期的還是不可預(yù)期的。如果只考慮功能本身功能特性,而忽視對異常情況的設(shè)計,當問題出現(xiàn)的時候業(yè)務(wù)本身可能無法感知造成服務(wù)異常,更重要的是站在客戶角度去看,不能有效獲取錯誤原因是非常痛苦的,很多時候只能束手無策,降低云服務(wù)提供商的整體口碑,甚至損害營收。
假設(shè)有個創(chuàng)建資源的API,每調(diào)用一次都會創(chuàng)建新的資源,考慮以下情況:
實踐中,如果不做好問題a的處理,可能會造成系統(tǒng)異常情況下大批資源被重復(fù)創(chuàng)建,有可能造成用戶或云服務(wù)商資損;問題b-e沒有處理好,可能會讓用戶陷入盲目等待或者盲目重試,使用體驗和效率極差;而f-g關(guān)系到自動化處理工具如何做到效率最大化,也關(guān)系到被集成的效率。

一個異步重試的狀態(tài)機
當出現(xiàn)異常的時候,API一般是要靠錯誤碼來告知用戶有什么問題。HTTP協(xié)議本身對錯誤碼做出了詳盡的規(guī)定,Restful的API要盡可能地符合標準。除此之外,云服務(wù)有必要在此基礎(chǔ)上進一步提供業(yè)務(wù)錯誤碼和錯誤信息,來描述錯誤具體的細節(jié)。
當前云服務(wù)的錯誤碼很多,看起來非常專業(yè),但問題主要集中在以下幾個方面:
1.錯誤類型過多:錯誤碼越多客戶端處理起來越方便嗎?看一下HTTP的錯誤碼,只有5大類加幾十個子類的錯誤碼就涵蓋了所有場景,而通常大家耳熟能詳?shù)臒o非是200、400、404、500、502等屈指可數(shù)的狀態(tài)碼。有的人考慮錯誤碼越多,客戶端可以switch/case一下針對每個錯誤碼做不同的操作,這個就見仁見智了,一般的程序員可能不會寫那么多的分支流程,必要性也不大。
2.錯誤信息表達不夠充分:相比于提供大量的錯誤碼,錯誤信息的明確表達更為重要。如果錯誤信息不夠詳細,作為用戶不了解細節(jié)無法掌控的云服務(wù),幾乎是無法明確發(fā)生了什么,要么提工單,要么只能被動等待,客戶體驗很差。
3.業(yè)務(wù)錯誤碼與HTTP錯誤碼含義不匹配:例如參數(shù)錯誤應(yīng)該返回4xx系列Code,返回5xx系列就不夠?qū)I(yè)。即便是RPC風格的API,也要大致符合HTTP規(guī)則,否則可能會給一些依賴HTTP Code的系統(tǒng)造成誤導(dǎo)。網(wǎng)上有種思路覺得無論后臺響應(yīng)如何,HTTP Code統(tǒng)統(tǒng)返回200,在Body里面的錯誤信息體現(xiàn)異常信息,這種不利于對接口的監(jiān)控,因為監(jiān)控系統(tǒng)很難通過識別消息體來鑒別功能是否正常響應(yīng)。
4.相同錯誤不同云產(chǎn)品表達不一致:這會給客戶端開發(fā)造成困擾,增加開發(fā)工作量,不利于自動化集成,用戶體驗比較差。
5.錯誤碼應(yīng)該是可枚舉集合:一個API能夠產(chǎn)生的錯誤碼類型應(yīng)該是可預(yù)期的,即便是業(yè)務(wù)升級,也應(yīng)該給客戶提供明確的錯誤碼列表,不能隨心所欲。因為用戶端需要明確知道可能會發(fā)生什么,而不是隨時可能出現(xiàn)不可預(yù)知的錯誤類型。如果錯誤類型不確定,就意味著針對錯誤碼分支處理基本是無效的。
要做好服務(wù)端容錯上述問題,需要從云服務(wù)整體層面加強API的容錯設(shè)計,做好錯誤碼規(guī)范,加強對錯誤信息的管理,來提升用戶體驗。
API都是不斷迭代的,通常都需要版本管理。云服務(wù)API的版本管理尤其重要,主要是以下原因:
針對API各種場景的管理,需要一套成熟的API管理平臺,照顧到各種場景的需求,也是一項不小的挑戰(zhàn)。
API如何開放看起來是奇怪的問題,難道API做出來不就是開放給別人用的嗎?做好就開放就開放啊?但在云服務(wù)場景下,情況會更復(fù)雜一點!
產(chǎn)品技術(shù)都是在不斷迭代的,功能始終在增加,新的API層出不窮。從客戶視角來看,他們對已開發(fā)完畢的API是否開放的需求是什么?假設(shè)一個云產(chǎn)品有100個功能特性,20個只能保留在內(nèi)部,官網(wǎng)上總共提供了80個特性,而公開API只開放了50個,這是用戶期望的狀態(tài)嗎?理想狀態(tài)應(yīng)該是什么?
圍繞云服務(wù)有一個龐大的生態(tài),除了普通的開發(fā)者,還有許多第三方服務(wù)商、企業(yè)客戶、開源工具。當我們考慮所有這些生態(tài)成員的需求時會發(fā)現(xiàn):云服務(wù)自身擁有的功能集合與客戶能使用的功能集合之間的差異比較能體現(xiàn)產(chǎn)品的開放程度。這里的差異強調(diào)的是云服務(wù)已經(jīng)擁有的,不包括云服務(wù)自身沒有的服務(wù)。客戶能使用的功能與云服務(wù)能提供的功能之間的差距越大,說明云產(chǎn)品的開放程度越低,因為很多功能都作為保留節(jié)目被雪藏了,導(dǎo)致客戶和第三方服務(wù)商無法享受與云廠商接近的服務(wù),最終生態(tài)無法拓展。理想狀況是,云服務(wù)商自身能通過API使用的功能,客戶都能通過OpenAPI使用,內(nèi)外看到的是一致的。
但具體到某個API應(yīng)不應(yīng)該開放,實踐中會做如下考慮:
針對這些問題,需要在API的管理機制上面下功夫,能夠區(qū)分不同的場景,并做好元數(shù)據(jù)的管理。針對API是否開放要有明確的規(guī)范和度量機制,確保該開放的API都可以開放,確保內(nèi)外客戶看到的功能集合基本一致,才有利于云服務(wù)更好地被集成,在客戶的業(yè)務(wù)中發(fā)揮更大的作用。
在云服務(wù)場景中,API并非孤立存在:
首先,API發(fā)布以后,用戶要想順利地使用API,配套設(shè)施必不可少,SDK、文檔、工具鏈的集成都需要考慮到,這里的重點是如何保障準確性、及時性和一致性。開發(fā)工程師一般都不太喜歡寫文檔,專業(yè)寫文檔的又可能不太懂技術(shù),再考慮到國際化的問題,就十分有挑戰(zhàn)了。SDK方面,一個API要有多種語言的實現(xiàn),每種語言還要保障其專業(yè)性、可用性,非常考驗對開發(fā)人員編程語言掌握的深度和對API的理解,業(yè)界經(jīng)常采用的自動化生成SDK的方式也會考驗對多語言的兼容能力。工具鏈比如阿里云的 API Explorer、CloudShell等產(chǎn)品也需要及時與API的最新狀態(tài)保持同步。
其次,云服務(wù)由于產(chǎn)品線眾多,如何讓用戶能夠快速學(xué)習(xí)使用API和相關(guān)工具,需要在教程、案例、運行時環(huán)境等諸多方面加強建設(shè)。圍繞云服務(wù),已經(jīng)發(fā)展出許多上層生態(tài)工具,例如terraform/ansible/spinnaker等開源軟件,它們能夠幫助云服務(wù)更好地使用起來,必須對它們提供支持,如何能夠快速覆蓋也對平臺開發(fā)能力是個考驗。
另外,API本身的質(zhì)量保障也是非常重要的。一般都要考慮性能、穩(wěn)定性、安全等方面的保障體系,通過壓測、監(jiān)控、部署防護軟件等方式來確保API在服務(wù)的時候不會掉鏈子。傳統(tǒng)的套路在解決系統(tǒng)問題時非常有效,但具體到業(yè)務(wù)問題的時候就無能為力了。例如,一個創(chuàng)建服務(wù)器的API一般來說都是要求冪等的,怎么檢測該API實際上有沒有做到冪等呢?推而廣之,其他業(yè)務(wù)流程的正確性又如何保障呢?等API開放了發(fā)現(xiàn)問題再修復(fù)就為時已晚,顯然應(yīng)該在上線前通過測試來發(fā)現(xiàn)這類問題。但是隨著業(yè)務(wù)的發(fā)展,如何能保障這類問題可以有統(tǒng)一的解決方案,能夠長期跟進及時發(fā)現(xiàn)風險避免損失呢?

阿里云API體系簡易圖
所謂量變引起質(zhì)變,上述問題針對單個API的時候都好解決,但是當API規(guī)模達到成千上萬的時候,就必須通過平臺化、系統(tǒng)化的手段來解決了。例如,API服務(wù)可靠性SLA指標如果要達到4個9,需要制定明確的標準,并且有手段監(jiān)控到所有API的運行結(jié)果,通過分析成功率來判斷其是否達到預(yù)期水平,這對云服務(wù)本身的底層系統(tǒng)建設(shè)提出了較高的要求。
所以,以API為中心完善相關(guān)體系,保障用戶體驗的一致性、及時性、穩(wěn)定性、易用性是非常有挑戰(zhàn)的。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Messages
https://tools.ietf.org/html/rfc7231#section-4
https://www.cnblogs.com/sparkdev/p/10052310.html
https://www.grpc.io/docs/guides/
https://www.terraform.io/docs/index.html
http://www.grabsun.com/article/2015/1135807.html
文章轉(zhuǎn)自微信公眾號@阿里云開發(fā)者