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.
Las infraestructuras basadas en la nube, como Azure Storage, proporcionan una plataforma de alta disponibilidad y duradera para hospedar datos y aplicaciones. Los desarrolladores de aplicaciones basadas en la nube deben considerar cuidadosamente cómo aprovechar esta plataforma para maximizar esas ventajas para sus usuarios. Azure Storage ofrece opciones de redundancia geográfica para garantizar una alta disponibilidad incluso durante una interrupción regional. Las cuentas de almacenamiento configuradas para la replicación con redundancia geográfica se replican de forma sincrónica en la región primaria y se replican de forma asincrónica en una región secundaria que se encuentra a cientos de kilómetros de distancia.
Azure Storage ofrece dos opciones para la replicación con redundancia geográfica: almacenamiento con redundancia geográfica (GRS) y almacenamiento con redundancia de zona geográfica (GZRS). Para usar las opciones de redundancia geográfica de Azure Storage, asegúrese de que la cuenta de almacenamiento está configurada para el almacenamiento con redundancia geográfica con acceso de lectura (RA-GRS) o almacenamiento con redundancia de zona geográfica con acceso de lectura (RA-GZRS). Si no es así, puede obtener más información sobre cómo cambiar el tipo de replicación de la cuenta de almacenamiento.
En este artículo se muestra cómo diseñar una aplicación que seguirá funcionando, aunque en una capacidad limitada, incluso cuando haya una interrupción significativa en la región primaria. Si la región primaria deja de estar disponible, la aplicación puede cambiar sin problemas para realizar operaciones de lectura en la región secundaria hasta que la región primaria vuelva a responder.
Consideraciones sobre el diseño de aplicaciones
Puede diseñar la aplicación para controlar errores transitorios o interrupciones significativas leyendo desde la región secundaria cuando hay un problema que interfiere con la lectura de la región primaria. Cuando la región primaria vuelva a estar disponible, la aplicación puede volver a leer desde la región primaria.
Tenga en cuenta estas consideraciones clave al diseñar la aplicación para la disponibilidad y la resistencia mediante RA-GRS o RA-GZRS:
Una copia de solo lectura de los datos que almacena en la región primaria se replica de forma asincrónica en una región secundaria. Esta replicación asincrónica significa que la copia de solo lectura en la región secundaria es finalmente coherente con los datos de la región primaria. El servicio de almacenamiento determina la ubicación de la región secundaria.
Puede usar las bibliotecas cliente de Azure Storage para realizar solicitudes de lectura y actualización en el punto de conexión de la región primaria. Si la región primaria no está disponible, puede redirigir automáticamente las solicitudes de lectura a la región secundaria. También puede configurar la aplicación para enviar solicitudes de lectura directamente a la región secundaria, si lo desea, incluso cuando la región primaria esté disponible.
Si la región primaria deja de estar disponible, puede iniciar una conmutación por error de la cuenta. Al conmutar por error a la región secundaria, las entradas DNS que apuntan a la región primaria se cambian para que apunten a la región secundaria. Una vez completada la conmutación por error, se restaura el acceso de escritura para las cuentas GRS y RA-GRS. Para obtener más información, consulte Recuperación ante desastres y conmutación por error de la cuenta de almacenamiento.
Trabajar con datos coherentes con el tiempo
La solución propuesta supone que es aceptable devolver datos potencialmente obsoletos a la aplicación que llama. Dado que los datos de la región secundaria son coherentes con el tiempo, es posible que la región primaria no sea accesible antes de que una actualización de la región secundaria haya terminado de replicarse.
Por ejemplo, supongamos que el cliente envía correctamente una actualización, pero se produce un error en la región primaria antes de que la actualización se propague a la región secundaria. Cuando el cliente pide que lea los datos de nuevo, reciben los datos obsoletos de la región secundaria en lugar de los datos actualizados. Al diseñar la aplicación, debe decidir si este comportamiento es aceptable o no. Si es así, también debe tener en cuenta cómo notificar al usuario.
Más adelante en este artículo, obtendrá más información sobre el control de datos coherentes con el tiempo y cómo comprobar la propiedad Hora de la última sincronización para evaluar las discrepancias entre los datos de las regiones primarias y secundarias.
Gestión de servicios por separado o todos juntos
Aunque es poco probable, es posible que un servicio (blobs, colas, tablas o archivos) deje de estar disponible mientras que los demás servicios siguen siendo totalmente funcionales. Puede controlar los reintentos para cada servicio por separado o puede controlar los reintentos de forma genérica para todos los servicios de almacenamiento en conjunto.
Por ejemplo, si usa colas y blobs en la aplicación, puede decidir colocar código independiente para controlar los errores reintentos de cada servicio. De este modo, un error de Blob service solo afectará a la parte de la aplicación que se ocupa de los blobs, lo que deja que las colas sigan ejecutándose de la forma normal. Sin embargo, si decide controlar todos los reintentos del servicio de almacenamiento juntos, las solicitudes a los servicios de blob y cola se verán afectadas si alguno de los servicios devuelve un error que se puede reintentar.
En última instancia, esta decisión depende de la complejidad de la aplicación. Es posible que prefiera controlar los errores por servicio para limitar el impacto de los reintentos. O bien, puede decidir redirigir las solicitudes de lectura de todos los servicios de almacenamiento a la región secundaria cuando detecte un problema con cualquier servicio de almacenamiento en la región primaria.
Ejecución de la aplicación en modo de solo lectura
Para prepararse eficazmente para una interrupción en la región primaria, la aplicación debe poder controlar las solicitudes de lectura con error y las solicitudes de actualización con errores. Si se produce un error en la región primaria, las solicitudes de lectura se pueden redirigir a la región secundaria. Sin embargo, no se pueden redirigir las solicitudes de actualización porque los datos replicados en la región secundaria son de solo lectura. Por este motivo, debe diseñar la aplicación para poder ejecutarse en modo de solo lectura.
Por ejemplo, puede establecer una marca que se compruebe antes de que las solicitudes de actualización se envíen a Azure Storage. Cuando se realiza una solicitud de actualización, puede omitir la solicitud y devolver una respuesta adecuada al usuario. Incluso puede optar por deshabilitar ciertas características por completo hasta que se resuelva el problema y notificar a los usuarios que las características no están disponibles temporalmente.
Si decide controlar los errores de cada servicio por separado, también tendrá que controlar la capacidad de ejecutar la aplicación en modo de solo lectura por servicio. Por ejemplo, puede configurar marcas de solo lectura para cada servicio. A continuación, puede habilitar o deshabilitar las marcas en el código, según sea necesario.
La posibilidad de ejecutar la aplicación en modo de solo lectura también le ofrece la posibilidad de garantizar una funcionalidad limitada durante una actualización de la aplicación principal. Puede desencadenar la aplicación para que se ejecute en modo de solo lectura y apuntar al centro de datos secundario, lo que garantiza que nadie acceda a los datos de la región primaria mientras realiza actualizaciones.
Control de actualizaciones al ejecutarse en modo de solo lectura
Hay muchas maneras de controlar las solicitudes de actualización al ejecutarse en modo de solo lectura. Esta sección se centra en algunos patrones generales que se deben tener en cuenta.
Puede responder al usuario y notificarles que las solicitudes de actualización no se están procesando actualmente. Por ejemplo, un sistema de administración de contactos podría permitir a los usuarios acceder a la información de contacto, pero no realizar actualizaciones.
Puede poner en cola las actualizaciones en otra región. En este caso, escribiría las solicitudes de actualización pendientes en una cola de otra región y, a continuación, procesaría esas solicitudes después de que el centro de datos principal vuelva a estar en línea. En este escenario, debe informar al usuario de que la solicitud de actualización está en cola para su posterior procesamiento.
Puede escribir las actualizaciones en una cuenta de almacenamiento en otra región. Cuando la región primaria vuelve a estar en línea, puede combinar esas actualizaciones en los datos principales, en función de la estructura de los datos. Por ejemplo, si va a crear archivos independientes con una marca de fecha y hora en el nombre, puede copiar esos archivos de nuevo en la región primaria. Esta solución se puede aplicar a cargas de trabajo como el registro y los datos de IoT.
Control de reintentos
Las aplicaciones que se comunican con los servicios que se ejecutan en la nube deben ser sensibles a eventos no planeados y errores que pueden producirse. Estos errores pueden ser transitorios o persistentes, desde una pérdida momentánea de conectividad a una interrupción significativa debido a un desastre natural. Es importante diseñar aplicaciones en la nube con el control de reintento adecuado para maximizar la disponibilidad y mejorar la estabilidad general de las aplicaciones.
Solicitudes de lectura
Si la región primaria deja de estar disponible, las solicitudes de lectura se pueden redirigir al almacenamiento secundario. Como se indicó anteriormente, debe ser aceptable que la aplicación lea datos obsoletos. La biblioteca cliente de Azure Storage ofrece opciones para controlar los reintentos y redirigir las solicitudes de lectura a una región secundaria.
En este ejemplo, el control de reintentos para Blob Storage se configura en la BlobClientOptions
clase y se aplicará al BlobServiceClient
objeto que creamos con estas opciones de configuración. Esta configuración sigue un enfoque primario y luego secundario, donde los reintentos de solicitud de lectura desde la región primaria son redirigidos a la región secundaria. Este enfoque es mejor cuando se espera que los errores de la región primaria sean temporales.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
Retry = {
// The delay between retry attempts for a fixed approach or the delay
// on which to base calculations for a backoff-based approach
Delay = TimeSpan.FromSeconds(2),
// The maximum number of retry attempts before giving up
MaxRetries = 5,
// The approach to use for calculating retry delays
Mode = RetryMode.Exponential,
// The maximum permissible delay between retry attempts
MaxDelay = TimeSpan.FromSeconds(10)
},
// If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for
// GET or HEAD requests during retries.
// If the status of the response from the secondary Uri is a 404, then subsequent retries
// for the request will not use the secondary Uri again, as this indicates that the resource
// may not have propagated there yet.
// Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
GeoRedundantSecondaryUri = secondaryAccountUri
};
// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
Si determina que es probable que la región primaria no esté disponible durante un largo período de tiempo, puede configurar todas las solicitudes de lectura para que apunten a la región secundaria. Esta configuración es un enfoque de tipo secundario únicamente. Como se explicó anteriormente, necesitará una estrategia para controlar las solicitudes de actualización durante este tiempo y una manera de informar a los usuarios de que solo se están procesando las solicitudes de lectura. En este ejemplo, creamos una nueva instancia de BlobServiceClient
que usa el endpoint de la región secundaria.
string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");
// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);
Saber cuándo cambiar al modo de solo lectura y solo las solicitudes secundarias forma parte de un patrón de diseño arquitectónico denominado patrón de Circuit Breaker, que se analizará en una sección posterior.
Solicitudes de actualización
Las solicitudes de actualización no se pueden redirigir al almacenamiento secundario, que es de solo lectura. Como se ha descrito anteriormente, la aplicación debe poder controlar las solicitudes de actualización cuando la región primaria no está disponible.
El patrón Circuit Breaker también se puede aplicar a las solicitudes de actualización. Para controlar los errores de solicitud de actualización, puede establecer un umbral en el código, como 10 errores consecutivos, y realizar un seguimiento del número de errores de las solicitudes a la región primaria. Una vez alcanzado el umbral, puede cambiar la aplicación al modo de solo lectura para que las solicitudes de actualización a la región primaria dejen de emitirse.
Cómo implementar el patrón Circuit Breaker
Controlar los errores que pueden tardar una cantidad variable de tiempo en recuperarse forma parte de un patrón de diseño arquitectónico denominado patrón Circuit Breaker. La implementación adecuada de este patrón puede impedir que una aplicación intente ejecutar repetidamente una operación que probablemente produzca un error, lo que mejora la estabilidad y la resistencia de la aplicación.
Un aspecto del patrón Circuit Breaker es identificar cuándo hay un problema continuo con un punto de conexión principal. Para realizar esta determinación, puede supervisar la frecuencia con la que el cliente encuentra errores reintentos. Dado que cada escenario es diferente, debe determinar un umbral adecuado que se usará para la decisión de cambiar al punto de conexión secundario y ejecutar la aplicación en modo de solo lectura.
Por ejemplo, podría decidir realizar el modificador si hay 10 errores consecutivos en la región primaria. Para realizar un seguimiento de esto, mantenga un recuento de los errores en el código. Si se realiza correctamente antes de alcanzar el umbral, establezca el recuento en cero. Si el recuento alcanza el umbral, cambie la aplicación para que use la región secundaria para las solicitudes de lectura.
Como enfoque alternativo, podría decidir implementar un componente de supervisión personalizado en la aplicación. Este componente podría hacer ping continuamente al punto de conexión de almacenamiento principal con solicitudes de lectura triviales (como leer un blob pequeño) para determinar su estado. Este enfoque ocuparía algunos recursos, pero no una cantidad significativa. Cuando se detecta un problema que alcanza el umbral, cambiaría a secundaria solo solicitudes de lectura y modo de solo lectura. En este escenario, cuando el ping al punto de conexión de almacenamiento principal vuelve a ser exitoso, puede cambiar de nuevo a la región principal y continuar permitiendo actualizaciones.
El umbral de errores que se usa para determinar cuándo se debe realizar el cambio puede variar para cada servicio en la aplicación, por lo que debería considerar convertir los umbrales en parámetros configurables.
Otra consideración es cómo controlar varias instancias de una aplicación y qué hacer al detectar errores reintentos en cada instancia. Por ejemplo, puede tener 20 máquinas virtuales que se ejecutan con la misma aplicación cargada. ¿Controla cada instancia por separado? Si una instancia comienza a tener problemas, ¿desea limitar la respuesta solo a esa instancia? ¿O desea que todas las instancias respondan de la misma manera cuando una instancia tiene un problema? Controlar las instancias por separado es mucho más sencillo que intentar coordinar la respuesta entre ellas, pero el enfoque dependerá de la arquitectura de la aplicación.
Manejo de datos eventualmente consistentes
El almacenamiento con redundancia geográfica funciona mediante la replicación de transacciones de la región principal a la secundaria. El proceso de replicación garantiza que los datos de la región secundaria sean finalmente coherentes. Esto significa que todas las transacciones de la región primaria aparecerán finalmente en la región secundaria, pero que puede haber un retraso antes de que aparezcan. Tampoco hay ninguna garantía de que las transacciones lleguen a la región secundaria en el mismo orden en que se aplicaron originalmente en la región primaria. Si las transacciones llegan a la región secundaria fuera de orden, podría considerar que sus datos en la región secundaria están en un estado inconsistente hasta que el servicio se ponga al día.
En el ejemplo siguiente de Azure Table Storage se muestra lo que puede ocurrir al actualizar los detalles de un empleado para que sean miembros del rol de administrador. Para este ejemplo, esto requiere actualizar la entidad employee y actualizar una entidad de rol de administrador con un recuento del número total de administradores. Observa cómo se aplican las actualizaciones fuera de orden en la región secundaria.
Hora | Transacción | Replicación | Hora de última sincronización | Resultado |
---|---|---|---|---|
T0 | Transacción A: Insertar empleado entidad en la principal |
Transacción A insertada a la base de datos principal. aún no se ha replicado. |
||
T1 | Transacción A replicado a secundario |
T1 | La transacción A se replicó en la secundaria. Hora de la última sincronización actualizada. |
|
T2 | Transacción B: Actualizar entidad de empleado en primaria |
T1 | Transacción B escrita en almacenamiento primario, aún no se ha replicado. |
|
T3 | Transacción C: Actualizar administrador entidad de función en principal |
T1 | Transacción C escrita en el sistema primario. aún no se ha replicado. |
|
T4 | Transacción C replicado a secundario |
T1 | Transacción C replicada en el servidor secundario. LastSyncTime no se actualizó porque transacción B aún no se ha replicado. |
|
T5 | Leer entidades de la secundaria |
T1 | Usted obtiene el valor desactualizado para el empleado. entidad porque la transacción B no ha todavía no replicado Consigues el nuevo valor para entidad de rol de administrador porque C tiene Replicado. La hora de la última sincronización todavía no ha ocurrido. ha sido actualizada porque la transacción B no se ha replicado. Puedes decirle a la entidad de rol de administrador es incoherente porque la fecha y hora de la entidad es posterior Hora de la última sincronización. |
|
T6 | Transacción B replicado a secundario |
T6 |
T6 : todas las transacciones a través de C tienen ha sido replicado, hora de la última sincronización La aplicación se actualiza. |
En este ejemplo, supongamos que el cliente cambia a leer desde la región secundaria en T5. Puede leer correctamente la entidad de rol de administrador en este momento, pero la entidad contiene un valor para el recuento de administradores que no es coherente con el número de entidades de empleado marcadas como administradores en la región secundaria en este momento. El cliente podría mostrar este valor, con el riesgo de que la información sea incoherente. Como alternativa, el cliente podría intentar determinar que el rol de administrador está en un estado potencialmente incoherente porque las actualizaciones se han producido fuera del orden y, a continuación, informar al usuario de este hecho.
Para determinar si una cuenta de almacenamiento tiene datos potencialmente incoherentes, el cliente puede comprobar el valor de la propiedad Hora de la última sincronización . Hora de la última sincronización indica la hora en que los datos de la región secundaria eran los últimos coherentes y cuando el servicio había aplicado todas las transacciones anteriores a ese momento dado. En el ejemplo anterior, después de que el servicio inserte la entidad employee en la región secundaria, la hora de la última sincronización se establece en T1. Permanece en T1 hasta que el servicio actualiza la entidad empleado en la región secundaria cuando se establece en T6. Si el cliente recupera la hora de la última sincronización cuando lee la entidad en T5, puede compararla con la marca de tiempo de la entidad. Si la marca de tiempo de la entidad es posterior a la hora de la última sincronización, la entidad se encuentra en un estado potencialmente incoherente y puede realizar la acción adecuada. El uso de este campo requiere que sepa cuándo se completó la última actualización del servidor primario.
Para obtener información sobre cómo comprobar la hora de la última sincronización, consulte Comprobación de la propiedad Hora de la última sincronización de una cuenta de almacenamiento.
Ensayo
Es importante probar que la aplicación se comporta según lo esperado cuando encuentra errores reintentos. Por ejemplo, debe probar que la aplicación cambia a la región secundaria cuando detecta un problema y, a continuación, vuelve a cambiar cuando la región primaria vuelve a estar disponible. Para probar correctamente este comportamiento, necesita una manera de simular errores reintentos y controlar la frecuencia con la que se producen.
Una opción es usar Fiddler para interceptar y modificar respuestas HTTP en un script. Este script puede identificar las respuestas que proceden del punto de conexión principal y cambiar el código de estado HTTP a uno que la biblioteca cliente de Storage reconoce como un error que se puede reintentar. Este fragmento de código muestra un ejemplo sencillo de un script Fiddler que intercepta las respuestas para leer las solicitudes en la tabla employeedata para devolver un estado 502:
static function OnBeforeResponse(oSession: Session) {
...
if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
&& (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
oSession.responseCode = 502;
}
}
Puede ampliar este ejemplo para interceptar una amplia gama de solicitudes y cambiar solo responseCode en algunos de ellos para simular mejor un escenario real. Para obtener más información sobre cómo personalizar los scripts de Fiddler, consulte Modificación de una solicitud o respuesta en la documentación de Fiddler.
Si ha configurado umbrales configurables para cambiar la aplicación a solo lectura, será más fácil probar el comportamiento con volúmenes de transacciones que no son de producción.
Pasos siguientes
Para obtener un ejemplo completo en el que se muestra cómo realizar el cambio entre los extremos principal y secundario, consulte Ejemplos de Azure: uso del patrón circuit breaker con RA-GRS almacenamiento.