Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
SE APLICA A: todos los niveles de API Management
El servicio Azure API Management tiene compatibilidad integrada con el almacenamiento en caché de respuesta HTTP mediante la dirección URL del recurso como clave. Puede modificar la clave mediante encabezados de solicitud que usan las vary-by propiedades . Esta técnica es útil para almacenar en caché respuestas HTTP completas (también conocidas como representaciones), pero a veces resulta útil almacenar en caché una parte de una representación. Las directivas cache-lookup-value y cache-store-value le permiten almacenar y recuperar fragmentos arbitrarios de datos desde definiciones de directiva. Esta capacidad también agrega valor a la directiva de solicitud de envío porque puede almacenar en caché las respuestas de servicios externos.
Architecture
El servicio API Management usa una caché de datos interna compartida por inquilino para que, a medida que escale verticalmente a varias unidades, siga teniendo acceso a los mismos datos almacenados en caché. Sin embargo, cuando se trabaja con una implementación de varias regiones son memorias caché independientes dentro de cada una de las regiones. Es importante no tratar la memoria caché como un almacén de datos, donde es el único origen de información. Si lo hizo y más adelante decidió aprovechar la implementación de varias regiones, los clientes con usuarios que viajan podrían perder el acceso a esos datos almacenados en caché.
Nota:
La caché interna no está disponible en el nivel Consumo de Azure API Management. En su lugar, puede usar una caché externa compatible con Redis . Una caché externa permite un mayor control y flexibilidad de caché para las instancias de API Management en todos los niveles.
Almacenamiento en caché de fragmentos
Hay algunos casos en los que las respuestas que se devuelven contienen alguna parte de los datos que son costosos de determinar. Sin embargo, los datos permanecen actualizados durante un período de tiempo razonable. Por ejemplo, considere un servicio creado por una aerolínea que proporciona información relacionada con las reservas de vuelos, el estado del vuelo, etc. Si el usuario es miembro del programa de puntos de líneas aéreas, también tendría información relacionada con su estado actual y kilometraje acumulado. Esta información relacionada con el usuario puede almacenarse en un sistema diferente, pero podría ser conveniente incluirla en las respuestas devueltas sobre el estado de vuelo y las reservas. Puede incluir estos datos mediante un proceso denominado almacenamiento en caché de fragmentos. La representación principal se puede devolver desde el servidor de origen mediante algún tipo de token para indicar dónde se va a insertar la información relacionada con el usuario.
Tenga en cuenta la siguiente respuesta JSON de una API de back-end.
{
"airline" : "Air Canada",
"flightno" : "871",
"status" : "ontime",
"gate" : "B40",
"terminal" : "2A",
"userprofile" : "$userprofile$"
}
Y el recurso secundario en /userprofile/{userid} que es como sigue,
{ "username" : "Bob Smith", "Status" : "Gold" }
Para determinar la información de usuario adecuada que se va a incluir, API Management debe identificar quién es el usuario final. Este mecanismo depende de la implementación. En el ejemplo siguiente se usa la notificación Subject de un token JWT.
<set-variable
name="enduserid"
value="@(context.Request.Headers.GetValueOrDefault("Authorization","").Split(' ')[1].AsJwt()?.Subject)" />
API Management almacena el enduserid valor en una variable de contexto para su uso posterior. El siguiente paso consiste en determinar si una solicitud anterior ya recuperó la información del usuario y la almacenó en la memoria caché. Para ello, API Management usa la cache-lookup-value política.
<cache-lookup-value
key="@("userprofile-" + context.Variables["enduserid"])"
variable-name="userprofile" />
<rate-limit calls="10" renewal-period="60" />
Nota:
Añade una política de límite de velocidad (o política de límite por clave ) tras la búsqueda de caché para ayudar a limitar el número de llamadas y evitar sobrecarga en el servicio de backend en caso de que la caché no esté disponible.
Si no hay ninguna entrada en la memoria caché que corresponda al valor de clave, no se crea ninguna userprofile variable de contexto. API Management comprueba el éxito de la búsqueda mediante la choose directiva de flujo de control.
<choose>
<when condition="@(!context.Variables.ContainsKey("userprofile"))">
<!-- If the userprofile context variable doesn’t exist, make an HTTP request to retrieve it. -->
</when>
</choose>
Si la userprofile variable de contexto no existe, API Management tendrá que realizar una solicitud HTTP para recuperarla.
<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 usa enduserid para construir la dirección URL al recurso de perfil de usuario. Una vez que API Management tiene la respuesta, extrae el texto del cuerpo de la respuesta y lo almacena en una variable de contexto.
<set-variable
name="userprofile"
value="@(((IResponse)context.Variables["userprofileresponse"]).Body.As<string>())" />
Para evitar que API Management vuelva a realizar esta solicitud HTTP cuando el mismo usuario realice otra solicitud, puede especificar que el perfil de usuario se almacena en la memoria caché.
<cache-store-value
key="@("userprofile-" + context.Variables["enduserid"])"
value="@((string)context.Variables["userprofile"])" duration="100000" />
API Management almacena el valor en la memoria caché con la misma clave con la que API Management intentó recuperarlo originalmente. La duración que API Management elige almacenar el valor debe basarse en la frecuencia con la que cambia la información y la tolerancia de los usuarios a la información obsoleta.
Es importante tener en cuenta que la recuperación de información de la memoria caché sigue siendo una solicitud de red fuera de proceso y puede agregar decenas de milisegundos a la solicitud. Las ventajas se presentan cuando determinar la información del perfil de usuario toma más tiempo que recuperar información de la memoria caché, debido a la necesidad de realizar consultas en la base de datos o de agregar información de varios sistemas de fondo.
El último paso del proceso es actualizar la respuesta devuelta con la información del perfil de usuario.
<!-- Update response body with user profile-->
<find-and-replace
from='"$userprofile$"'
to="@((string)context.Variables["userprofile"])" />
Puede elegir incluir las comillas como parte del token para que incluso cuando no se produzca el reemplazo, la respuesta sigue siendo JSON válida.
Una vez que combine estos pasos, el resultado final es una directiva similar a la siguiente.
<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" />
<rate-limit calls="10" renewal-period="60" />
<!-- 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>
Este enfoque de almacenamiento en caché se usa principalmente en sitios web donde HTML se compone en el lado servidor para que se pueda representar como una sola página. También puede ser útil en las API en las que los clientes no pueden realizar el almacenamiento en caché HTTP del lado cliente o es conveniente no poner esa responsabilidad en el cliente.
Este mismo tipo de almacenamiento en caché de fragmentos también se puede realizar en los servidores web back-end mediante un servidor de almacenamiento en caché de Redis. Sin embargo, el uso del servicio API Management para realizar este trabajo es útil cuando los fragmentos almacenados en caché proceden de distintos back-ends que las respuestas principales.
Control de versiones transparente
Es habitual admitir varias versiones de implementación diferentes de una API en cualquier momento. Por ejemplo, para admitir entornos diferentes (desarrollo, prueba, producción, etc.) o para admitir versiones anteriores de la API para dar tiempo a que los consumidores de API migren a versiones más recientes.
Un enfoque para controlar varias versiones, en lugar de requerir que los desarrolladores cliente cambien las direcciones URL de /v1/customers a /v2/customers, es almacenar en los datos de perfil del consumidor qué versión de la API que desean usar y llamar a la dirección URL de back-end adecuada. Para determinar la dirección URL de back-end correcta para llamar a un cliente determinado, es necesario consultar algunos datos de configuración. Al almacenar en caché estos datos de configuración, API Management puede minimizar la penalización de rendimiento de realizar esta búsqueda.
El primer paso es determinar el identificador usado para configurar la versión deseada. En este ejemplo, asociamos la versión a la clave de suscripción del producto.
<set-variable name="clientid" value="@(context.Subscription.Key)" />
Después, API Management realiza una búsqueda de caché para ver si ya recuperó la versión de cliente deseada.
<cache-lookup-value
key="@("clientversion-" + context.Variables["clientid"])"
variable-name="clientversion" />
<rate-limit calls="10" renewal-period="60" />
Nota:
Añade una política de límite de velocidad (o política de límite por clave ) tras la búsqueda de caché para ayudar a limitar el número de llamadas y evitar sobrecarga en el servicio de backend en caso de que la caché no esté disponible.
A continuación, API Management comprueba si no lo encontró en la memoria caché.
<choose>
<when condition="@(!context.Variables.ContainsKey("clientversion"))">
Si API Management no lo encontró, API Management lo recupera.
<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>
Extraemos el texto del cuerpo de respuesta de la respuesta.
<set-variable
name="clientversion"
value="@(((IResponse)context.Variables["clientconfiguresponse"]).Body.As<string>())" />
Almacénelo de nuevo en la memoria caché para su uso futuro.
<cache-store-value
key="@("clientversion-" + context.Variables["clientid"])"
value="@((string)context.Variables["clientversion"])"
duration="100000" />
Y, por último, actualice la dirección URL del back-end para seleccionar la versión del servicio que desee el cliente.
<set-backend-service
base-url="@(context.Api.ServiceUrl.ToString() + "api/" + (string)context.Variables["clientversion"] + "/")" />
La directiva completa es la siguiente:
<inbound>
<base />
<set-variable name="clientid" value="@(context.Subscription.Key)" />
<cache-lookup-value key="@("clientversion-" + context.Variables["clientid"])" variable-name="clientversion" />
<rate-limit calls="10" renewal-period="60" />
<!-- 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>
Esta solución elegante aborda muchos problemas de control de versiones de API, ya que permite a los consumidores de API controlar de forma transparente qué versión de back-end acceden sus clientes sin tener que actualizar y volver a implementar sus clientes.
Aislamiento de inquilino
En implementaciones más grandes y multiinquilino, algunas empresas crean grupos independientes de inquilinos en distintas implementaciones de hardware back-end. Esta estructura minimiza el número de clientes afectados cuando hay problemas de hardware en el back-end. También permite implementar nuevas versiones de software en fases. Lo ideal es que esta arquitectura de back-end sea transparente para los consumidores de API. Puede lograr esta transparencia mediante una técnica similar al versionamiento transparente, manipulando la URL del backend utilizando el estado de configuración por clave de API.
En lugar de devolver una versión preferida de la API para cada clave de suscripción, devolvería un identificador que relaciona un inquilino con el grupo de hardware asignado. Ese identificador se puede usar para construir la dirección URL de back-end adecuada.
Resumen
La libertad de usar la caché de Azure API Management para almacenar cualquier tipo de datos permite un acceso eficaz a los datos de configuración que pueden afectar a la forma en que se procesa una solicitud entrante. También se puede usar para almacenar fragmentos de datos que pueden aumentar las respuestas, devueltas desde una API de back-end.