La .NET CONF 2024 acaba de terminar. Descubre las NOVEDADES de .NET 9 junto a los CAMBIOS que trae C# 13.
Puedes ver el contenido de este vídeo junto con su curso en el modo vídeo (similar a Udemy) si pulsas aquí.

Monitorización en los sistemas distribuidos

Hemos visto a lo largo del curso de Distribt que vamos a crear microservicios para realizar diferentes acciones dentro de un sistema mas grande.

 

En el post sobre el patrón SAGA, vimos como una transacción sencilla en el mundo monolítico se convertía en una muy compleja dentro de los microservicios. Y mencioné que es muy importante tener una idea clara de todo lo que ha pasado, y cuando ha pasado en nuestro sistema.

 

 

 

1 - Observabilidad de nuestro sistema distribuido

Como acabo de mencionar es importante saber cuándo y cómo un evento en nuestro sistema ha sucedido, para ello tenemos 3 formas de hacerlo. 

 

  • Logs: los cuales van a decir el error concreto, o el evento en concreto que estamos indicando, vimos un post sobre ellos hace un tiempo.
  • Métricas: Las cuales nos dicen las estadísticas puras sobre el sistema; Por ejemplo una métrica es el tiempo de carga de determinada página en nuestra web o cuántas veces se ha cargado
  • Traces: El contexto de porque las cosas pasan. El curso de una acción a lo largo de nuestro sistema, de principio a fin. Si ponemos como ejemplo el caso de uso de la saga de creación de un pedido, cada evento tendrá una propiedad llamada “traceId” y en caso de tener un error únicamente debemos buscar por el ID en nuestro sistema de monitorización para encontrar todos los eventos relacionados. 

 

 

2 - Qué es OpenTelemetry? 

Cuando tenemos un sistema distribuido tenemos múltiples aplicaciones y estas aplicaciones pueden estar escritas todas en el mismo lenguaje de programación o en lenguajes diferentes. 

A la hora de crear sistemas es crucial tener métricas de datos para así ser capaces de detectar antes que el usuario cuando el sistema va lento o cuando algo está fallando. 

 

Antes de la llegada de OpenTelemetry cada lenguaje generaba las métricas de una manera, y cada servicio que utilizas las quería recibir de otra forma diferente. Por ejemplo New Relic quería recibir los datos en el formato A y Prometheus los quiere en el Formato B, etc. 

 

Esto causaba varios problemas, tener que implementar lo mismo varias veces, o la imposibilidad de cambiar de un proveedor a otro ya que bueno, tenías que escribir todo desde 0. 

Aquí es donde entra OpenTelemetry, estandariza la forma en la que las aplicaciones envían las métricas, para que así, esté en el lenguaje que esté tu aplicación escrita la información de las métricas será generada de la misma forma.  

Open telemetry collector example

Como puedes ver en la imagen, disponemos de un elemento que se llama OpenTelemetry collector, que es básicamente el servicio que va a recoger esos datos, procesarlos y mostrarlos, ya que OpenTelemetry no es una aplicación back end, sino un estándar que provee APIs y SDKs en los diferentes lenguajes así como la forma de exportar la información.

Por cierto, no está en la imagen, pero una máquina virtual, la pipeline de CI/CD, otros servicios de tu infraestructura, etc también pueden generar métricas.

 

2.1 -  OpenTelemetry Collector

Lo que llamamos Opentelemetry Collector es una aplicación o servicio que vamos a desplegar junto a nuestras aplicaciones, para que, dicha aplicación envíe los datos de las métricas a ese servicio. 

Tenemos dos formas de desplegar dicho collector

  1. Agente: cuando despliegas la aplicación debes correr otro servicio junto a ella, en el mismo host. Esta acción se hace normalmente con un sidecar si usas k8s o un daemonset, etc. 
  2. Puerta de entrada: el colector se despliega como un servicio más normal y corriente.

Puedes encontrar más información en la web oficial.

  • Nota: en nuestro ejemplo lo veremos desplegado en docker como un servicio.

 

 

3 - Visualizar métricas 

Hasta ahora, únicamente estamos exportando la información pero no estamos haciendo nada con ella, debemos procesarla y almacenarla para posteriormente visualizarla, aquí es donde entran Prometheus, Grafana y Zipkin; Aunque la realidad es que puedes utilizar los servicios que quieras o tengas disponibles en tu proveedor de servicios si estas en la nube, aún así, la idea es la misma.

 

3.1  - Qué es Prometheus?

Lo primero que necesitamos es un backend para almacenar la información, que procese dichos datos y los almacene, por lo tanto que actúe de base de datos. 

Aquí es donde entra Prometheus, una base de datos que hace de almacenamiento para nuestros sistemas de monitorización y métricas.

Imagen prometheus arquitectura

Y su interfaz no es nada del otro mundo la verdad, algo feucha:

Interfaz prometheus

Nota: Podemos enviar los datos directamente desde la aplicación a prometheus sin necesidad de pasar por OpenTelemetry, como siempre, dependerá de la infraestructura que quieres implementar. 

 

3.2 - Qué es Grafana? 

Una vez tenemos la información almacenada y procesada, vamos a querer poder verla, pero no verla de forma plana, sino con gráficos y tablas chulas. Ahi entra Grafana, es la interfaz de usuario que nos va a permitir ver las métricas.

arquitectura grafana y prometheus

Como puedes observar, yo soy un desastre haciendo gráficas, pero bueno, los datos están ahí para crear unos gráficos chulos.

imagen grafana

 

3.3 - Que es Zipkin?

Igual que Grafana nos da gráficos y diagramas sobre las métricas de nuestro sistema o de nuestra aplicación, lo que hace Zipkin es permitirnos ver la trazabilidad de las llamadas, donde va cada llamada y en qué punto tarda más o menos tiempo. 

ejemplo zipkin

 

 

NOTA: En este post no voy a mostrar como añadir traces personalizados o métricas personalizadas, ya que esta fuera del scope del post y sería muy largo. Estas acciones las mostraré en el futuro en post independientes. 

 

 

4 - Necesitamos OpenTelemetry? 

Ahora que ya he explicado que Open Telemetry es un estándar y que los que de verdad hacen el trabajo de almacenar, procesar y mostrar los datos son Prometheus y Grafana (u otros servicios), la pregunta es clara. 

 

¿Debemos implementar Open Telemetry en nuestros servicios? 

Pues depende un poco, como todo, siempre tenemos pros y contras. 

Un pro es que si cambiamos de proveedor, por ejemplo migramos de prometheus y grafana a New Relic no vamos a tener que cambiar el código. 

Pero a la vez, New Relic entiende el output de Prometheus. Esto quiere decir que si exportas a prometheus y cambias a new relic, no tienes que cambiar nada tampoco. 

  • Nota: no se lo que pasa en otros servicios, estos son los que tengo experiencia. 

 

Una contra es que para que OpenTelemetry funcione, debemos tener nuestro servicio/sidecar configurado lo que conlleva trabajo adicional, tanto en el mantenimiento del servicio como en los recursos del sistema que tenemos que asignar. 

Así que tendremos dos opciones, ir por la vía “rápida” donde enviamos los logs desde la aplicación al sistema backend (Prometheus), o pasamos por un intermediario para normalizar los datos (OpenTelemetry)? 

 

Como siempre radicará en los recursos que queramos invertir. 

 

 

5 - Configurar OpenTelemetry en .NET

Para este ejemplo lo voy a hacer con OpenTelemetry, lo que quiere decir que nuestras aplicaciones van a utilizar el opentelemetry collector y Prometheus se conectará a él para leer y procesar dicha información.

 

5.1 - Creación de la infraestructura para la observabilidad

Lo primero que haremos será crear toda la configuración que necesitamos en nuestro sistema, para ello vamos a nuestro fichero de docker compose y añadimos los contenedores de OpenTelemetry, Prometheus, Grafana y Zipkin

opentelemetry-collector:
  image: otel/opentelemetry-collector:latest
  container_name: open_telemetry_collector
  command: [ "--config=/etc/otel-collector-config.yaml" ]
  volumes:
    - ./tools/telemetry/otel-collector-config.yaml:/etc/otel-collector-config.yaml
    - ./tools/telemetry/logs:/etc/output:rw # Store the logs (not commited in git)
  ports:
    - "8888:8888"   # Prometheus metrics exposed by the collector
    - "8889:8889"   # Prometheus exporter metrics
    - "4317:4317"   # OTLP gRPC receiver
prometheus:
  image: bitnami/prometheus
  container_name: prometheus
  volumes:
    - ./tools/telemetry/prometheus.yaml:/etc/prometheus/prometheus.yml
  ports:
    - 9090:9090
grafana:
  image: grafana/grafana
  container_name: grafana
  environment:
    - GF_SECURITY_ADMIN_USER=admin
    - GF_SECURITY_ADMIN_PASSWORD=admin
    - GF_USERS_ALLOW_SIGN_UP=false
  volumes:
    - ./tools/telemetry/grafana_datasources.yaml:/etc/grafana/provisioning/datasources/all.yaml
  ports:
    - 3000:3000
zipkin:
  container_name: zipkin-traces
  image: openzipkin/zipkin:latest
  ports:
    - "9411:9411"

Como puedes observar, dentro del contenedor de OpenTelemetry estamos utilizando un fichero de configuración llmado otel-collector-config.yaml, el cual contiene la configuración que incluye protocolos disponibles y donde la información recolectada va a ser exportada:

# https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver
receivers:
  otlp:
    protocols:
      grpc:

# Configure exporters
exporters:
  # Export prometheus endpoint
  prometheus:
    endpoint: "0.0.0.0:8889"

  # log to the console
  logging:

  # Export to zipkin
  zipkin:
    endpoint: "http://zipkin:9411/api/v2/spans"
    format: proto

  # Export to a file
  file:
    path: /etc/output/logs.json

# https://opentelemetry.io/docs/collector/configuration/#processors
processors:
  batch:

# https://opentelemetry.io/docs/collector/configuration/#service
# https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/design.md#pipelines
service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging, zipkin]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [logging, prometheus]
    logs:
      receivers: [otlp]
      processors: []
      exporters: [logging, file]

 

Este es el de prometheus (prometheus.yaml), como vemos le estamos indicando que consulte el contenedor de opentelemetry para recibir los datos

scrape_configs:
  - job_name: 'collect-metrics'
    scrape_interval: 10s
    static_configs:
      - targets: ['opentelemetry-collector:8889']
      - targets: ['opentelemetry-collector:8888']

 

Y finalmente el de grafana donde indicamos Prometheus como una fuente de datos y donde está ubicada: 

datasources:
  - name: 'prometheus'
    type: 'prometheus'
    access: 'proxy'
    url: 'http://prometheus:9090'
  • Nota: el usuario y la contraseña para conectarnos a grafana es admin:admin

 

Y ahora ya podemos hacer docker-compose up para ejecutar nuestra infraestructura --. 

 

5.2 - Implementar Opentelemetry en código C#

Lo primero que tenemos que hacer es añadir los siguientes paquetes:

  • OpenTelemetry.Exporter.OpenTelemetryProtocol
  • OpenTelemetry.Extensions.Hosting (prerelease)
  • OpenTelemetry.Instrumentation.AspNetCore (prerelease)

 

Si en vez del paquete Exporter.OpenTelemetryProtocol instalamos el paquete Exporter.Prometheus podemos enviar la información directamente a prometheus sin pasar por el collector. 

  • Nota: Si estás en el proyecto de Distribt, este paquete está añadido dentro del proyecto Distribt.Shared.Setup, lo que quiere decir que todas nuestras aplicaciones van a tener opentelemetry implementado por defecto.

 

Con estos paquetes podemos incluir tanto tracing, como métricas como logs.

 

5.2.1 - Añadir Tracing a una aplicación .NET con OpenTelemetry

Únicamente debemos utilizar el método AddOpenTelemetryTracing() y pasar en el builder la configuración necesaria.

public static void AddTracing(this IServiceCollection serviceCollection, IConfiguration configuration)
{
    serviceCollection.AddOpenTelemetryTracing(builder => builder
        .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(configuration["AppName"]))
        .AddAspNetCoreInstrumentation()
        .AddOtlpExporter(exporter =>
        {
            //TODO: call the discovery service to retrieve the correctUrl dinamically
            exporter.Endpoint = new Uri("http://localhost:4317");
        })
    );; 
}

Como puedes ver estamos mandando un nombre para el servicio, el cual lo vamos a tener configurado en los ficheros de appsettings.json de cada una de nuestras aplicaciones. 

 

5.2.2 - Añadir Metrics a una aplicación .NET con OpenTelemetry

Similar al caso anterior, debemos utilizar el método .AddOpenTelemetryMetrics():

public static void AddMetrics(this IServiceCollection serviceCollection, IConfiguration configuration)
{
    serviceCollection.AddOpenTelemetryMetrics(builder => builder
        // Configure the resource attribute `service.name` to MyServiceName
        .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("MyServiceName"))
        // Add metrics from the AspNetCore instrumentation library
        .AddAspNetCoreInstrumentation()
        .AddOtlpExporter(exporter =>
        {
            //TODO: call the discovery service to retrieve the correctUrl dinamically
            exporter.Endpoint = new Uri("http://localhost:4317");
        }));
}

 

5.2.3 -  Añadir Logs a una aplicación .NET con OpenTelemetry

Similar al caso anterior, debemos utilizar el método .ConfigureLogging():

public static void AddLogging(this IHostBuilder builder, IConfiguration configuration)
{
    builder.ConfigureLogging(logging => logging
            //Next line optional to remove other providers
            .ClearProviders()
            .AddOpenTelemetry(options =>
            {
                options.IncludeFormattedMessage = true;
                options.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(configuration["AppName"]));
                options.AddConsoleExporter();
            }));
}

En el caso de la librería de Distribt este es más opcional ya que vimos como configurar la aplicación para utilizar graylog.

 

Y ya está, si ejecutamos las aplicaciones podemos ver el resultado. Las imágenes que has visto en este post son sacadas del propio resultado. 

 

 

6 - Añadir observabilidad a otras partes de nuestra infraestructura

Podemos añadir observabilidad a muchas partes de la infraestructura, o incluso a todas, si utilizamos servicios en la nube estos ya vienen preparados para tener observabilidad, traces, etc, out of the box, osea que no hay que configurar nada, simplemente vienen disponibles por defecto. 

 

6.1 - Conectar RabbitMQ con PromeTheus y Grafana

En otro post sobre el curso de sistemas distribuidos, vimos que es un service bus, en concreto RabbitMQ, ahora vamos a ver como añadir informacion a Prometheus/Grafana.

 

Lo primero que tenemos que hacer es, en nuestra infraestructura, modificar el servicio dentro del fichero docker-compose para indicar que pasaremos un fichero llamado enabled_plugins a través de los volumenes:

rabbitmq:
  image: rabbitmq:3.8.34-management-alpine #management version needed to be able to have a User interface
  container_name: rabbitmq
  ports:
      - 5672:5672
      - 15672:15672
  volumes: 
      - ./tools/rabbitmq/rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
      - ./tools/rabbitmq/definitions.json:/etc/rabbitmq/definitions.json
      - ./tools/rabbitmq/enabled_plugins:/etc/rabbitmq/enabled_plugins

Este fichero contiene una lista con los plugins que vamos a activar en RabbitMQ, en este caso, el que nos interesa es rabbitmq_prometheus pero yo ento habilitado alguno mas.

[rabbitmq_prometheus, rabbitmq_amqp1_0, rabbitmq_management, rabbitmq_web_dispatch, rabbitmq_management_agent, rabbitmq_stomp].

 

Y finalmente modificar nuestro fichero de prometheus.yaml para añadir el nuevo target para recoger la información.

scrape_configs:
  - job_name: 'collect-metrics'
    scrape_interval: 10s
    static_configs:
      - targets: ['opentelemetry-collector:8889']
      - targets: ['opentelemetry-collector:8888']
      - targets: [ 'rabbitmq:15692' ]

 

Y ahora podemos ejecutar docker-compose up -d.

 

Una vez lo tenemos corriendo, tenemos que hacer algún paso manual, recuerda, esto lo harás en producción una única vez

 

Debemos importar el dashboard de la página oficial de Grafana. Esto se debe a que los propios de Grafana tienen una gran comunidad que comparten información. 

importar dashboard grafana

 

Cuando lo importes, estate seguro de que has cambiado el datasource a Prometheus, ya que es el que tiene dicha información disponible.

importar rabbitmq en grafana a través de prometheus

 

Y este es el resultado final, como podemos ver en la esquina superior nos sale el número de colas que tenemos disponibles en RabbitMQ.

rabbitmq grafana

 

Y si ejecutamos las propias aplicaciones y generamos unos cuantos eventos, podemos ver como el resto de gráficas también cambian:

rabbitmq grafana ejemplo

 

 

Conclusión

En este post hemos visto que es opentelemetry y como entra dentro de la observabilidad.

Cómo utilizar OpenTelemetry con .NET y Prometheus.

Cómo utilizar Prometheus con Grafana.

Cómo utilizar Prometheus con Zipkin.

Cómo añadir observabilidad a otras partes de nuestra infraestructura.

 


Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2024 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café