Compartir vía


Diseño para la recuperación automática

Diseñe la aplicación para que se recupere automáticamente cuando esto suceda.

En un sistema distribuido, hay que esperar que se produzcan fallos. Pueden producirse errores de hardware. La red puede tener errores transitorios. En raras ocasiones, un servicio completo, un centro de datos o incluso una región de Azure podrían experimentar una interrupción. Sin embargo, incluso eso debe planificarse en la arquitectura de la carga de trabajo. La resistencia y la recuperación deben abordarse al principio del diseño de la carga de trabajo.

Por tanto, diseñe una aplicación que se recupere automáticamente cuando esto suceda. Esto requiere un enfoque basado en tres puntos:

  • Detectar errores.
  • Responder a los errores con elegancia.
  • Registrar y supervisar errores a fin de conseguir una perspectiva operativa.

La manera de responder a un determinado tipo de error depende de los requisitos de disponibilidad de su aplicación. Por ejemplo, si necesita alta disponibilidad, puede implementar en varias zonas de disponibilidad de una región. Para evitar interrupciones, incluso en el caso improbable de que toda una región de Azure sufra una interrupción, puede conmutar automáticamente a una región secundaria. Sin embargo, eso generará un coste más alto y un rendimiento potencialmente más bajo que una implementación de una sola región.

Además, no piense solo en grandes eventos como interrupciones regionales, que suelen ser poco frecuentes. Debe centrarse igualmente, si no más, en la gestión de los errores locales y de corta duración, como los errores de conectividad de red o los errores en la conexión a una base de datos.

Recomendaciones

Use componentes desacoplados que se comunican de forma asincrónica. Lo ideal es que los componentes estén desacoplados en el tiempo y el espacio. Desacoplado en el tiempo significa que los componentes no necesitan estar presentes al mismo tiempo para que la comunicación sea posible. Desacoplado en el espacio significa que el emisor y el receptor no tienen por qué ejecutarse en el mismo proceso, pero pueden hacerlo siempre que sea más eficiente. Lo ideal es que los componentes desacoplados usaran eventos para comunicarse entre sí. Esto ayuda a minimizar la posibilidad de errores en cascada.

Vuelva a intentar las operaciones fallidas. Los errores transitorios pueden deberse a una pérdida momentánea de conectividad de red, una conexión de base de datos caída o un tiempo de espera agotado cuando un servicio está ocupado. Cree la lógica de reintento en la aplicación para controlar los errores transitorios. En muchos de los servicios de Azure, el SDK de cliente implementa los reintentos automáticos. Para obtener más información, consulte Control de errores transitorios y patrón de reintento.

Proteja los servicios remotos con errores (Circuit Breaker). Es conveniente intentar de nuevo después de un fallo transitorio, pero si el fallo persiste, puede acabar con demasiados usuarios sobrecargando un servicio que está fallando. Esto puede provocar fallos en cadena, ya que las solicitudes se acumulan. Use el patrón Circuit Breaker para fracasar y responder rápido a los errores (sin realizar la llamada remota) cuando sea probable que una operación genere un error.

Aísle recursos críticos (Bulkhead). Los errores de un subsistema a veces pueden reproducirse en cascada. Esto puede ocurrir si un error provoca que algunos recursos, como subprocesos o sockets, no se liberen a tiempo, lo que conduce a un agotamiento de estos. Para evitarlo, use el patrón Bulkhead para particionar un sistema en grupos aislados para que un error en una partición no descompona todo el sistema.

Realice la ordenación de carga. Las aplicaciones pueden experimentar picos repentinos en el tráfico, lo que puede sobrecargar los servicios en el back-end. Para evitar esto, utilice el modeloQueue-Based Nivelación de carga para organizar los elementos de trabajo para ser ejecutados de forma asincrónica. La cola actúa como un búfer que suaviza los picos de carga.

Realice una conmutación por error. Si no se puede tener acceso a una instancia, aplique una conmutación por error a otra instancia. En el caso de los elementos que no tienen estado, como un servidor web, coloque varias instancias detrás de un equilibrador de carga o el administrador de tráfico. En el caso de los elementos que almacenan el estado, como una base de datos, use réplicas y la conmutación por error. En función del almacén de datos y del modo en que se replique, la aplicación puede tener que lidiar con la coherencia final.

Compensar las transacciones fallidas. En general, evite las transacciones distribuidas, ya que requieren coordinación a través de servicios y recursos. En su lugar, componga una operación a partir de transacciones individuales más pequeñas. Si se produce un error en la operación a mitad de camino, use Transacciones de compensación para deshacer cualquier paso que ya se haya completado.

Aplique puntos de control a las transacciones de ejecución prolongada. Los puntos de control pueden proporcionar resistencia si se produce un error en una operación de ejecución prolongada. Cuando la operación se reinicia (por ejemplo, si la recoge otra máquina virtual), es posible reanudar desde el último punto de control. Considere implementar un mecanismo que registre información sobre el estado de la tarea en intervalos regulares y que guarde este estado en almacenamiento duradero accesible para cualquier instancia del proceso que ejecute la tarea. De este modo, si el proceso se cierra, el trabajo que estaba realizando puede reanudarse desde el último punto de comprobación con otra instancia. Hay bibliotecas que proporcionan esta funcionalidad, como NServiceBus y MassTransit. Conservan de forma transparente el estado, donde los intervalos se alinean con el procesamiento de mensajes de colas en Azure Service Bus.

Degradación gradual y capacidad de respuesta en caso de error. En ocasiones no es posible solucionar un problema, pero puede proporcionar una funcionalidad reducida que sigue siendo útil. Piense en una aplicación que muestre un catálogo de libros. Si la aplicación no puede recuperar la imagen en miniatura de la portada, puede que muestre una imagen de marcador de posición. Es posible que para la aplicación no sea esencial contar con subsistemas completos. Por ejemplo, en un sitio de comercio electrónico, mostrar las recomendaciones de productos es probablemente menos crítico que procesar los pedidos.

Clientes limitados. En ocasiones, un número reducido de usuarios crea una carga excesiva, lo que puede reducir la disponibilidad de la aplicación para otros usuarios. En esta situación, limite el cliente durante un período de tiempo determinado. Consulte el patrón de limitación.

Bloquear individuos malintencionados. El hecho de que limite a un cliente no significa que ese cliente estuviera actuando de manera malintencionada. Simplemente significa que el cliente ha superado su cuota de servicio. Pero si un cliente supera constantemente su cuota o se comporta de manera incorrecta, tiene la posibilidad de bloquearlo. Defina un proceso fuera de banda para que el usuario solicite ser desbloqueado.

Use la elección del líder. Cuando necesite coordinar una tarea, use Leader Election para seleccionar un coordinador. De este modo, el coordinador no es un único punto de error. Si se produce un error en el coordinador, se selecciona uno nuevo. En lugar de implementar un algoritmo de elección de líder desde el principio, considere la posibilidad de una solución inmediata, como Zookeeper.

Realice pruebas con inserción de errores. Con demasiada frecuencia, el camino hacia el éxito está bien probado, pero no así el camino de los fracasos. Un sistema podría ejecutarse en producción durante mucho tiempo antes de que se utilice una ruta de acceso para errores. Use la inserción de errores para probar la resistencia del sistema a los errores, ya sea mediante la activación de errores reales o mediante su simulación.

Adopte la ingeniería del caos. La ingeniería del caos amplía la noción de inserción de errores mediante la inserción aleatoria de errores o condiciones irregulares en instancias de producción.

Usar zonas de disponibilidad. Muchas regiones de Azure proporcionan zonas de disponibilidad, que son conjuntos aislados de centros de datos dentro de la región. Algunos servicios de Azure se pueden implementar de forma zonal, lo que garantiza que se colocan en una zona específica y pueden ayudar a reducir la latencia en la comunicación entre los componentes de la misma carga de trabajo. Como alternativa, algunos servicios se pueden implementar con redundancia de zona, lo que significa que Azure replica automáticamente el recurso entre zonas para lograr una alta disponibilidad. Considere qué enfoque proporciona el mejor equilibrio de compromisos para su solución. Para obtener más información sobre cómo diseñar la solución para usar regiones y zonas de disponibilidad, consulte Recomendaciones para usar regiones y zonas de disponibilidad.

Para obtener un enfoque estructurado para realizar la recuperación automática de las aplicaciones, consulte Diseño de aplicaciones confiables para Azure.