API-hantering

Slutförd

Så vad är problemet jag har som gör att jag vill söka efter en API-hanteringslösning? Du har förmodligen följande utmaningar:

  • Skalning, API:er eller API:er används av många klienter i olika regioner i världen och du måste se till att det är tillgängligt och responsivt.
  • Säkerhet, du måste se till att ditt API är säkert och att endast auktoriserade klienter kan komma åt det.
  • Felhantering, du måste se till att api:et kan hantera fel på ett korrekt sätt.
  • Övervakning, du måste övervaka dina API:er för att säkerställa att de fungerar som förväntat.
  • Motståndskraft, du måste se till att ditt API är motståndskraftigt och kan hantera fel på ett smidigt sätt.

För var och en av dessa utmaningar kan du välja en punktlösning, men det kan vara svårt att hantera. Tänk också på att dina API:er kan byggas i olika teknikstackar, vilket innebär att lösningarna på ovanstående utmaningar kan innebära att du behöver olika lösningar för varje API. Om du har alla dessa utmaningar bör du överväga en centraliserad API-hanteringslösning som Azure API Management.

Nu ska vi gå djupare in på några utmaningar och se hur en centraliserad API-hanteringslösning som Azure API Management kan hjälpa dig att hantera dem.

Infrastruktur som kod, IaC

Det är helt okej genom att skapa dina Azure-resurser med hjälp av Azure Portal, men när infrastrukturen växer blir det svårare att hantera. Ett av problemen du står inför är att du inte enkelt kan replikera infrastrukturen i en annan miljö.

Det är också svårt att spåra alla ändringar som görs i infrastrukturen. Det är i den här situationen som infrastruktur som kod (IaC) kommer in. IaC är en metod för att hantera infrastrukturen med hjälp av kod. Om du vill tillämpa IaC på Azure har du flera alternativ, varav ett är Bicep. Bicep är ett domänspecifikt språk (DSL) för distribution av Azure-resurser deklarativt. Det är ett bra sätt att hantera dina molnresurser. Här är ett enkelt exempel på hur Bicep ser ut:

param location string = 'eastus'

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

I föregående exempel definierade vi ett lagringskonto med Bicep. Vi definierade platsen för lagringskontot, typen av lagringskonto och SKU :n (lagerhållningsenhet). Plats är en parameter som vi kan skicka in när vi distribuerar Bicep-filen. För att distribuera filen som presenteras använder vi Azure CLI så här:

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

Föregående kommando distribuerar lagringskontot till resursgruppen myResourceGroup och använder Bicep-filen main.bicep för att skapa resurserna i filen.

Hantera belastning via en lastbalanserare

Att lägga till en belastningsutjämningskonstruktion är svaret när problemet är att ditt API överbelastas av begäranden. En lastbalanserare kan hjälpa dig att distribuera belastningen över flera instanser av ditt API.

I Azure API Management-tjänsten implementeras belastningsutjämning genom att du definierar ett koncept som kallas serverdelar. Tanken är att du konfigurerar många serverdelar som motsvarar dina API-slutpunkter och sedan skapar en lastbalanserare som distribuerar belastningen över dessa serverdelar. Så här ser arkitekturen ut:

Skärmbild av en lastbalanserare.

Det som händer i den föregående arkitekturen är:

  1. Klienten skickar en begäran till API Management-instansen.
  2. Begäran autentiseras och auktoriseras.
  3. Begäran skickas sedan till lastbalanseraren.
  4. Lastbalanseraren distribuerar begäran till en av serverdelarna (valt Azure OpenAI-API anges i fetstil).

Serverdelen bearbetar begäran och skickar ett svar tillbaka till klienten.

Definiera lastbalanseraren

Om du vill konfigurera en lastbalanserare i Azure API Management måste du göra följande:

  • Serverdelar, så många serverdelar som du vill distribuera belastningen på.
  • Lastbalanserare, en lastbalanserare som innehåller de serverdelar som du vill distribuera belastningen över.
  • En princip som dirigerar inkommande anrop till lastbalanseraren.

Skapa serverdelarna

Om du vill skapa en serverdel i Azure API Management måste du definiera en serverdelsentitet. Så här kan du definiera en serverdel i 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'
        }
      ]
    }
}

I föregående Bicep-kod definieras en serverdel som motsvarar en API-slutpunkts-URL. Observera även att namnet backend2 det här namnet är något vi kan använda senare. För varje serverdel du har bör du koda den som föregående bicep-kod.

Kommentar

Kom ihåg att du kan ha flera serverdelar så att du kan definiera så många serverdelar du vill.

Skapa serverdelspool

Sedan vill vi skapa en serverdelspool som konfigurerar vilka serverdelar som vi vill distribuera belastningen mellan. Vi kan koda den här serverdelspoolen som en serverdelsentitet så här:

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}'
        }
      ]
    }
  }
}

Serverdelen som vi skapade tidigare, backend2, refereras tillsammans med en annan serverdel backend1, den senare utelämnade vi för korthet.

Vi kan också inkludera en priority egenskap och weight för varje objekt i services listan för att avgöra hur lastbalanseraren distribuerar belastningen. Så här kan du ange prioritet och vikt för varje serverdel:

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
    }
  ]

I föregående exempel distribuerar lastbalanseraren belastningen till backend-1 tre gånger mer än backend-2.

Direkt inkommande samtal

Slutligen måste vi dirigera alla inkommande anrop till den här belastningsutjämningsserverdelen. Riktningsinstruktionen skapas i följande API-entitet:

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'
    }
    
}

Konfigurera principen

Nu kan vi slutligen ange principen för tidigare beskrivna API:et och dirigera inkommande anrop till lastbalanseraren:

// 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
  }
}

Det vi gjorde var att skapa en princip som dirigerar inkommande anrop till lastbalanseraren. Principen set-backend-service används för att dirigera inkommande anrop till lastbalanseraren. Egenskapen backend-id är inställd på namnet på lastbalanseraren som vi skapade tidigare.

Med alla dessa rörliga delar på plats är DIN API Management-instans nu belastningsutjämning. Nu kan du skala ditt API genom att lägga till fler serverdelar i lastbalanseraren.

Kretsbrytaren

En kretsbrytare är något du använder när du vill skydda ditt API från att överbelastas av begäranden. Hur det fungerar är att du definierar en uppsättning regler som när den uppfylls utlöser och slutar skicka begäranden till serverdelen. I Azure API Management kan du definiera en kretsbrytare genom att konfigurera en serverdel och definiera en kretsbrytarregel. Så här kan du göra det:

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'
            }
          ]
        }
       }
     }

I föregående serverdelsdefinition finns det en egenskap failureCondition som definierar när kretsbrytaren ska köras. I det här fallet utlöses kretsbrytaren om det finns tre serverfel på en dag. Egenskapen tripDuration definierar hur länge kretsbrytaren ska vara öppen innan den stängs igen. Det är bra att definiera en kretsbrytare för varje serverdel som du har i DIN API Management-instans.

Hanterad identitet

Ett annat problem som vi vill ta itu med är säkerheten. Du vill se till att ditt API är säkert och att endast behöriga klienter kan komma åt det. Ett sätt att skydda ditt API är att använda hanterad identitet. Hanterad identitet är ett sätt att autentisera ditt API till andra Azure-tjänster. I Azure API Management måste du tillämpa hanterad identitet på flera platser:

  • PÅ APIM-instansnivå kan du aktivera hanterad identitet i APIM-instansen identity genom att ange egenskapen så SystemAssigned här:

    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'
        }
    }
    

    Den här åtgärden genererar en hanterad identitet för APIM-instansen som vi senare kan använda vår APIM-instans till, till exempel en Azure OpenAI-instans.

  • FÖR DIN API-instans kan du associera den med en princip. I den här principen kan du lägga till de instruktioner som behövs för att hanterad identitet ska fungera:

    <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>
    

    Se föregående anrop till authentication-managed-identity och set-header dessa instruktioner kontrollerar att den hanterade identiteten tillämpas på API:et.

  • Serverdelsnivå, slutligen, förutsatt att dina serverdelar pekar på Azure OpenAI-instanser. Vi måste ansluta vår APIM-instans till Azure OpenAI-instansen/-instanserna. Här är Bicep-instruktionen för att upprätta den här anslutningen:

    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)
      }
    }
    

    Tanken med ovanstående Bicep-instruktion är att skapa en rolltilldelning mellan APIM-instansen och Azure OpenAI-instansen. I det här fallet:

    • principalId är identitets-ID:t från APIM-instansen,
    • roleDefinitionId är den specifika användaren, i det här fallet är det en användare som heter "Cognitive Services User", en användare som har åtkomst till Azure OpenAI-instansen.
    • nameser den här egenskapen till att rolltilldelningen tillämpas på rätt omfång, vilket i det här fallet är en specifik prenumeration och resursgrupp. (måste vara samma resursgrupp som Azure OpenAI-instansen)

Kontrollera dina kunskaper

1.

Vad är en av de största utmaningarna som kan få dig att söka efter en API-hanteringslösning?

2.

Vad används IaC (Infrastructure as Code) för att hantera Azure-resurser?

3.

Vad är syftet med en kretsbrytare i API-hantering?