雲服務 OpenAPI 的 7 大挑戰,架構師如何應對?

Moting發表於2019-10-16

來源 | 阿里技術官方公眾號(ali_tech)雲服務 OpenAPI 的7大挑戰,架構師如何應對?

雲服務 OpenAPI 的7大挑戰,架構師如何應對?_0.webp

阿里妹導讀:API 是模組或者子系統之間互動的介面定義。好的系統架構離不開好的 API 設計,而一個設計不夠完善的 API 則註定會導致系統的後續發展和維護非常困難。比較好的API設計樣板可以參考 Github 和 K8s,它們都是典型的 RESTful 介面。雲服務對外開放的視窗就是 OpenAPI,今天要討論的話題是“雲服務場景下 OpenAPI 設計的挑戰”。

為什麼要有 API 規範

之所以強調“雲服務”的原因在於,小規模獨立 API 的設計與大規模批次生產 API 面臨的問題是不一樣的。同樣,只專注於自身產品 API 的可用性與從更高的層次去看雲服務整體 API 體系的健壯性,要建設的體系也是不一樣的。

例如,做一個 WEB 頁面使用的 API,只需要考慮效能、穩定性、鑑權就好,因為頁面與 API 是一體的,可以一起釋出和回滾,只要功能正常,即便 API 設計有缺陷,使用者也可以接受。而云服務要開放 API 考慮問題就多了:

  • 首先,雲服務開放的是基礎設施和服務介面,一般是系統級的對接,API 一旦開放想要變更就非常困難;

  • 其次,雲服務並非單獨執行,不同的產品實際場景中是互相組合的,需考慮產品間的一致性和互通便利性;

  • 雲服務 API 數量龐大,為了更方便使用,配套的 API 查詢、編排、自動化生成SDK等需求也比普通服務強烈;

  • 雲服務的穩定性非常重要,核心產品的穩定性就是客戶的生命線,要求非常高。

所以雲服務由於產品線眾多,需要統一的 API 規範來保證雲產品間 API 體驗一致,在底層平臺層面互相相容,便於上層應用平臺化,同時要兼顧到圍繞公有云服務的第三方生態、開源生態、企業生態。

在具體規範層面,業界也在不斷嘗試,比較知名的是 OpenAPI Specfication 和 Google API Design Guide。前者針對 RESTful API 設計在細節層面給出了非常具體的規定,已經成為 RESTful API 設計領域的事實標準,而後者則主要從雲廠商的角度提出許多最佳實踐性質的規範與建議,這些原則不僅僅適用於 RESTful API ,也適合其他型別 API 設計。對 API 設計感興趣的開發者,可以詳細研究一下資料。

2018年Openapi Specification釋出了3.0版本
圖片來源:https://swagger.io/

因此,對於雲服務商來說,在關鍵環節制定明確的 API 規範有助於雲服務對內提高產品間互通的效率,對外提供一致的使用體驗,有助於雲服務更好地被整合。那麼要做好雲服務的橫向規範會碰到哪些困難呢?本文就從實踐中總結了 7 大挑戰。

挑戰1:選擇 API 設計模式

當你在考慮單個產品的 API 表現形式時,首先會選擇一種具體的 API 風格,常見的有 RPC(Remote Procedure Call) 和 ROA(the Rest-Oriented Architecture) 兩種模式,然後針對複雜的資料結構你會考慮使用什麼樣的序列化協議,常見的包括 Json/Xml/WSDL/Hessian 等,用於封裝傳輸資料。但涉及到不同的產品時,在具體選型時考慮的問題可能就不太一樣了。

gRPC示意圖
圖片來源:https://www.grpc.io/docs/guides/

雖然 RESTful 設計風格曝光率很高,但並不是所有云服務商都選擇了完全遵循 RESTful,例如 AWS 和阿里雲 RPC 風格反而佔了大多數,Google 和 Azure 則 RESTful居多。

Restful API 的優勢是 HTTP 具備更好的易用性,讓異構系統更容易整合,且開發執行效率比較高,面向資源要求也比較高。而 RPC API 可以使用更廣泛的框架和方案,技術層面更底層也更為靈活,設計起來相對簡單,掌握起來有一定門檻,架構上更加複雜。

RESTful 與 RPC 模式對比

不同的團隊根據實際情況和業務形態可能選擇不同的方案,那雲服務作為一個整體應該強制統一好還是隨意選擇好?如果強制統一風格,有些適合 RESTful風格的服務非要使用 RPC 的話,看起來就會比較醜陋,如果只是一個過程化的服務呼叫,往 RESTful 資源化設計方向去靠會比較困難。但如果不強制使用統一風格,會造成針對 API 的體系化支援會更加複雜,例如為相容兩種風格 SDK 的自動化支援需要兩套程式碼。

通常 RESTful 風格對 API 設計者的要求是比較高的,主要的難點在於面向資源設計要求開發者事先做好規劃,將後端資料模型與 API 服務模型相匹配。所以 RESTful API 的開發者應該是熟知系統整體實體關係模型的,很難想象一個不懂後臺業務的新手能設計出合理的 API 來。那麼是不是 RPC 風格 API 就不需要面向資源設計了呢?從實踐中來看,並不是!RPC 風格的 API 也需要資源模型來支援,在下一節中會重點分析。

所以,對於雲服務商來說,選擇 API 風格時要考慮幾個問題:

  • 選擇支援哪種風格,才能更好地體現業務特性,讓客戶操作起來更加方便;

  • 設計 API 時能否面向資源設計,相應的工程人員是否具備做這種設計的能力;

  • 針對這種風格工具鏈的支援是否到位,投入產出比如何;

  • 業界流行的趨勢如何,是否需要考慮與其他系統體系的互操作。

選定了具體設計模式後,就要努力做到統一,避免多種模式混雜帶來管理成本的上升。 如果確實有必要兩種方式都支援(例如阿里雲就同時支援 RPC 和 ROA),就需要在技術上做好充分的準備。

挑戰2:面向資源設計 API

使用者使用 API 來訪問雲服務,本質上是想透過對某種雲資源執行特定的操作來完成一個業務動作。Restful API 需要面向資源設計眾所周知,那為什麼RPC介面在雲服務場景下也需要有資源模型呢?

RPC 形式的 API 組織形態是領域和行為(物件和方法),隨著時間的推移, API 越來越多最終形成一個龐大的集合。以阿里云為例,對外開放的 OpenAPI 數量已經達到 10000 多個,涵蓋了接近 200 個不同的產品。因為開發者必須單獨學習每個 API ,耗時又容易出錯,如果沒有一個脈絡的理解起來比較困難。 如果有一套標準的資源模型, API 就可以按照資源模型的維度分類組織,使用者使用起來也會有跡可循 ,體驗上會更好,否則面對如此多的 API 一點點學習無疑是個痛苦的過程。

另外,雲服務並非單個服務的簡單排列,它是多個體系的橫向整合,總體對外呈現出有機連線。隨著雲端計算的發展,企業客戶對對雲服務的要求不斷提高。最典型的就是當企業客戶大規模開始上雲後,對虛擬化的雲產品提出了各種管理需求,例如鑑權、編排、彈性伸縮等。

企業客戶對雲服務的管理需求

以最常用的鑑權功能為例,客戶建立了一組雲伺服器來跑業務,運維人員需要有重啟伺服器的許可權,其他角色人員則不需要此類許可權,針對RestartServer這麼一個 API 就需要進行許可權控制了。許可權在雲平臺中一般是中心式管理的,單獨的雲產品不需要分別管理。如果統一處理鑑權,就需要知道當前 API 正在操作什麼資源,與此相關的資源有哪些(例如與伺服器有關的資源包括磁碟、網路卡、網路等關聯資源),然後針對所有相關資源逐一鑑權才能確認 API 操作是否可行。

上面提到的資源有兩個關鍵點,一是要有統一的資源模型,便於雲產品對特定的 API 進行鑑權,二是要明確資源關係,當出現資源依賴的時候,需要關聯鑑權。在 Google 的 API Guide 中就明確提到需要資源關係,可以看出資源關係不僅僅是用來做 API 設計建模的,它對於平臺功能的實現也有至關重要的作用。不瞭解資源關係,有可能把多個資源封裝到一個 API 中,使用和變更都很痛苦,即便後期發現了問題再補救拆開,由於很多使用者已經在使用了,要付出的開發成本和溝通成本也是極大的,甚至成為不可能。所以 清晰的資源模型有利於梳理清楚 API 體系。

定義清晰的實體關係圖有助於設計出更為完整的 API

而且,明確的資源模型對於構建雲上運維管理基礎設施至關重要,例如可以透過對資源打 Tag 來對資源進行分類管理(參考阿里雲資源 Tag ),分組授權(參考阿里雲資源組),資源審計(參考阿里雲 CloudConfig ),類似開源軟體 Terraform 這樣的編排工具,由於有資源模型會更容易接入和使用。

所以,統一的資源模型對雲服務的幫助是巨大的:

  • 它可以使 API 具有更清晰的結構,幫助使用者理解;

  • 它可以幫助對比 API 與後臺實體關係模型,更容易提供更完整的 API 服務;

  • 它可以使產品協作更加順暢,對資源的操作也更加規範化;

  • 它可以使雲服務底層平臺實現起來更統一、更方便;

  • 它可以使圍繞 API 的生態整合起來更加簡單、高效。

既然有這麼多好處,那麼眾多的雲產品在實際設計 API 的時候能否堅持以資源為中心,充分考慮到上下游的需求就變成一個很大的挑戰了。

挑戰3: API 設計風格

確定了設計模式和資源模型後,是時候進入到 API 設計細節了。諸如 API 名稱、引數名、屬性名稱、資料格式、錯誤碼之類的資訊,看起來根本不是問題。單個產品問題還不大,只要保證內部風格一致即可,如果考慮到雲服務多產品對外的整體體驗,就有必要考慮以下問題:

  • 在 API 命名的時候,遵循什麼樣的正規化來確保大體風格相似?動詞、名詞、介詞如何組合才能保持 API 風格看起來比較統一,降低理解成本?

  • 對於類似的操作,有沒有使用規範?有哪些公共的標準詞彙使得同型別的操作可以比較容易理解,避免使用晦澀奇怪的詞彙(例如讀操作,Read/Query/Describe/List/Get 中都在什麼場合使用什麼動詞)?

  • 被廣泛使用的引數如何儘可能保持一致,避免不同產品的表達混亂的情況(例如分頁引數用 PageNumber 還是 PageNum)?

  • 對於常用的場景,例如冪等、分頁、非同步 API 的設計有沒有統一的規範,避免使用體驗不一致?

  • 錯誤碼應該怎麼設計?公共錯誤碼怎麼統一,業務錯誤碼怎麼表達?

上述問題都是實際研發過程中要注意的,要全部羅列的話遠不止這些。 API 的用詞描述是雲服務展現給外部使用者的第一印象,絕非隨意寫就。對人員有一定規模,內部有多條產品線的組織來說,如何協調組織的各個部分對外具有統一的體驗是個很大挑戰。

回顧下HTTP協議,最廣為認知的是對HTTP Mehod的約定,使用9個單詞就完成了對基本動作的規範,為開發者提供了清晰的思維模型:

Http Method 型別
圖片來源:https://tools.ietf.org/html/rfc7231

同樣,在 HTTP Header 裡面也對瀏覽器資訊、語言、網路連線屬性等做了詳細的規定,這樣開發者在使用 HTTP 服務的時候都有一個大致的約定,在關鍵資訊上面不會有偏差,保障了異構系統的介面一致性。

因此雲服務在管理 API 時應該考慮一些具體的規範,對命名規則、標準詞彙、最佳實踐模式、錯誤碼等資訊都有明確的規定,同時用系統化、平臺化的手段來管理 API ,確保不走偏。設計風格不是雲服務 API 設計中致命的問題,但是它關乎雲服務外表形象,不可不察。

挑戰4:服務端容錯處理

API 是後端服務的外部表達,是服務就有可能出現問題,無論這個問題是可預期的還是不可預期的。如果只考慮功能本身功能特性,而忽視對異常情況的設計,當問題出現的時候業務本身可能無法感知造成服務異常,更重要的是站在客戶角度去看,不能有效獲取錯誤原因是非常痛苦的,很多時候只能束手無策,降低雲服務提供商的整體口碑,甚至損害營收。

假設有個建立資源的 API ,每呼叫一次都會建立新的資源,考慮以下情況:

  • 同樣的請求多次提交,是否會重複建立資源?
  • 請求處理時間過長,客戶端是長時間等待,還是先非同步返回一個任務ID?
  • 如果需要等待,Timeout 最大值是多少?
  • 如果 Timeout 最大值達到,客戶端的策略是重試還是放棄
  • 如果最終處理還是失敗了,具體是哪個環節的問題?如何給出準確的錯誤資訊?
  • 如果非同步方式,非同步處理完成後是主動查詢還是另有通知?
  • 第三方工具和整合商到哪裡去獲取這些資訊?能不能有標準化的處理?

實踐中,如果不做好問題 a 的處理,可能會造成系統異常情況下大批資源被重複建立,有可能造成使用者或雲服務商資損;問題 b-e 沒有處理好,可能會讓使用者陷入盲目等待或者盲目重試,使用體驗和效率極差;而 f-g 關係到自動化處理工具如何做到效率最大化,也關係到被整合的效率。

一個非同步重試的狀態機

當出現異常的時候, API 一般是要靠錯誤碼來告知使用者有什麼問題。HTTP 協議本身對錯誤碼做出了詳盡的規定,Restful 的 API 要儘可能地符合標準。除此之外,雲服務有必要在此基礎上進一步提供業務錯誤碼和錯誤資訊,來描述錯誤具體的細節。

當前雲服務的錯誤碼很多,看起來非常專業,但問題主要集中在以下幾個方面:

1.錯誤型別過多: 錯誤碼越多客戶端處理起來越方便嗎?看一下 HTTP 的錯誤碼,只有 5 大類加幾十個子類的錯誤碼就涵蓋了所有場景,而通常大家耳熟能詳的無非是 200、400、404、500、502 等屈指可數的狀態碼。有的人考慮錯誤碼越多,客戶端可以 switch/case 一下針對每個錯誤碼做不同的操作,這個就見仁見智了,一般的程式設計師可能不會寫那麼多的分支流程,必要性也不大。

2.錯誤資訊表達不夠充分: 相比於提供大量的錯誤碼,錯誤資訊的明確表達更為重要。如果錯誤資訊不夠詳細,作為使用者不瞭解細節無法掌控的雲服務,幾乎是無法明確發生了什麼,要麼提工單,要麼只能被動等待,客戶體驗很差。

3.業務錯誤碼與HTTP錯誤碼含義不匹配: 例如引數錯誤應該返回 4xx 系列 Code,返回 5xx 系列就不夠專業。即便是 RPC 風格的 API,也要大致符合 HTTP 規則,否則可能會給一些依賴 HTTP Code 的系統造成誤導。網上有種思路覺得無論後臺響應如何,HTTP Code 統統返回 200,在 Body 裡面的錯誤資訊體現異常資訊,這種不利於對介面的監控,因為監控系統很難透過識別訊息體來鑑別功能是否正常響應。

4.相同錯誤不同雲產品表達不一致: 這會給客戶端開發造成困擾,增加開發工作量,不利於自動化整合,使用者體驗比較差。

5.錯誤碼應該是可列舉集合: 一個 API 能夠產生的錯誤碼型別應該是可預期的,即便是業務升級,也應該給客戶提供明確的錯誤碼列表,不能隨心所欲。因為使用者端需要明確知道可能會發生什麼,而不是隨時可能出現不可預知的錯誤型別。如果錯誤型別不確定,就意味著針對錯誤碼分支處理基本是無效的。

要做好服務端容錯上述問題,需要從雲服務整體層面加強 API 的容錯設計,做好錯誤碼規範,加強對錯誤資訊的管理,來提升使用者體驗。

挑戰5:版本管理

API 都是不斷迭代的,通常都需要版本管理。雲服務 API 的版本管理尤其重要,主要是以下原因:

  • 雲服務 API 直接面向使用者,由於呼叫量大,變更影響的使用者範圍也更廣,版本變更要非常謹慎;

  • 雲服務有多種形態,主要是公有云、私有云、細分的行業雲等,不同的雲對同樣功能 API 的要求可能不一樣, API 更加多樣化。既要保障不同版本功能正常,又要能快速部署維護不同版本,挑戰很大;

  • 不相容變更的推廣極其困難,很難讓使用者在短時間內快速升級,維護多版本 API 成本很高;

  • 必須變更的情況,要確保呼叫方能夠及時感知並且平滑切換的技術難度很大。

針對 API 各種場景的管理,需要一套成熟的 API 管理平臺,照顧到各種場景的需求,也是一項不小的挑戰。

挑戰6: API 該如何開放

API 如何開放看起來是奇怪的問題,難道 API 做出來不就是開放給別人用的嗎?做好就開放就開放啊?但在雲服務場景下,情況會更復雜一點!

產品技術都是在不斷迭代的,功能始終在增加,新的 API 層出不窮。從客戶視角來看,他們對已開發完畢的 API 是否開放的需求是什麼?假設一個雲產品有 100 個功能特性,20 個只能保留在內部,官網上總共提供了 80 個特性,而公開 API 只開放了 50 個,這是使用者期望的狀態嗎?理想狀態應該是什麼?

圍繞雲服務有一個龐大的生態,除了普通的開發者,還有許多第三方服務商、企業客戶、開源工具。當我們考慮所有這些生態成員的需求時會發現:雲服務自身擁有的功能集合與客戶能使用的功能集合之間的差異比較能體現產品的開放程度。這裡的差異強調的是雲服務已經擁有的,不包括雲服務自身沒有的服務。客戶能使用的功能與雲服務能提供的功能之間的差距越大,說明雲產品的開放程度越低,因為很多功能都作為保留節目被雪藏了,導致客戶和第三方服務商無法享受與雲廠商接近的服務,最終生態無法擴充。 理想狀況是,雲服務商自身能透過 API 使用的功能,客戶都能透過 OpenAPI 使用,內外看到的是一致的。

但具體到某個 API 應不應該開放,實踐中會做如下考慮:

  • API 剛剛上線尚未打磨充分,貿然開放可能會留下隱患,再想調整為時已晚,所以選擇先不開放。

  • API 本身並非原子化,封裝了若干業務場景,主要目的是最佳化效能或者服務特定的客戶,並不需要開放給所有使用者;而且當業務場景發生變化的時候,調整起來也比較困難,不適合開放出去。

  • 某些 API 不適合開放給全部使用者,只能部分開放,例如特定行業專業的 API。

  • API 僅供特定場景或私有場景使用,需要外部能夠訪問,但是不能開放給使用者。

針對這些問題,需要在 API 的管理機制上面下功夫,能夠區分不同的場景,並做好後設資料的管理。針對 API 是否開放要有明確的規範和度量機制,確保該開放的 API 都可以開放,確保內外客戶看到的功能集合基本一致,才有利於雲服務更好地被整合,在客戶的業務中發揮更大的作用。

挑戰7:API 體系如何打通

在雲服務場景中,API 並非孤立存在:

首先,API 釋出以後,使用者要想順利地使用 API,配套設施必不可少,SDK、文件、工具鏈的整合都需要考慮到,這裡的重點是如何保障準確性、及時性和一致性。開發工程師一般都不太喜歡寫文件,專業寫文件的又可能不太懂技術,再考慮到國際化的問題,就十分有挑戰了。SDK 方面,一個 API 要有多種語言的實現,每種語言還要保障其專業性、可用性,非常考驗對開發人員程式語言掌握的深度和對 API 的理解,業界經常採用的自動化生成SDK的方式也會考驗對多語言的相容能力。工具鏈比如阿里雲的 API Explorer、CloudShell 等產品也需要及時與 API 的最新狀態保持同步。

其次,雲服務由於產品線眾多,如何讓使用者能夠快速學習使用 API 和相關工具,需要在教程、案例、執行時環境等諸多方面加強建設。圍繞雲服務,已經發展出許多上層生態工具,例如 terraform/ansible/spinnaker 等開源軟體,它們能夠幫助雲服務更好地使用起來,必須對它們提供支援,如何能夠快速覆蓋也對平臺開發能力是個考驗。

另外,API 本身的質量保障也是非常重要的。一般都要考慮效能、穩定性、安全等方面的保障體系,透過壓測、監控、部署防護軟體等方式來確保 API 在服務的時候不會掉鏈子。傳統的套路在解決系統問題時非常有效,但具體到業務問題的時候就無能為力了。例如,一個建立伺服器的 API 一般來說都是要求冪等的,怎麼檢測該 API 實際上有沒有做到冪等呢?推而廣之,其他業務流程的正確性又如何保障呢?等 API 開放了發現問題再修復就為時已晚,顯然應該在上線前透過測試來發現這類問題。但是隨著業務的發展,如何能保障這類問題可以有統一的解決方案,能夠長期跟進及時發現風險避免損失呢?

阿里雲 API 體系簡易圖

所謂量變引起質變,上述問題針對單個 API 的時候都好解決,但是當 API 規模達到成千上萬的時候,就必須透過平臺化、系統化的手段來解決了。例如, API 服務可靠性SLA指標如果要達到 4 個 9,需要制定明確的標準,並且有手段監控到所有 API 的執行結果,透過分析成功率來判斷其是否達到預期水平,這對雲服務本身的底層系統建設提出了較高的要求。

所以,以 API 為中心完善相關體系,保障使用者體驗的一致性、及時性、穩定性、易用性是非常有挑戰的。

參考文獻:
https://developer.mozilla.org/en-US/docs/W...
https://tools.ietf.org/html/rfc7231#sectio...
https://www.cnblogs.com/sparkdev/p/1005231...
https://www.grpc.io/docs/guides/
https://www.terraform.io/docs/index.html
http://www.grabsun.com/article/2015/113580...

end

本作品採用《CC 協議》,轉載必須註明作者和本文連結
雨暮青

相關文章