API 管理

已完成

那麼,我到底遇到什麼問題,而需要尋求 API 管理解決方案? 您最有可能面臨下列挑戰:

  • 調整,您的 API 由世界上不同區域的眾多用戶端所使用,您必須確保 API 可供使用且能迅速回應。
  • 安全性,您必須確定 API 是安全的,且只有授權用戶端可加以存取。
  • 錯誤管理,您必須確保 API 可以正常處理錯誤。
  • 監視,您必須監視 API 以確保其正常執行。
  • 復原能力,您必須確保 API 具有復原性,且可以正常處理失敗。

您可以選擇用單點解決方案來因應前述各項挑戰,但這可能有管理上的困難。 也請考量您的 API 可以建置在不同的技術堆疊中,這表示上述挑戰的解決方案可能需要對每個 API 使用不同的解決方案。 如果您面臨前述所有挑戰,則應考慮採用集中式 API 管理解決方案,例如 Azure API 管理。

我們將深入探討一些挑戰,並了解 Azure API 管理之類的集中式 API 管理解決方案如何協助您克服這些挑戰。

基礎結構即程式碼 (IaC)

使用 Azure 入口網站建立 Azure 資源絕對沒問題,但隨著基礎結構的成長,會變得很難管理。 浮現的問題之一是,您無法輕鬆地在其他環境中複寫基礎結構。

此外也很難追蹤基礎結構的所有變更。 這正是基礎結構即程式碼 (IaC) 發揮作用之處。 IaC 是使用程式碼來管理基礎結構的實務做法。 在 Azure 上套用 IaC 有數個選項,Bicep 是其中之一。 Bicep 是可讓您以宣告方式部署 Azure 資源的特定領域語言 (DSL)。 這是管理雲端資源的絕佳方式。 以下簡單的範例顯示 Bicep 的樣貌:

param location string = 'eastus'

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-06-01' = {
  name: 'mystorageaccount'
  location: location
  kind: 'StorageV2'
  sku: {
    name: 'Standard_LRS'
  }
}

在上述範例中,我們使用 Bicep 定義了儲存體帳戶。 我們定義了儲存體帳戶的位置、儲存體帳戶的類型,以及SKU (庫存單位)。 位置是我們在部署 Bicep 檔案時可傳入的參數。 若要部署提供的檔案,請使用 Azure CLI,如下所示:

az deployment group create --resource-group myResourceGroup --template-file main.bicep

上述命令會將儲存體帳戶部署至資源群組 myResourceGroup,並使用 Bicep 檔案 main.bicep 在檔案中建立資源。

透過負載平衡器處理負載

若問題出在您的 API 因要求而超載,新增負載平衡建構將是解方。 負載平衡器可協助您將負載分散到 API 的多個執行個體。

在 Azure API 管理服務中,定義名為後端的概念可實作負載平衡。 其概念是,設定許多對應至 API 端點的後端,然後建立負載平衡器,將負載分散到這些後端。 以下是其架構的樣貌:

負載平衡器的螢幕擷取畫面。

上述架構中發生的情況如下:

  1. 用戶端將要求傳送至 API 管理執行個體。
  2. 要求通過驗證並獲得授權。
  3. 要求隨後傳送至負載平衡器。
  4. 負載平衡器將要求分散到其中一個後端 (選取的 Azure OpenAI API 以粗體顯示)。

後端在處理要求後,將回應傳回至用戶端。

定義負載平衡器

若要在 Azure API 管理中設定負載平衡器,必須執行下列幾部分的工作:

  • 後端,要用來分散負載的後端 (數量不限)。
  • 負載平衡器,包含要用來分散負載之後端的負載平衡器。
  • 原則,將傳入呼叫導向至負載平衡器。

建立後端

若要在 Azure API 管理中建立後端,必須定義後端實體。 以下說明在 Bicep 中定義後端的方式:

resource backend2 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  parent: apimService
  name: 'backend2'
  properties: {
    url: '${openai2Endpoint}openai'
    protocol: 'http'
    circuitBreaker: {
      rules: [
        {
          failureCondition: {
            count: 3
            errorReasons: [
              'Server errors'
            ]
            interval: 'P1D'
            statusCodeRanges: [
              {
                min: 500
                max: 599
              }
            ]
          }
          name: 'myBreakerRule'
          tripDuration: 'PT1H'
        }
      ]
    }
}

在上述 Bicep 程式碼中,後端會定義為對應至 API 端點 URL,另請注意名稱 backend2,我們稍後可能會用到此名稱。 對於您的每個後端,您都應像先前的 bicep 程式碼一樣加以編碼。

注意

請記住,您可以有多個後端,因此您可以視需要定義不限數量的後端。

建立後端集區

接下來,我們想要建立後端集區,以設定要在其間分散負載的後端。 我們可以將此後端集區編碼為後端實體,如下所示:

resource loadBalancing 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
  parent: apimService
  name: 'LoadBalancer'
  properties: {
    description: 'Load balancer for multiple backends'
    type: 'Pool'
    pool: {
      services: [
        {
          id: '/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiManagement/service/${apimService.name}/backends/${backend1.id}'
        }
        {
          id: '/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.ApiManagement/service/${apimService.name}/backends/${backend2.id}'
        }
      ]
    }
  }
}

我們先前建立的後端 backend2 會與另一個後端 backend1 一起受參考,為求簡潔我們省略了後者。

我們也可以為 services 清單中的每個項目加上 priorityweight 屬性,以決定負載平衡器分散負載的方式。 以下是您可以為每個後端設定優先順序和權數的方式:

services: [
    {
      id: '/subscriptions/<subscriptionID>/resourceGroups/<resourceGroupName>/providers/Microsoft.ApiManagement/service/<APIManagementName>/backends/backend-1'
      priority: 1
      weight: 3
    }
    {
      id: '/subscriptions/<subscriptionID>/resourceGroups/<resourceGroupName>/providers/Microsoft.ApiManagement/service/<APIManagementName>/backends/backend-2'
      priority: 1
      weight: 1
    }
  ]

在上述範例中,負載平衡器分散到 backend-1 的負載比 backend-2 多出三倍。

引導傳入呼叫

最後,我們必須將任何傳入呼叫導向至此負載平衡後端。 導向指示會建立於下列 API 實體:

resource api1 'Microsoft.ApiManagement/service/apis@2020-06-01-preview' = {
  parent: apimService
  name: apiName
  properties: {
    displayName: apiName
    apiType: 'http'
    path: apiSuffix
    format: 'openapi+json-link'
    value: 'https://raw.githubusercontent.com/Azure/azure-rest-api-specs/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/preview/2024-03-01-preview/inference.json'
    subscriptionKeyParameterNames: {
      header: 'api-key'
    }
    
}

設定原則

最後,我們可在先前所述的 API 上設定原則,並將傳入呼叫導向至負載平衡器:

// policy.xml
<policies>
  <inbound>
    <base />
    <set-backend-service id="apim-generated-policy" backend-id="{0}" />
  </inbound>
  <backend>
    <base />
  </backend>
  <outbound>
    <base />
  </outbound>
  <on-error>
    <base />
  </on-error>
</policies>

var headerPolicyXml = format(loadTextContent('./policy.xml'), loadBalancing.name, 5000)

// Create a policy for the API, using the headerPolicyXml variable
resource apiPolicy 'Microsoft.ApiManagement/service/apis/policies@2020-06-01-preview' = {
  parent: api1
  name: 'policy'
  properties: {
    format: 'rawxml'
    value: headerPolicyXml
  }
}

我們所做的就是建立原則,將傳入呼叫導向至負載平衡器。 set-backend-service 原則用來將傳入呼叫導向至負載平衡器。 backend-id 屬性設定為我們先前建立之負載平衡器的名稱。

這些要件都就緒後,您的 API 管理執行個體即達到負載平衡。 現在,您可以將更多後端新增至負載平衡器,藉以調整 API。

斷路器

斷路器是您想要保護 API 不因要求而超載時所使用的功能。 其運作方式是定義一組規則,符合規則時即觸發斷路器,並停止將要求傳送至後端。 在 Azure API 管理中,您可以藉由設定後端及定義斷路器規則,來定義斷路器。 其具體做法如下:

resource backend2 'Microsoft.ApiManagement/service/backends@2023-09-01-preview' = {
      parent: apimService
      name: 'backend2'
      properties: {
        url: '${openai2Endpoint}openai'
        protocol: 'http'
        circuitBreaker: {
          rules: [
            {
              failureCondition: {
                count: 3
                errorReasons: [
                  'Server errors'
                ]
                interval: 'P1D'
                statusCodeRanges: [
                  {
                    min: 500
                    max: 599
                  }
                ]
              }
              name: 'myBreakerRule'
              tripDuration: 'PT1H'
            }
          ]
        }
       }
     }

上述後端定義中有一個屬性 failureCondition,會定義斷路器跳開的時機。 在此案例中,如果一天內發生三個伺服器錯誤,斷路器就會跳開。 tripDuration 屬性會定義斷路器在再次關閉之前應保持開啟的時間長度。 為您在 API 管理執行個體中擁有的每個後端定義斷路器,是很好的做法。

受控識別

我們需處理的另一個問題是安全性。 您想要確定 API 是安全的,且只有授權用戶端可加以存取。 保護 API 的方法之一,是使用受控識別。 受控識別是向其他 Azure 服務驗證 API 的一種方法。 在 Azure API 管理中,您必須在數個位置套用受控識別,即:

  • APIM 執行個體層級,您可以將 identity 屬性設定為 SystemAssigned,以在 APIM 執行個體中啟用受控識別,如下所示:

    resource apimService 'Microsoft.ApiManagement/service@2023-09-01-preview' = {
        name: name
        location: location
        tags: union(tags, { 'azd-service-name': name })
        sku: {
        name: sku
        capacity: (sku == 'Consumption') ? 0 : ((sku == 'Developer') ? 1 : skuCount)
        }
        properties: {
            publisherEmail: publisherEmail
            publisherName: publisherName
        // Custom properties are not supported for Consumption SKU
        }
        identity: {
            type: 'SystemAssigned'
        }
    }
    

    此動作會為 APIM 執行個體產生後續可用於 APIM 執行個體的受控識別,例如 Azure OpenAI 執行個體。

  • API 層級,對於 API 執行個體,您可以將其與原則產生關聯。 在此原則中,您可以新增受控識別運作所需的指示:

    <policies>
      <inbound>
        <base />
        <authentication-managed-identity resource="https://cognitiveservices.azure.com" output-token-variable-name="managed-id-access-token" ignore-error="false" /> 
    
        <set-header name="Authorization" exists-action="override"> 
          <value>@("Bearer " + (string)context.Variables["managed-id-access-token"])</value> 
      </set-header> 
      </inbound>
      <backend>
        <base />
      </backend>
      <outbound>
        <base />
      </outbound>
      <on-error>
        <base />
      </on-error>
    </policies>
    

    請參閱上述對 authentication-managed-identityset-header 的呼叫,這些指示可確保受控識別會套用至 API。

  • 後端層級,最後,將您的後端指向 Azure OpenAI 執行個體。 我們必須將 APIM 執行個體與 Azure OpenAI 執行個體連線。 若要進行此連線,請參考以下 Bicep 指示:

    resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
      name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId)
      properties: {
        principalId: principalId
        principalType: "ServicePrincipal"
        roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
      }
    }
    

    上述 Bicep 指示的概念,是建立 APIM 執行個體與 Azure OpenAI 執行個體之間的角色指派。 在此案例中:

    • principalId 是來自 APIM 執行個體的身分識別碼。
    • roleDefinitionId 是特定使用者,在此案例中為名為「認知服務使用者」的使用者,這是有權存取 Azure OpenAI 執行個體的使用者。
    • name,此屬性可確保角色指派會套用至正確的範圍,在此案例中為特定的訂用帳戶和資源群組。 (必須是與 Azure OpenAI 執行個體相同的資源群組)

檢定您的知識

1.

可能讓您尋求 API 管理解決方案的主要挑戰之一為何?

2.

管理 Azure 資源時,基礎結構即程式碼 (IaC) 有何作用?

3.

API 管理中的斷路器有何用途?