Sdílet prostřednictvím


Vlastní ukládání do mezipaměti ve službě Azure API Management

PLATÍ PRO: Všechny úrovně služby API Management

Služba Azure API Management má integrovanou podporu ukládání odpovědí HTTP do mezipaměti pomocí adresy URL prostředku jako klíče. Klíč lze upravit hlavičkami požadavku pomocí vary-by vlastností. To je užitečné pro ukládání celých odpovědí HTTP (označovaných také jako reprezentace), ale někdy je užitečné jen ukládat část reprezentace do mezipaměti. Zásady pro vyhledávání a ukládání do mezipaměti poskytují možnost ukládat a načítat libovolné části dat z definic zásad. Tato schopnost také přidává hodnotu do zásad odesílání požadavků , protože odpovědi z externích služeb můžete ukládat do mezipaměti.

Architektura

Služba API Management používá sdílenou interní mezipaměť dat pro jednotlivé tenanty, abyste při vertikálním navýšení kapacity na více jednotek stále získali přístup ke stejným datům uloženým v mezipaměti. Při práci s nasazením ve více oblastech jsou však v každé oblasti nezávislé mezipaměti. Je důležité, abyste mezipaměť nezacházeli jako s úložištěm dat, kde je jediným zdrojem některých informací. Pokud jste to udělali a později se rozhodli využít nasazení ve více oblastech, zákazníci s uživateli, kteří cestují, mohou ztratit přístup k datům uloženým v mezipaměti.

Poznámka:

Interní mezipaměť není k dispozici ve vrstvě Consumption služby Azure API Management. Místo toho můžete použít externí službu Azure Cache for Redis . Externí mezipaměť umožňuje větší řízení mezipaměti a flexibilitu pro instance služby API Management ve všech úrovních.

Ukládání fragmentů do mezipaměti

Existují určité případy, kdy vrácené odpovědi obsahují část dat, která je nákladná k určení a přesto zůstává po určitou dobu čerstvá. Představte si například službu vytvořenou leteckým společností, která poskytuje informace týkající se rezervací letů, stavu letu atd. Pokud je uživatel členem programu leteckých společností, měl by také informace týkající se aktuálního stavu a kumulované kilometry. Tyto informace související s uživatelem můžou být uložené v jiném systému, ale může být žádoucí je zahrnout do odpovědí vrácených o stavu letu a rezervacích. Můžete to provést pomocí procesu označovaného jako ukládání fragmentů do mezipaměti. Primární reprezentaci lze vrátit ze zdrojového serveru pomocí určitého typu tokenu, který označuje, kam se mají vložit informace související s uživatelem.

Podívejte se na následující odpověď JSON z back-endového rozhraní API.

{
  "airline" : "Air Canada",
  "flightno" : "871",
  "status" : "ontime",
  "gate" : "B40",
  "terminal" : "2A",
  "userprofile" : "$userprofile$"
}  

A sekundární prostředek v /userprofile/{userid} tom vypadá takto:

{ "username" : "Bob Smith", "Status" : "Gold" }

Aby bylo možné určit vhodné informace o uživateli, které se mají zahrnout, musí služba API Management určit, kdo je koncovým uživatelem. Tento mechanismus je závislý na implementaci. Následující příklad používá Subject deklaraci identity tokenu JWT .

<set-variable
  name="enduserid"
  value="@(context.Request.Headers.GetValueOrDefault("Authorization","").Split(' ')[1].AsJwt()?.Subject)" />

Api Management ukládá enduserid hodnotu do kontextové proměnné pro pozdější použití. Dalším krokem je určení, jestli předchozí požadavek již načetl informace o uživateli a uložil je do mezipaměti. K tomu služba API Management používá zásadu cache-lookup-value .

<cache-lookup-value
key="@("userprofile-" + context.Variables["enduserid"])"
variable-name="userprofile" />

Pokud v mezipaměti neexistuje žádná položka odpovídající hodnotě klíče, není vytvořena žádná userprofile kontextová proměnná. API Management kontroluje úspěch vyhledávání pomocí choose zásad toku řízení.

<choose>
    <when condition="@(!context.Variables.ContainsKey("userprofile"))">
        <!-- If the userprofile context variable doesn’t exist, make an HTTP request to retrieve it.  -->
    </when>
</choose>

userprofile Pokud kontextová proměnná neexistuje, bude muset služba API Management vytvořit požadavek HTTP, aby ji načetl.

<send-request
  mode="new"
  response-variable-name="userprofileresponse"
  timeout="10"
  ignore-error="true">

  <!-- Build a URL that points to the profile for the current end-user -->
  <set-url>@(new Uri(new Uri("https://apimairlineapi.azurewebsites.net/UserProfile/"),
      (string)context.Variables["enduserid"]).AbsoluteUri)
  </set-url>
  <set-method>GET</set-method>
</send-request>

Služba API Management používá enduserid k vytvoření adresy URL prostředku profilu uživatele. Jakmile má služba API Management odpověď, přetáhne z odpovědi základní text a uloží ji zpět do kontextové proměnné.

<set-variable
    name="userprofile"
    value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />

Pokud se chcete službě API Management vyhnout opětovnému vytvoření tohoto požadavku HTTP, můžete určit, jestli se má profil uživatele uložit do mezipaměti.

<cache-store-value
    key="@("userprofile-" + context.Variables["enduserid"])"
    value="@((string)context.Variables["userprofile"])" duration="100000" />

Služba API Management ukládá hodnotu v mezipaměti pomocí stejného klíče, kterým se služba API Management původně pokusila ji načíst. Doba trvání, kterou služba API Management zvolí k uložení hodnoty, by měla být založena na tom, jak často se informace mění a jak jsou tolerantní uživatelé k zastaralým informacím.

Je důležité si uvědomit, že načítání z mezipaměti je stále požadavek na síť mimo proces a potenciálně může do požadavku přidat desítky milisekund. Výhody při určování informací o profilu uživatele trvá déle, než je potřeba provádět databázové dotazy nebo agregovat informace z více back-endů.

Posledním krokem v procesu je aktualizace vrácené odpovědi informacemi o profilu uživatele.

<!-- Update response body with user profile-->
<find-and-replace
    from='"$userprofile$"'
    to="@((string)context.Variables["userprofile"])" />

Jako součást tokenu můžete zahrnout uvozovky, aby i v případě, že k nahrazení nedojde, odpověď je stále platným kódem JSON.

Po zkombinování těchto kroků je konečným výsledkem zásada, která vypadá jako následující.

<policies>
    <inbound>
        <!-- How you determine user identity is application dependent -->
        <set-variable
          name="enduserid"
          value="@(context.Request.Headers.GetValueOrDefault("Authorization","").Split(' ')[1].AsJwt()?.Subject)" />

        <!--Look for userprofile for this user in the cache -->
        <cache-lookup-value
          key="@("userprofile-" + context.Variables["enduserid"])"
          variable-name="userprofile" />

        <!-- If API Management doesn’t find it in the cache, make a request for it and store it -->
        <choose>
            <when condition="@(!context.Variables.ContainsKey("userprofile"))">
                <!-- Make HTTP request to get user profile -->
                <send-request
                  mode="new"
                  response-variable-name="userprofileresponse"
                  timeout="10"
                  ignore-error="true">

                   <!-- Build a URL that points to the profile for the current end-user -->
                    <set-url>@(new Uri(new Uri("https://apimairlineapi.azurewebsites.net/UserProfile/"),(string)context.Variables["enduserid"]).AbsoluteUri)</set-url>
                    <set-method>GET</set-method>
                </send-request>

                <!-- Store response body in context variable -->
                <set-variable
                  name="userprofile"
                  value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />

                <!-- Store result in cache -->
                <cache-store-value
                  key="@("userprofile-" + context.Variables["enduserid"])"
                  value="@((string)context.Variables["userprofile"])"
                  duration="100000" />
            </when>
        </choose>
        <base />
    </inbound>
    <outbound>
        <!-- Update response body with user profile-->
        <find-and-replace
              from='"$userprofile$"'
              to="@((string)context.Variables["userprofile"])" />
        <base />
    </outbound>
</policies>

Tento přístup k ukládání do mezipaměti se primárně používá na webech, kde se HTML skládá na straně serveru, aby se mohl vykreslit jako jedna stránka. Může být také užitečné v rozhraních API, kde klienti nemůžou provádět ukládání do mezipaměti HTTP na straně klienta nebo je žádoucí, aby tuto odpovědnost nezasáli na klienta.

Stejný druh ukládání fragmentů do mezipaměti lze provést také na back-endových webových serverech pomocí serveru mezipaměti Redis, ale použití služby API Management k provedení této práce je užitečné, když fragmenty uložené v mezipaměti pocházejí z různých back-endů než primární odpovědi.

Transparentní správa verzí

Je běžné, že se podporuje více různých verzí implementace rozhraní API najednou. Pokud například chcete podporovat různá prostředí (vývoj, testování, produkční atd.) nebo podporovat starší verze rozhraní API, aby měli uživatelé rozhraní API čas na migraci na novější verze.

Jedním z přístupů k tomu je místo toho, aby vývojáři klientů museli změnit adresy URL /v1/customers na /v2/customers , ukládat do dat profilu uživatele, kterou verzi rozhraní API aktuálně chtějí použít, a volat odpovídající back-endovou adresu URL. Pokud chcete určit správnou adresu URL back-endu pro volání konkrétního klienta, je nutné zadat dotaz na některá konfigurační data. Ukládáním těchto konfiguračních dat do mezipaměti může služba API Management minimalizovat snížení výkonu tohoto vyhledávání.

Prvním krokem je určení identifikátoru použitého ke konfiguraci požadované verze. V tomto příkladu jsem se rozhodl přidružit verzi k kódu Product Subscription Key.

<set-variable name="clientid" value="@(context.Subscription.Key)" />

Služba API Management pak vyhledá mezipaměť a zjistí, jestli už načetla požadovanou verzi klienta.

<cache-lookup-value
key="@("clientversion-" + context.Variables["clientid"])"
variable-name="clientversion" />

Pak služba API Management zkontroluje, jestli ho v mezipaměti nenašla.

<choose>
    <when condition="@(!context.Variables.ContainsKey("clientversion"))">

Pokud ho služba API Management nenašla, služba API Management ji načte.

<send-request
    mode="new"
    response-variable-name="clientconfiguresponse"
    timeout="10"
    ignore-error="true">
            <set-url>@(new Uri(new Uri(context.Api.ServiceUrl.ToString() + "api/ClientConfig/"),(string)context.Variables["clientid"]).AbsoluteUri)</set-url>
            <set-method>GET</set-method>
</send-request>

Extrahujte základní text odpovědi z odpovědi.

<set-variable
      name="clientversion"
      value="@(((IResponse)context.Variables["clientconfiguresponse"]).Body.As<string>())" />

Uložte ho zpátky do mezipaměti pro budoucí použití.

<cache-store-value
      key="@("clientversion-" + context.Variables["clientid"])"
      value="@((string)context.Variables["clientversion"])"
      duration="100000" />

Nakonec aktualizujte back-endovou adresu URL tak, aby vybrali verzi služby, kterou klient chce.

<set-backend-service
      base-url="@(context.Api.ServiceUrl.ToString() + "api/" + (string)context.Variables["clientversion"] + "/")" />

Úplná zásada je následující:

<inbound>
    <base />
    <set-variable name="clientid" value="@(context.Subscription.Key)" />
    <cache-lookup-value key="@("clientversion-" + context.Variables["clientid"])" variable-name="clientversion" />

    <!-- If API Management doesn’t find it in the cache, make a request for it and store it -->
    <choose>
        <when condition="@(!context.Variables.ContainsKey("clientversion"))">
            <send-request mode="new" response-variable-name="clientconfiguresponse" timeout="10" ignore-error="true">
                <set-url>@(new Uri(new Uri(context.Api.ServiceUrl.ToString() + "api/ClientConfig/"),(string)context.Variables["clientid"]).AbsoluteUri)</set-url>
                <set-method>GET</set-method>
            </send-request>
            <!-- Store response body in context variable -->
            <set-variable name="clientversion" value="@(((IResponse)context.Variables["clientconfiguresponse"]).Body.As<string>())" />
            <!-- Store result in cache -->
            <cache-store-value key="@("clientversion-" + context.Variables["clientid"])" value="@((string)context.Variables["clientversion"])" duration="100000" />
        </when>
    </choose>
    <set-backend-service base-url="@(context.Api.ServiceUrl.ToString() + "api/" + (string)context.Variables["clientversion"] + "/")" />
</inbound>

Umožňuje uživatelům rozhraní API transparentně řídit, ke které back-endové verzi přistupuje klienti, aniž by museli aktualizovat a znovu nasadit klienty, je elegantní řešení, které řeší řadu problémů se správou verzí rozhraní API.

Izolace tenanta

Ve větších nasazeních s více tenanty některé společnosti vytvářejí samostatné skupiny tenantů na různých nasazeních back-endového hardwaru. Tím se minimalizuje počet zákazníků, kteří mají vliv na problém s hardwarem na back-endu. Umožňuje také, aby se nové verze softwaru zaváděly ve fázích. V ideálním případě by tato back-endová architektura měla být pro uživatele rozhraní API transparentní. Toho lze dosáhnout podobným způsobem jako transparentní správa verzí, protože je založená na stejné technice manipulace s back-endovou adresou URL pomocí stavu konfigurace na klíč rozhraní API.

Místo vrácení upřednostňované verze rozhraní API pro každý klíč předplatného byste vrátili identifikátor, který souvisí s přiřazenou hardwarovou skupinou. Tento identifikátor lze použít k vytvoření příslušné back-endové adresy URL.

Shrnutí

Svoboda používat mezipaměť Azure API Management k ukládání jakéhokoli druhu dat umožňuje efektivní přístup ke konfiguračním datům, které můžou ovlivnit způsob zpracování příchozího požadavku. Dá se také použít k ukládání fragmentů dat, které můžou rozšířit odpovědi vrácené z back-endového rozhraní API.