Share via


Azure API Management'ta özel önbelleğe alma

UYGULANANLAR: Tüm API Management katmanları

Azure API Management hizmeti, anahtar olarak kaynak URL'sini kullanarak HTTP yanıtı önbelleğe alma için yerleşik desteğe sahiptir. Anahtar, özellikler kullanılarak vary-by istek üst bilgileriyle değiştirilebilir. Bu, HTTP yanıtlarının tamamını önbelleğe almak için yararlıdır (gösterim olarak da bilinir), ancak bazen gösterimin yalnızca bir bölümünü önbelleğe almak yararlı olabilir. Cache-lookup-value ve cache-store-value ilkeleri, ilke tanımları içinde rastgele veri parçalarını depolama ve alma olanağı sağlar. Bu özellik, dış hizmetlerden gelen yanıtları önbelleğe alabildiğiniz için gönderme isteği ilkesine de değer ekler.

Mimari

API Management hizmeti, birden çok birimde ölçeği artırdıkça aynı önbelleğe alınmış verilere erişmeye devam edebilmeniz için kiracı başına paylaşılan bir iç veri önbelleği kullanır. Ancak, çok bölgeli bir dağıtımla çalışırken her bölgede bağımsız önbellekler vardır. Önbelleği bir veri deposu olarak ele almamak önemlidir; burada bazı bilgilerin tek kaynağıdır. Bunu yaptıysanız ve daha sonra çok bölgeli dağıtımdan yararlanmaya karar verdiyseniz, seyahat eden kullanıcıları olan müşteriler bu önbelleğe alınmış verilere erişimi kaybedebilir.

Not

İç önbellek, Azure API Management'ın Tüketim katmanında kullanılamaz. Bunun yerine dış Redis için Azure Cache kullanabilirsiniz. Dış önbellek, tüm katmanlardaki API Management örnekleri için daha fazla önbellek denetimi ve esneklik sağlar.

Parça önbelleğe alma

Döndürülen yanıtların, belirlenmesi pahalı olan ve makul bir süre boyunca yeni kalan verilerin bir kısmını içerdiği bazı durumlar vardır. Örnek olarak, uçuş rezervasyonları, uçuş durumu vb. ile ilgili bilgiler sağlayan bir havayolu şirketi tarafından oluşturulan bir hizmeti düşünün. Kullanıcı havayolları puan programına üyeyse, geçerli durumu ve birikmiş mesafe ile ilgili bilgilere de sahip olacaktır. Kullanıcıyla ilgili bu bilgiler farklı bir sistemde depolanabilir, ancak uçuş durumu ve rezervasyonlar hakkında döndürülen yanıtlara eklenmesi istenebilir. Bu işlem parça önbelleğe alma adı verilen bir işlem kullanılarak yapılabilir. Birincil gösterim, kullanıcıyla ilgili bilgilerin nereye eklendiğini belirtmek için bir tür belirteç kullanılarak kaynak sunucudan döndürülebilir.

Arka uç API'sinden aşağıdaki JSON yanıtını göz önünde bulundurun.

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

İkincil kaynak /userprofile/{userid} şuna benzer:

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

Eklenecek uygun kullanıcı bilgilerini belirlemek için API Management'ın son kullanıcının kim olduğunu belirlemesi gerekir. Bu mekanizma uygulamaya bağımlıdır. Aşağıdaki örnekte belirteç JWT talebi gerçekleştirilirSubject.

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

API Management değeri enduserid daha sonra kullanmak üzere bir bağlam değişkeninde depolar. Sonraki adım, önceki bir isteğin kullanıcı bilgilerini alıp önbellekte depolayıp depolamadığını belirlemektir. Bunun için API Management ilkeyi cache-lookup-value kullanır.

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

Önbellekte anahtar değerine karşılık gelen bir giriş yoksa bağlam userprofile değişkeni oluşturulmaz. API Management, denetim akışı ilkesini kullanarak aramanın başarısını choose denetler.

<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 Bağlam değişkeni yoksa API Management'ın bunu almak için bir HTTP isteğinde bulunması gerekir.

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

API Management, kullanıcı profili kaynağının URL'sini oluşturmak için öğesini kullanır enduserid . API Management yanıtı aldıktan sonra gövde metnini yanıttan çıkarır ve bir bağlam değişkenine geri depolar.

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

API Management'ın bu HTTP isteğini yeniden yapmasını önlemek için, aynı kullanıcı başka bir istek yaptığında, kullanıcı profilini önbellekte depolamayı belirtebilirsiniz.

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

API Management, api Management'ın başlangıçta almak için denemiş olduğu anahtarı kullanarak değeri önbellekte depolar. API Management'ın değeri depolamak için seçtiği süre, bilgilerin ne sıklıkta değiştiğine ve kullanıcıların güncel olmayan bilgilere ne kadar dayanıklı olduğuna bağlı olmalıdır.

Önbellekten alma işleminin hala işlem dışı bir ağ isteği olduğunu ve isteğe onlarca milisaniye ekleyebileceğini fark etmek önemlidir. Bunun avantajları, veritabanı sorguları yapmak veya birden çok arka uçtan bilgi toplamak gerektiğinden, kullanıcı profili bilgilerinin belirlenmesi bundan daha uzun sürerken ortaya çıkar.

İşlemin son adımı, döndürülen yanıtı kullanıcı profili bilgileriyle güncelleştirmektir.

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

Değiştirme gerçekleşmediğinde bile yanıtın geçerli bir JSON olması için tırnak işaretlerini belirtecin parçası olarak eklemeyi seçebilirsiniz.

Bu adımları birleştirdikten sonra sonuç, aşağıdakine benzer bir ilke olur.

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

Bu önbelleğe alma yaklaşımı öncelikle HTML'nin sunucu tarafında oluşturularak tek bir sayfa olarak işlenebilmesi için web sitelerinde kullanılır. İstemcilerin istemci tarafı HTTP önbelleğe alma işlemini gerçekleştiremediği veya bu sorumluluğu istemciye yüklememek istendiği API'lerde de yararlı olabilir.

Bu tür parça önbelleğe alma işlemi, redis önbelleğe alma sunucusu kullanılarak arka uç web sunucularında da yapılabilir, ancak önbelleğe alınan parçalar birincil yanıtlardan farklı arka uçlardan geldiğinde bu işi gerçekleştirmek için API Management hizmetini kullanmak yararlı olur.

Saydam sürüm oluşturma

Bir API'nin birden çok farklı uygulama sürümünün herhangi bir anda desteklenmesi yaygın bir uygulamadır. Örneğin, farklı ortamları (geliştirme, test, üretim vb.) desteklemek veya API tüketicilerinin daha yeni sürümlere geçişine zaman tanımak için API'nin eski sürümlerini desteklemek.

Bunu işlemeye yönelik yaklaşımlardan biri, istemci geliştiricilerin URL'leri /v1/customers/v2/customers olarak değiştirmesini gerektirmek yerine, tüketicinin profil verilerinde api'nin şu anda hangi sürümünü kullanmak istediklerini depolamak ve uygun arka uç URL'sini çağırmaktır. Belirli bir istemci için çağrılacak doğru arka uç URL'sini belirlemek için bazı yapılandırma verilerini sorgulamak gerekir. API Management, bu yapılandırma verilerini önbelleğe alarak bu aramayı yapmanın performans cezasını en aza indirir.

İlk adım, istenen sürümü yapılandırmak için kullanılan tanımlayıcıyı belirlemektir. Bu örnekte sürümü ürün abonelik anahtarıyla ilişkilendirmeyi seçtim.

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

ARDıNDAN API Management, istenen istemci sürümünü alıp almadığını görmek için bir önbellek araması yapar.

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

Ardından API Management, önbellekte bulup bulmadığını denetler.

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

API Management bulamıyorsa API Management bunu alır.

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

Yanıt gövdesi metnini yanıttan ayıklayın.

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

Gelecekte kullanmak üzere önbellekte depolayın.

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

Son olarak, istemci tarafından istenen hizmet sürümünü seçmek için arka uç URL'sini güncelleştirin.

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

İlkenin tamamı aşağıdaki gibidir:

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

API tüketicilerinin istemcileri güncelleştirmek ve yeniden dağıtmak zorunda kalmadan istemciler tarafından hangi arka uç sürümüne erişildiğini şeffaf bir şekilde denetlemesini sağlamak, birçok API sürümü oluşturma endişesini ele alan zarif bir çözümdür.

Kiracı Yalıtımı

Daha büyük, çok kiracılı dağıtımlarda bazı şirketler arka uç donanımının ayrı dağıtımlarında ayrı kiracı grupları oluşturur. Bu, arka uçta bir donanım sorunundan etkilenen müşteri sayısını en aza indirir. Ayrıca, yeni yazılım sürümlerinin aşamalı olarak dağıtılabilmesini sağlar. İdeal olan bu arka uç mimarisinin API tüketicileri için şeffaf olmasıdır. Bu, API anahtarı başına yapılandırma durumunu kullanarak arka uç URL'sini işleme tekniğini temel alarak saydam sürüm oluşturmayla benzer bir şekilde elde edilebilir.

Her abonelik anahtarı için API'nin tercih edilen bir sürümünü döndürmek yerine, kiracıyı atanan donanım grubuyla ilişkilendiren bir tanımlayıcı döndürebilirsiniz. Bu tanımlayıcı uygun arka uç URL'sini oluşturmak için kullanılabilir.

Özet

Her tür veriyi depolamak için Azure API yönetim önbelleğini kullanma özgürlüğü, gelen isteğin işlenme şeklini etkileyebilecek yapılandırma verilerine verimli erişim sağlar. Ayrıca, arka uç API'sinden döndürülen yanıtları artırabilen veri parçalarını depolamak için de kullanılabilir.