Trabajar con microservicios nos aporta numerosas ventajas, tantas que incluso a veces nos olvidamos de los desafíos que esto puede conllevar.
De ahí surge la necesidad de tener más control y visibilidad de como se comporta nuestro sistema en cada momento.
¿Por que es tan importante la observabilidad en microservicios?
- Conseguimos mantener consistencia en nuestro sistema.
- Podremos resolver posibles problemas y errores de manera más ágil.
- Obtenemos mayor visibilidad y trazabilidad de lo que ocurre en nuestro sistema.
- Obtenemos el estado de nuestro sistema en tiempo real y siempre disponible.
Dentro de la observabilidad nos encontramos con 3 pilares fundamentales:
- Logs: Almacenan información de eventos producidos en nuestros servicios, proveen información sobre qué esta pasando en tiempo real. Es una manera de obtener información detallada sobre el flujo de tu sistema para poder identificar futuros errores.
- Métricas: Almacena datos de rendimiento de cada servicio, como podrían ser el uso de CPU o el uso de memoria. Con esto podemos identificar anomalías y problemas de rendimiento en nuestro sistema.
- Trazas: Podremos ver el flujo y las respuestas entre nuestros servicios. Las trazas son un punto importante ya que nos da la posibilidad de encontrar el foco del error de manera mucho las eficiente. Podremos ver en que servicio en concreto esta sucediendo algo (ya sea error o no). Aunque el error se haya producido en otro servicio, seremos capaces de identificar de dónde viene originalmente.
- Alertas: Este punto es esencial en observabilidad, ya que las alertas serán las que nos tengan informados en todo momento de qué está pasando. Siendo éstas configurables y adaptables a nuestro sistema.
A continuación veremos algunos de los posibles patrones que se pueden aplicar en nuestro sistema:
1. Health Check API
Este primer patrón se basa en la implementación de una serie de endpoints que nos devolverán el estado actual de nuestro servicio, así como el estado de servicios externos de los que dependa, como podrían ser RabbitMQ o Redis.
Esto es interesante cuando tenemos el caso de que nuestro servicio no es capaz de procesar ciertas operaciones, como podría ser la desconexión de nuestra base de datos mientras el servicio sigue corriendo.
Tendremos un endpoint que nos dará el estado de nuestra base de datos, el cual consultaremos periódicamente para tener un estado controlado del servicio. Las respuestas de estos endpoints los podremos representar en un dashboard.
2. Log Aggregation
En este caso nuestros servicios se tienen que encargar de generar una serie de logs (en base a nuestras necesidades), los cuales se enviarán y se almacenarán en un servicio de logging centralizado.
Los logs almacenados pueden contener información de lo que esta ocurriendo en nuestro servicio, errores producidos en éste, warnings etc.
A partir de estos logs y usando el servicio de logging, podremos crear alertas en base a los resultados de los logs generados. Por ejemplo, podremos generar una alerta cuando se hayan producido X número de logs con un mensaje de error especifico.
Algunos de los servicios de logging que podríamos usar son Sumologic o Datadog.
3. Distributed tracing
Con este patrón tendremos la posibilidad de tener información de todas las posibles interacciones entre servicios. Podremos obtener una traza detallada de todo el flujo completo.
En cada petición que haga nuestro sistema deberemos generar un ID único. Mandaremos este ID en las peticiones que hagamos y los eventos que lancemos, de esta manera lo podremos identificar como una única transacción entre los distintos servicios.
Con este ID podremos buscar los logs relacionados dentro de nuestro servicio de logging y ver de manera estructura cual ha sido todo el proceso.
4. Exception tracking
En este caso las excepciones lanzadas desde nuestros servicios irán reportadas a un servicio de tracking de errores, como podría ser Sentry.
Estas excepciones de mostrarán detalladas en el servicio de tracking, mostrando dónde se generó el error, los parámetros recibidos, la cantidad de veces que se ha producido etc.
Con esta información a través del servicio de tracking podemos generar alertas de estos errores.
Por ejemplo, recibimos un error 500 al hacer una petición a uno de nuestros endpoints, recogeremos este error y lanzaremos una alerta, ya sea via email o Slack. En nuestro servicio de tracking de errores, podremos ver, a que hora se generó el error, donde se generó el error, el entorno donde se produzco o la cantidad de veces que ocurrió.
5. Application metrics
Este patrón se encarga de recoger todas las métricas de nuestros servicios y reunirlas en una plataforma común. Las posibles métricas recogidas son:
- A nivel de infraestructura: CPU, memoria, disco etc.
- A nivel de aplicación: Latencia en una petición, número de peticiones etc.
- A nivel de usuario: Tiempos de carga de la aplicación
Todas estas métricas, al igual que los patrones ya mencionados, se almacenarán en un sistema centralizado, como podría ser New Relic o AWS CloudWatch.
Al igual que en el resto de patrones, de estas métricas podremos generar alertas personalizadas.
6. Audit logging
Guardaremos en base de datos toda la actividad del usuario con nuestro servicio.
Podremos saber el uso que se le está dando a nuestra aplicación, para así identificar posibles problemas de performance o incluso problemas de seguridad.
Se almacenará toda la información relativa al usuario, como podría ser, la identidad de éste, la acción que ha ejecutado etc.
Conclusión
Implementar observabilidad en nuestro sistema es una inversión a largo plazo para conseguir un sistema estable y mantenible.
Nos aporta una manera de detectar errores sin tener un gran contexto de la aplicación.
A la hora de documentar y explicar cualquier incidencia nos será mas sencillo.
Podremos ser proactivos ante posibles problemas de performance.
Cierto es que su implementación puede llegar a ser costosa, pero puesto en la balanza, esto nos aportará mas ventajas que desventajas.
_Bibliografia:
https://microservices.io/patterns
https://medium.com/@greekykhs/microservices-observability-patterns-eff92365e2a8