雲平臺SDK攻略

微軟技術棧發表於2022-05-01

作為一個雲原生的開發者,你會最關注哪方面的開發體驗?在你的應用中與雲上的資源進行互動肯定是你非常在意的吧,不管是往Service Bus中傳送一條訊息,亦或是為更大的運算需求建立新的虛擬機器。你可以利用雲平臺的SDK,比如Azure SDK來完成所有這些操作,那麼Azure SDK是如何寫出來的呢?一個雲平臺的SDK和一個傳統的SDK有何區別?

傳統SDK和雲平臺SDK之間的不同

傳統SDK, 比如說.NET SDK或者JAVA SDK,都是.NET執行時(.NET CLR)或者JAVA執行時(JVM)的程式設計介面,他們之間的“通訊協議”是在程式內的,基於二進位制的。
雲平臺SDK通常基於OpenAPI定義。OpenAPI更像是一個跨程式的基於RESTFul HTTP APIs的通訊協議,OpenAPI雲端計算的世界中無處不在,但是OpenAPI有其自己的侷限性。

利用OpenAPI和Azure進行互動時候會遇到的問題

OpenAPI是一個REST API Service的介面定義,對於任何一個程式語言來說,他都不是一個開箱即用的解決方案。當一個開發者想要開始使用OpenAPI, 他通常會遇到下面的一些問題:

  • 異常處理
  • 長時間執行操作的處理
  • 分頁操作處理
  • HTTP Client生命週期管理

為這些處理構建健壯的程式碼並不是一件容易的事情。這種情況下,引入SDK就變成了一種很自然地選擇。

微軟是如何從OpenAPI中生成Azure SDK的

Azure SDK的設計遵從了通用SDK庫設計指導,這份指導綱要確保了在不同Azure Service之間一致的SDK使用體驗,從2022年3月31號開始,我們對不符合指導綱要版本的SDK庫開始了逐步淘汰。

為一個新的Azure Service建立SDK,Azure SDK團隊緊密合作,常見的工作步驟如下:

  1. Azure Service團隊定義好OpenAPI說明(Swagger file),並且在REST API specification repository起一個PR。
  2. Azure SDK 團隊會稽核新的OpenAPI說明,確保裡面沒有破壞性變更,語法錯誤等等。
  3. Azure SDK 團隊利用AutoRest從OpenAPI說明當中生成客戶端庫。AutoRest是微軟建立的一個開源客戶端庫生成工具來訪問Restful web services. AutoRest利用不同語言的擴充來為不同程式語言生成Restful web service的客戶端庫。
  4. 我們會稽核生成出來的客戶端庫,並起一個PR到相應語言SDK的Github repository. 我們有一個非常棒的內部工程平臺對這些客戶端庫進行測試,以確保我們不會引入任何regression issue。這些測試包括自動生成的測試和手寫測試,但是在未來我們會更多的依賴自動生成的測試用例。
  5. 一旦所有檢查都通過了,這個新生成的客戶端庫就會被合併到相應語言的SDK Github Repository。
  6. 在客戶端庫被合併到相應語言的SDK Github repository之後,相應的持續整合和部署管線就會被觸發,如果一切無誤,新的客戶端庫就會被髮布到相應語言的包管理器,如nuget, npm等等。
  7. 所有SDK相關文件,樣例程式碼也會陸續得到更新。

AutoRest是整個客戶端庫生成過程當中的關鍵。AutoRest知道常見模式的REST API呼叫,並在客戶端庫中將這些呼叫暴露成對於開發者友好的程式設計介面。比如說,長時間執行的操作(Long-running operation, LRO)以及一些資源建立,刪除等無法立即知道操作結果的REST API呼叫。這些情況下,伺服器會返回一個201(Created)或者202(Accepted)狀態碼,並附帶一個連結來持續監測請求的完成狀態。這個操作行為對於直接的RESTFul API呼叫是合理的,但是從程式語言的角度來看這是有問題的,這種操作應該被轉變成一個帶回撥函式的非同步操作,回撥函式允許開發者為LRO操作的成功或失敗編寫相應程式碼。OpenAPI, 很不幸的,沒有這種非同步語法上的支援。為了能夠支援這種操作,微軟定義了一系列AutoRest OpenAPI擴充來豐富OpenAPI的語法。

現在讓我們回到之前的LRO場景。我們可以在OpenAPI中定義一個x-ms-long-running-operation。比如說,下面的定義是一個建立/更新Azure VM的OpenAPI定義(完整定義可在這裡找到)

"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}": {
      "put": {
        "tags": [
          "VirtualMachines"
        ],
        "operationId": "VirtualMachines_CreateOrUpdate",
        "description": "The operation to create or update a virtual machine. Please note some properties can be set only during virtual machine creation.",
        "parameters": [
          {
            "name": "resourceGroupName",
            "in": "path",
            "required": true,
            "type": "string",
            "description": "The name of the resource group."
          },
          {
            "name": "vmName",
            "in": "path",
                        "required": true,
            "type": "string",
            "description": "The name of the virtual machine."
          },
          {
            "name": "parameters",
            "in": "body",
            "required": true,
            "schema": {
              "$ref": "#/definitions/VirtualMachine"
            },
            "description": "Parameters supplied to the Create Virtual Machine operation."
          },
          {
            "$ref": "#/parameters/ApiVersionParameter"
          },
          {
            "$ref": "#/parameters/SubscriptionIdParameter"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "schema": {
              "$ref": "#/definitions/VirtualMachine"
            }
          },
          "201": {
            "description": "Created",
            "schema": {
              "$ref": "#/definitions/VirtualMachine"
            }
          },
          "default": {
            "description": "Error response describing why the operation failed.",
            "schema": {
              "$ref": "#/definitions/CloudError"
            }
          }
        },
        "x-ms-long-running-operation": true
      }
   }

有了上面的OpenAPI定義,我們生成的客戶端庫中的BeginCreateOrUpdate方法呼叫就變成了下面的樣子,以Go語言為例(完整程式碼可在這裡找到)

pollerResponse, err := vmClient.BeginCreateOrUpdate(ctx, resourceGroupName, vmName, parameters, nil)
    if err != nil {
        return nil, err
    }
​
    resp, err := pollerResponse.PollUntilDone(ctx, 10*time.Second)
    if err != nil {
        return nil, err
    }
}

上述程式碼中的Poller類來自於Azure Core專案。Azure Core提供了整個Azure SDK的基礎架構,比如說HTTP Client的生命週期管理,異常處理。利用Azure Core, 我們就可以在OpenAPI中定義更多的擴充,並將這些擴充轉變成更加開發者友好的客戶端庫語法,常見的OpenAPI擴充有:

  • X-ms-error-response:該擴充可以確定是否把一些http返回狀態碼對映成為一個錯誤
  • X-ms-pageable:該擴充可以將返回的list對映成為一個可分頁的結果

更多的擴充,請參見AutoRest Extensions for OpenAPI

我們討論了使用雲SDK的好處以及微軟構建雲SDK的流程,感謝您的閱讀。



長按識別二維碼
關注微軟中國MSDN

相關文章