Mejora de la resistencia con la ingeniería del caos y la inserción de errores

Publicado el 27 julio, 2020

Chief Technology Officer, Microsoft Azure

“Cuando inicié esta serie de entradas de blog sobre la mejora de la confiabilidad con mi entrada del pasado mes de julio, destaqué varias iniciativas que están en marcha para seguir mejorando la disponibilidad de la plataforma, como parte de nuestro compromiso de proporcionar un conjunto de servicios en la nube de confianza. Un área que mencioné es la inserción de errores, que nos está permitiendo validar cada vez más que los sistemas funcionarán según lo previsto en el caso de que se produzcan errores. Hoy le he pedido a nuestro administrador principal de programas en esta área, Chris Ashton, que arroje algo de luz sobre estos conceptos más amplios de “ingeniería del caos” y que muestre ejemplos de cómo los estamos aplicando ya en Azure, junto con pruebas de esfuerzo y cargas de trabajo sintéticas, para mejorar la resistencia de las aplicaciones y los servicios”. - Mark Russinovich, director de tecnología, Azure.


 

El desarrollo de aplicaciones distribuidas a gran escala nunca ha sido más fácil, pero hay un inconveniente. Sí, la infraestructura se proporciona en minutos gracias a la nube pública, hay muchas opciones de lenguaje entre las que elegir, gran cantidad de código abierto disponible para aprovecharlo y numerosos componentes y servicios en Marketplace para usarlos como base. Sí, hay buenas guías de consulta que ayudan con la arquitectura y el diseño de las soluciones, como Azure Well-Architected Framework y otros recursos del Centro de arquitectura de Azure. Pero, aunque el desarrollo de aplicaciones es más sencillo, también hay un mayor riesgo de que surjan problemas relacionados con las dependencias. Aunque solo sea en raras ocasiones, pueden producirse interrupciones que escapen a su control en cualquier momento, pueden surgir incidentes relacionados con las dependencias o puede verse ralentizada la capacidad de respuesta de sus servicios o sistemas clave. Interrupciones leves en un área pueden agravarse o tener efectos secundarios duraderos en otra área. Estas interrupciones del servicio pueden restar productividad a los desarrolladores, afectar negativamente a la confianza de los clientes, provocar la pérdida de negocio e incluso afectar al balance final de su organización.

Las aplicaciones modernas, así como las plataformas en la nube en las que se crean, deben diseñarse y validarse continuamente para posibles errores que puedan surgir. Los desarrolladores deben tener en cuenta las condiciones de error conocidas y desconocidas, las aplicaciones y los servicios deben estar diseñados para ofrecer redundancia, los algoritmos necesitan mecanismos de reintento y retroceso. Los sistemas deben ser resistentes a situaciones y condiciones causadas por interrupciones y perturbaciones en el entorno de producción que son poco frecuentes pero inevitables. Esta entrada está diseñada para ayudarle a pensar en la mejor manera de validar las condiciones de error habituales, incluso con ejemplos de cómo validamos en Microsoft nuestros propios sistemas.

Resistencia

Resistencia es la capacidad de un sistema para dejar de funcionar de manera controlada y, finalmente, recuperarse ante eventos disruptivos. La validación de que una aplicación, un servicio o una plataforma son resistentes es igual de importante que crearlos para resistir ante posible errores. Es fácil y tentador validar la confiabilidad de los componentes individuales de forma aislada y deducir que todo el sistema será igual de confiable, pero esto podría ser un error. La resistencia es una propiedad de todo un sistema, no solo de sus componentes. Para saber si un sistema es realmente resistente, lo mejor es medir y saber la resistencia de todo el sistema en el entorno en el que se ejecutará. Pero, ¿cómo se puede hacer esto y dónde habría que empezar?

Ingeniería del caos e inserción de errores

La ingeniería del caos es la práctica de someter un sistema a errores y problemas de dependencia reales que experimentará en un entorno de producción. La inserción de errores consiste en la introducción deliberada de errores en un sistema con el fin de validar su solidez y su capacidad de controlar los errores.

Mediante el uso de la inserción de errores y la aplicación de prácticas de ingeniería del caos de forma generalizada, los arquitectos pueden generar confianza en sus diseños y los desarrolladores pueden medir, conocer y mejorar la resistencia de sus aplicaciones. Del mismo modo, los ingenieros de confiabilidad de sitios (SRE) y, en realidad, cualquier persona cuyo equipo tenga responsabilidad en este campo, puede asegurar que sus objetivos de nivel de servicio están dentro de lo previsto y supervisar el estado del sistema en producción. También los equipos de operaciones pueden validar el hardware y los centros de datos nuevos antes de implementarlos para que los usen los clientes. La incorporación de técnicas de caos en la validación de versiones proporciona a todos, incluida la directiva, confianza en los sistemas que está creando su organización.

A lo largo del proceso de desarrollo, realice pruebas frecuentes desde las primeras fases, como es de esperar que ya esté haciendo. A medida que prepare una aplicación o un servicio para producción, lleve a cabo las prácticas de pruebas normales, es decir, agregue y ejecute pruebas unitarias, funcionales, de esfuerzo y de integración. Si procede, agregue también pruebas para casos de error y utilice la inserción de errores para comprobar el control de los errores y el comportamiento de los algoritmos. Para un impacto aún mayor, y aquí es donde la ingeniería del caos entra en juego realmente, aumente las cargas de trabajo por completo (como pruebas de esfuerzo, bancos de pruebas del rendimiento o una carga de trabajo sintética) con la inserción de errores. Comience en un entorno de prueba de preproducción antes de hacer experimentos en producción y vea cómo se comporta la solución en un entorno seguro con una carga de trabajo sintética antes de introducir un posible impacto en el tráfico real de los clientes.

Un uso correcto de la inserción de errores en un proceso de validación puede incluir uno o varios de los siguientes elementos:

  • Validación ad hoc de características nuevas en un entorno de prueba:
    Un desarrollador podría configurar una máquina virtual (VM) de prueba y ejecutar el nuevo código de forma aislada. Al ejecutar pruebas funcionales o de esfuerzo, se pueden insertar errores para bloquear el acceso de red a una dependencia remota (como SQL Server) para demostrar que el nuevo código controla la situación correctamente.
  • Inserción de errores automatizada en una canalización de CI/CD, incluidas las puertas de implementación o resistencia:
    Las pruebas de escenario completas (como la pruebas de integración o de esfuerzo) se pueden ampliar con la inserción de errores. Solo tiene que insertar un nuevo paso después de la ejecución normal para seguir ejecutando el código o ejecutarlo de nuevo con algunos errores aplicados. Al agregar errores, se pueden detectar problemas que, normalmente, no se habrían encontrado con las pruebas, o bien acelerar la detección de problemas que se podrían haber encontrado finalmente.
  • Validación de la corrección de incidentes y pruebas de regresión de incidentes:
    La inserción de errores se puede usar junto con una carga de trabajo o una ejecución manual para inducir las mismas condiciones que causaron un incidente y, de este modo, permitir la validación de la corrección de un incidente específico o la realización de pruebas de regresión del escenario de un incidente.
  • Simulacros de BCDR en un entorno de preproducción:
    Los errores que provocan la conmutación por error de una base de datos o que dejan sin conexión el almacenamiento se pueden usar en simulacros de BCDR, con el fin de validar que los sistemas se comportan correctamente en el caso de que se produzcan estos errores y que no se pierden los datos durante las pruebas de conmutación por error.
  • Días de partido en producción:
    Un “día de partido” es una simulación coordinada de una interrupción o un incidente para validar que los sistemas controlan el evento correctamente. Normalmente, esto incluye la validación de los sistemas de supervisión y también procesos humanos que entran en juego durante un incidente. Los equipos que llevan a cabo los días de partido pueden aprovechar las herramientas de inserción de errores para provocar errores que representen un escenario hipotético de una manera controlada.

Canalización de versión típica

En esta ilustración se muestra una canalización de versión típica y las oportunidades para incorporar la inserción de errores:

Oportunidades de caos en una canalización de versión

 

Una inversión en prácticas de inserción de errores será más fructífera si se basa en algunos componentes fundamentales:

  • Canalización de implementación coordinada.
  • Implementaciones de ARM automatizadas.
  • Ejecutores sintéticos y cargas de trabajo sintéticas completas.
  • Paneles de supervisión, de alertas y del sitio en vivo.

Con estos elementos en contexto, la inserción de errores se puede integrar en el proceso de implementación con muy poca o ninguna sobrecarga adicional, y se puede usar para validar el flujo de código en su camino hacia producción.

En el análisis de la causa principal de incidentes anteriores, se encontraron interrupciones del suministro eléctrico en bastidores o errores en equipos localizados como únicos puntos de error. Descubrir que un servicio se ha visto afectado por uno de estos eventos en producción y que no es resistente a él es un proceso largo, arduo y costoso para un ingeniero de guardia. Hay varias oportunidades para usar la inserción de errores con el fin de validar la resistencia a estos errores a lo largo de la canalización de versión en un entorno y un período de tiempo controlados, lo que también se traduce en más oportunidades para que el autor del código lleve a cabo una investigación de los problemas detectados. Un desarrollador que tenga cambios de código o un código nuevo puede crear un entorno de prueba, implementar el código y realizar experimentos ad hoc usando pruebas funcionales y herramientas con errores que simulen una desconexión de las dependencias, como apagar máquinas virtuales, bloquear el acceso a servicios o, simplemente, modificar los permisos. En un entorno de ensayo, se puede agregar la inserción de errores similares a pruebas de integración y completas automatizadas, o a otras cargas de trabajo sintéticas. Los resultados y la telemetría de las pruebas se pueden usar para determinar el impacto de los errores y compararlo con el rendimiento de línea de base para bloquear el flujo de código si es necesario.

En un entorno de preproducción o controlado, se pueden usar ejecutores automatizados con errores que bloqueen de nuevo el acceso a las dependencias o las desconecten. Después, se pueden usar los paneles de supervisión, de alertas y del sitio en vivo para validar que se han observado las interrupciones y que el sistema reaccionó y compensó el problema, es decir, que mostró resistencia. En este mismo entorno, los SRE o los equipos de operaciones pueden realizar también simulacros de continuidad empresarial y recuperación ante desastres (BCDR), usando la inserción de errores para desconectar el almacenamiento o las bases de datos y, una vez más, supervisar las métricas del sistema para validar la resistencia y la integridad de los datos. Estas mismas actividades controladas se pueden realizar también en producción, donde haya tráfico real de los clientes, pero, en ese caso, habrá una probabilidad mayor de que afecte a los clientes, por lo que solo se recomienda hacerlo después de haber usado la inserción de errores en fases anteriores de la canalización. El establecimiento de estas prácticas y la incorporación de la inserción de errores a una canalización de implementación permite llevar a cabo una validación sistemática y controlada de la resistencia que permita a los equipos mitigar los problemas y mejorar la confiabilidad de las aplicaciones sin que ello afecte a los clientes finales.

Inserción de errores en Microsoft

En Microsoft, algunos equipos incorporan la inserción de errores en las primeras fases de la canalización de validación y de las pruebas automatizadas. Los diferentes equipos ejecutan pruebas de esfuerzo, bancos de pruebas de rendimiento o cargas de trabajo sintéticas en sus puertas de validación automatizadas como algo habitual y tienen establecida una línea base. Después, vuelven a ejecutar la carga de trabajo, pero esta vez con errores aplicados, como presión en la CPU, inestabilidad en las operaciones de E/S del disco o latencia de red. Los resultados de la carga de trabajo se supervisan, se examina la telemetría, se comprueban los volcados de memoria y se comparan los indicadores de nivel de servicio (SLI) con los objetivos de nivel de servicio (SLO) para medir el impacto. Si se considera que los resultados indican un error, es posible que el código no continúe a la siguiente fase de la canalización.

Otros equipos de Microsoft usan la inserción de errores en simulacros de continuidad empresarial y recuperación ante desastres (BCDR) y en los días de partido. Algunos equipos realizan simulacros de BCDR mensuales, trimestrales o semestrales, y usan la inserción de errores para inducir un desastre y validar tanto el proceso de recuperación como los procesos de alerta, de supervisión y del sitio en vivo. Esto se suele hacer en un entorno de preproducción controlado antes de usarlo en producción con el tráfico real de los clientes. Algunos equipos también llevan a cabo días de partido, donde elaboran un escenario hipotético, como la replicación de un incidente anterior, y usan la inserción de errores para prepararlo. En este caso, los errores podrían ser más destructivos, como el bloqueo de máquinas virtuales, la desactivación del acceso a la red, la provocación de la conmutación por error de las bases de datos o la simulación de la desconexión de un centro de datos completo. De nuevo, se utilizan las alertas y la supervisión del sitio en vivo habituales, por lo que también se validan los procesos de DevOps y de administración de incidentes. Para no molestar a los implicados, estas actividades suelen realizarse durante el horario comercial, no por la noche ni durante el fin de semana.

Nuestros equipos de operaciones también usan la inserción de errores para validar el hardware nuevo antes de implementarlo para que lo usen los clientes. Se realizan simulacros en los que se corta el suministro eléctrico de un bastidor o un centro de datos. Así se pueden observar los sistemas de supervisión y copia de seguridad para asegurar que funcionan según lo previsto.

En Microsoft, usamos principios de ingeniería del caos y técnicas de inserción de errores para aumentar la resistencia y la confianza en los productos que distribuimos. Se utilizan para validar las aplicaciones que ofrecemos a los clientes y los servicios que ponemos a disposición de los desarrolladores. Se usan para validar la propia plataforma Azure subyacente, con el fin de probar el hardware nuevo antes de implementarlo. Por separado y en conjunto, estas prácticas contribuyen a la confiabilidad general de la plataforma Azure y a una mejor calidad de nuestros servicios.

Consecuencias no deseadas

Recuerde: la inserción de errores es una herramienta eficaz y debe usarse con precaución. Deben implementarse medidas de seguridad para asegurarse de que los errores introducidos en un entorno de prueba o de preproducción no afecten también al entorno de producción. El radio de acción de un escenario de error debe estar contenido para minimizar el impacto en otros componentes y en los clientes finales. La capacidad de insertar errores debe tener el acceso restringido, con el fin de evitar accidentes o el uso potencial de piratas informáticos malintencionados. La inserción de errores se puede usar en producción, pero debe planearse con cuidado, probar primero en un entorno de preproducción, limitar el radio de acción y disponer de un mecanismo de seguridad para asegurar que un experimento se pueda parar de inmediato si fuese necesario. El accidente nuclear de Chernóbil de 1986 es un ejemplo aleccionador de un simulacro de inserción de errores que acabó mal. Tenga cuidado de aislar su sistema de consecuencias no deseadas.

¿Caos como servicio?

Como dijo Mark Russinovich en esta entrada de blog anterior, nuestro objetivo es que los servicios de inserción de errores nativos estén disponibles para los clientes y asociados, con el fin de que puedan llevar a cabo la misma validación en sus propios servicios y aplicaciones. Este es un campo muy interesante, con un gran potencial para mejorar la confiabilidad de los servicios en la nube y reducir el impacto de las interrupciones, que, aunque son muy poco frecuentes, son inevitables. Hay muchos equipos haciendo muchas cosas interesantes en este campo, y estamos estudiando la mejor manera de reunir todas estas herramientas y errores diferentes para facilitarnos la vida, para nuestros desarrolladores internos que crean los servicios de Azure, para los servicios integrados en Azure, como Microsoft 365, Microsoft Teams y Dynamics y, finalmente, para que nuestros clientes y asociados usen las mismas herramientas para causar estragos en sus propias aplicaciones y soluciones con el fin de mejorar su resistencia.