Skip to main content

¿Alguna vez has perdido información importante debido a un fallo informático?

¿Tu negocio se ha visto paralizado por la caída de un servicio? Estos problemas son más comunes de lo que parecen, especialmente a medida que las empresas crecen y sus sistemas se vuelven más complejos.

A lo largo de nuestra experiencia, hemos encontrado este tipo de situaciones en varias ocasiones. A medida que una organización avanza, sus sistemas informáticos crecen en complejidad y los requisitos del negocio se vuelven más exigentes. Esto convierte procesos simples en críticos, y cuando se produce un fallo, el impacto puede ser significativo.

Este desafío aumenta cuando el sistema escala hacia un entorno distribuido, donde múltiples componentes o servicios deben comunicarse de manera eficiente. En sistemas distribuidos, se introducen nuevas posibilidades de asincronía y vectores de error que no aparecen en un sistema monolítico.

Por eso, es crucial que las soluciones tecnológicas estén preparadas para afrontar estos retos. Los sistemas deben diseñarse para minimizar los fallos y, cuando ocurran, mitigar sus efectos de manera eficaz.

Gestionando los fallos en el software

Como ingeniero de software, existen dos enfoques principales para gestionar los fallos en una aplicación o sistema:

Prevenir los fallos

El primer enfoque es intentar que tu sistema no sea susceptible de fallar, es decir, que siempre se comporte como se espera y que su funcionamiento esté completamente definido, sin bugs. Todos nos esforzamos por no introducir fallos en nuestros sistemas, pero alcanzar un software perfecto es prácticamente imposible. Sin embargo, existen técnicas y tecnologías que nos permiten acercarnos a este objetivo. Algunos ejemplos incluyen:

    • Testing automatizado
    • Análisis estático de código, que detecta posibles errores en nuestra base de código
    • Verificación formal, utilizada en lenguajes como Ada u OCaml (Coq), aplicable en sectores críticos como el aeronáutico o militar.

Asumir que el sistema puede fallar

El segundo enfoque es reconocer que los fallos son inevitables y estar preparados para ellos. Esto implica establecer protocolos de recuperación y minimizar los daños. Un sistema verdaderamente resiliente es aquel que, ante un fallo, sigue funcionando sin afectar al negocio.

En LambdaLoopers, hemos desarrollado una amplia experiencia utilizando tecnologías que nos ayudan a diseñar sistemas tolerantes a fallos. Con estas herramientas, reducimos significativamente el tiempo de inactividad (downtime) y logramos que nuestros sistemas sean resistentes ante imprevistos.

Retos de una arquitectura distribuida

BackPressure: ¿Está tu sistema preparado para enfrentarse a situaciones de estrés?

El término BackPressure proviene de la dinámica de fluidos, donde se utiliza para describir una fuerza que se opone al movimiento de un fluido en una tubería. En la ingeniería de software, este concepto se aplica cuando un flujo de datos no se procesa a la velocidad adecuada.

Imaginemos un escenario: el servicio A envía mensajes al servicio B, que puede procesar 60 mensajes por segundo. Si en algún momento el servicio A comienza a enviar 90 mensajes por segundo, el servicio B enfrentará dos posibles problemas:

  1. El servicio B se satura y se cae, permaneciendo inactivo hasta su recuperación.
  2. El servicio B sigue procesando 60 mensajes por segundo, pero los 30 restantes se pierden sin ser procesados.

 

Técnicas de Mitigación del BackPressure:

Para evitar estos problemas, existen varias técnicas de mitigación del BackPressure:

Limitar el ratio de mensajes

Se controla el ritmo al que el servicio A envía mensajes para que el servicio B pueda procesarlos adecuadamente. Sin embargo, esta solución puede ser compleja debido a la comunicación bidireccional necesaria.

Uso de buffers

Almacenar los mensajes en un buffer para que el servicio B los consuma a su propio ritmo. Esto permite ponerse al día cuando la carga disminuye.

Descartar información

Dependiendo de la naturaleza de los datos, se puede optar por descartar parte de la información. Combinado con el buffering, el servicio B podría procesar solo un porcentaje de los mensajes entrantes, generalmente basado en el tiempo.

Auto-escalado

Detectar la sobrecarga y escalar automáticamente el servicio B para procesar más mensajes por segundo.

En LambdaLoopers, hemos implementado sistemas de comunicación asíncrona mediante colas que funcionan como buffers en arquitecturas de microservicios, utilizando tecnologías como Apache Kafka o RabbitMQ.

También contamos con experiencia en el despliegue de estas soluciones en Azure, utilizando herramientas como Azure Event Hubs y Azure Service Bus para el procesamiento de datos en tiempo real y la intercomunicación entre servicios. Monitorizamos constantemente el lag en los buffers y auto-escalamos los servicios para reducir el efecto del BackPressure, manteniendo así flujos de datos en tiempo real.

Respuesta a errores: Modelo de actores Akka

Como mencionamos anteriormente, en un sistema distribuido es casi inevitable enfrentar fallos. Estos pueden ser causados por diversos factores, entre ellos:

  1. Bugs en el código, introducidos por errores humanos o situaciones no previstas.
  2. Fallos de hardware o infraestructura, como un disco duro dañado o cortes de energía.
  3. Errores de comunicación, paralelismo y concurrencia, donde los mensajes pueden no llegar, duplicarse o procesarse en un orden incorrecto.

A medida que el sistema escala, se vuelve esencial utilizar arquitecturas y soluciones que manejen estos errores de manera eficaz. El objetivo es que, ante un fallo, el funcionamiento del sistema completo no se vea amenazado, se pierda la menor cantidad de información posible y la parte afectada se recupere automáticamente sin intervención humana.

Modelo de actores

Para lograr esto, utilizamos el modelo de actores, un enfoque matemático que nació en 1973 y fue adoptado por Ericsson en 1986 con el desarrollo de Erlang, un lenguaje de programación y runtime basado en este modelo. Tras su éxito en telecomunicaciones, muchas bibliotecas y frameworks han adoptado este concepto en otros lenguajes y tecnologías. Uno de los más conocidos es Akka, un framework de Scala diseñado para sistemas de alto throughput y baja latencia, y que sirve como base de tecnologías actuales como Apache Spark.

Ventajas del modelo de actores en la programación concurrente

En el modelo de actores, la unidad básica de procesamiento es el actor, que recibe y emite mensajes para procesar. Cada actor tiene una pequeña cola de mensajes llamada Mailbox, donde los mensajes se almacenan hasta ser procesados. Este enfoque no solo simplifica el manejo de la concurrencia y permite escalabilidad horizontal, sino que también aporta una ventaja clave en la resiliencia del sistema.

 

Cuando un actor falla, ya sea por un estado corrupto, un bug en el código o un mensaje no contemplado, el actor se reinicia en un estado limpio. Lo importante es que los mensajes pendientes en el Mailbox no se pierden, permanecen en el orden correcto y el actor puede retomar su trabajo sin afectar al resto del sistema. Al estar los actores aislados y comunicarse solo a través de mensajes, los fallos de un actor no interfieren con el funcionamiento del resto del sistema.

El diseño basado en el modelo de actores requiere un enfoque distinto al de la programación tradicional, pero ofrece ventajas significativas en términos de concurrencia, escalabilidad y tolerancia a fallos. Es, sin duda, una de las soluciones más sólidas para la programación concurrente y distribuida.

En LambdaLoopers, utilizamos el modelo de actores Akka y Akka.NET para diseñar sistemas que minimicen el downtime y reduzcan los efectos de los fallos. Además, estas herramientas nos permiten aplicar técnicas avanzadas como:

  • Políticas de reintento: Reintentar una operación tras un fallo, pasado un tiempo.
  • Circuit Breaking: Detener el envío de mensajes a un servicio que está fallando durante un periodo de tiempo.
  • Timeouts: Terminar una operación si supera un tiempo límite, permitiendo continuar con la siguiente tarea y evitando el BackPressure.

Monitorización: Conocimiento en todo momento del estado de tu sistema

Una pieza clave para garantizar que tu sistema esté preparado ante fallos es contar con un sólido sistema de monitorización. La monitorización proporciona una visión completa y en tiempo real del estado y rendimiento del sistema, permitiendo detectar posibles problemas antes de que se conviertan en fallos críticos.

En LambdaLoopers, utilizamos diversas herramientas de monitorización para asegurar el correcto funcionamiento de nuestras soluciones:

  • Grafana: Implementamos dashboards en tiempo real que nos permiten visualizar estadísticas clave de rendimiento. Estas métricas son fundamentales para detectar picos de carga o problemas en la infraestructura.
  • Sentry: Esta herramienta recopila información de diagnóstico de errores que se producen en nuestras soluciones, proporcionando un análisis detallado de las fallas para poder corregirlas rápidamente.
  • Better Uptime: Integramos esta herramienta para proporcionar alertas automáticas y mejorar la transparencia sobre el estado del sistema. Better Uptime nos ayuda a identificar anomalías, como una regresión en componentes o un aumento inusual de carga.

En conclusión, gracias a la implementación de estas herramientas, tanto el equipo de operaciones como el de desarrollo tiene mayor capacidad de reacción ante imprevistos. Esto disminuye el tiempo de degradación del sistema y minimiza las consecuencias de los fallos.

¿Quieres saber más sobre sistemas resilientes en entornos distribuidos?

Leave a Reply

Discover more from LambdaLoopers

Subscribe now to keep reading and get access to the full archive.

Continue reading