Skip to content

Monitoreando Microservicios con Grafana

En este tutorial, aprenderemos cómo monitorear los microservicios de CodeDesignPlus utilizando Grafana. Explicaremos el flujo de métricas desde los microservicios, a través de OpenTelemetry y Prometheus, hasta la visualización en Grafana. Esto nos permitirá observar el rendimiento y la salud de nuestros microservicios en tiempo real.

¿Por qué Monitorear Microservicios con Grafana?

El monitoreo es esencial para mantener la salud, el rendimiento y la estabilidad de los microservicios. Grafana, con su capacidad de crear dashboards y visualizar datos de diferentes fuentes, es una herramienta poderosa para analizar las métricas de nuestros microservicios. El monitoreo nos permite:

  • Observar el rendimiento: Analizar métricas como el tiempo de respuesta, el uso de CPU y memoria, y el número de solicitudes por minuto.
  • Detectar problemas: Identificar cuellos de botella, errores y anomalías en el comportamiento de los microservicios.
  • Optimizar el uso de recursos: Ajustar la configuración y los recursos de los microservicios para mejorar su eficiencia.
  • Recibir alertas: Configurar alertas que nos avisen cuando se detecten problemas.

¿Qué Aprenderás?

  1. Cómo los microservicios exportan métricas a OpenTelemetry.
  2. Cómo Prometheus obtiene las métricas de OpenTelemetry.
  3. Cómo visualizar las métricas de los microservicios en Grafana.
  4. Cómo explorar y personalizar los dashboards predefinidos.
  5. Cómo agregar dashboards adicionales según la necesidad.

Arquitectura de Monitoreo de Métricas

El flujo de métricas en nuestro entorno de microservicios sigue la siguiente arquitectura:

  1. Microservicios: Los microservicios, construidos con el framework de CodeDesignPlus, generan métricas y las envían a través de OpenTelemetry (OTLP) al OpenTelemetry Collector.
  2. OpenTelemetry Collector: Recibe las métricas de los microservicios y las direcciona a Prometheus.
  3. Prometheus: Obtiene las métricas del OpenTelemetry Collector mediante scraping (es decir, consultando un endpoint) y las almacena en una base de datos de series temporales.
  4. Grafana: Consulta las métricas almacenadas en Prometheus y las visualiza en dashboards.
Entorno de Desarrollo

Configuración

El entorno de desarrollo de CodeDesignPlus ya incluye la configuración necesaria para el monitoreo de métricas. La librería CodeDesignPlus.Net.Observability se encarga de exportar las métricas de los microservicios a OpenTelemetry, que a su vez las envía a Prometheus.

using CodeDesignPlus.Net.Core.Abstractions.Options;
using CodeDesignPlus.Net.Core.Extensions;
using CodeDesignPlus.Net.Observability.Abstractions.Options;
using CodeDesignPlus.Net.Observability.Exceptions;
using Confluent.Kafka.Extensions.OpenTelemetry;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry;
using OpenTelemetry.Exporter;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace CodeDesignPlus.Net.Observability.Extensions;
/// <summary>
/// Provides extension methods for adding observability services to the service collection.
/// </summary>
public static class ServiceCollectionExtensions
{
/// <summary>
/// Adds observability services to the service collection.
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="configuration">The configuration.</param>
/// <param name="environment">The host environment.</param>
/// <param name="metricsBuilder">Optional metrics builder action.</param>
/// <param name="traceBuilder">Optional trace builder action.</param>
/// <returns>The OpenTelemetry builder.</returns>
/// <exception cref="ObservabilityException">Thrown when the observability section is missing in the configuration.</exception>
public static IOpenTelemetryBuilder AddObservability(this IServiceCollection services, IConfiguration configuration, IHostEnvironment environment, Action<MeterProviderBuilder> metricsBuilder = null, Action<TracerProviderBuilder> traceBuilder = null)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(configuration);
ArgumentNullException.ThrowIfNull(environment);
var observabilitySection = configuration.GetSection(ObservabilityOptions.Section);
if (!observabilitySection.Exists())
throw new ObservabilityException($"The section {ObservabilityOptions.Section} is required.");
var observabilityOptions = observabilitySection.Get<ObservabilityOptions>();
var coreOptions = configuration.GetSection(CoreOptions.Section).Get<CoreOptions>();
services
.AddOptions<ObservabilityOptions>()
.Bind(observabilitySection)
.ValidateDataAnnotations();
services.AddCore(configuration);
var otel = services.AddOpenTelemetry()
.ConfigureResource(resource =>
{
resource.AddService(serviceName: coreOptions.AppName, serviceVersion: coreOptions.Version);
});
otel.ConfigureMetrics(environment, observabilityOptions, metricsBuilder);
otel.ConfigureTracing(observabilityOptions, environment, traceBuilder);
return otel;
}
/// <summary>
/// Configures metrics for OpenTelemetry.
/// </summary>
/// <param name="otel">The OpenTelemetry builder.</param>
/// <param name="environment">The host environment.</param>
/// <param name="observabilityOptions">The observability options.</param>
/// <param name="builder">Optional metrics builder action.</param>
private static void ConfigureMetrics(this IOpenTelemetryBuilder otel, IHostEnvironment environment, ObservabilityOptions observabilityOptions, Action<MeterProviderBuilder> builder)
{
if (!observabilityOptions.Metrics.Enable)
return;
otel.WithMetrics(metricsBuilder =>
{
metricsBuilder.AddMetricsAspNetCoreInstrumentation(observabilityOptions.Metrics.AspNetCore);
metricsBuilder.AddOtlpExporter(x =>
{
x.Endpoint = observabilityOptions.ServerOtel;
x.Protocol = OtlpExportProtocol.Grpc;
});
if (environment.IsDevelopment())
metricsBuilder.AddConsoleExporter();
builder?.Invoke(metricsBuilder);
});
}
/// <summary>
/// Adds ASP.NET Core instrumentation for metrics.
/// </summary>
/// <param name="metricsBuilder">The metrics builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddMetricsAspNetCoreInstrumentation(this MeterProviderBuilder metricsBuilder, bool enable)
{
if (enable)
metricsBuilder.AddAspNetCoreInstrumentation();
}
/// <summary>
/// Configures tracing for OpenTelemetry.
/// </summary>
/// <param name="otel">The OpenTelemetry builder.</param>
/// <param name="observabilityOptions">The observability options.</param>
/// <param name="environment">The host environment.</param>
/// <param name="builder">Optional trace builder action.</param>
private static void ConfigureTracing(this IOpenTelemetryBuilder otel, ObservabilityOptions observabilityOptions, IHostEnvironment environment, Action<TracerProviderBuilder> builder)
{
if (!observabilityOptions.Trace.Enable)
return;
otel.WithTracing(tracing =>
{
tracing.AddTraceAspNetCoreInstrumentation(observabilityOptions.Trace.AspNetCore);
tracing.AddTraceGrpcClientInstrumentation(observabilityOptions.Trace.GrpcClient);
tracing.AddTraceSqlClientInstrumentation(observabilityOptions.Trace.SqlClient);
tracing.AddTraceCodeDesignPlusSdkInstrumentation(observabilityOptions.Trace.CodeDesignPlusSdk);
tracing.AddTraceRedisInstrumentation(observabilityOptions.Trace.Redis);
tracing.AddTraceKafkaInstrumentation(observabilityOptions.Trace.Kafka);
tracing.AddOtlpExporter(x =>
{
x.Endpoint = observabilityOptions.ServerOtel;
x.Protocol = OtlpExportProtocol.Grpc;
});
if (environment.IsDevelopment())
tracing.AddConsoleExporter();
builder?.Invoke(tracing);
});
}
/// <summary>
/// Adds ASP.NET Core instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceAspNetCoreInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
{
tracing.AddAspNetCoreInstrumentation(options =>
{
options.Filter = httpContext => httpContext.Request.Path.StartsWithSegments("/api");
});
tracing.AddHttpClientInstrumentation();
}
}
/// <summary>
/// Adds gRPC client instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceGrpcClientInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
{
tracing.AddGrpcClientInstrumentation();
tracing.AddHttpClientInstrumentation();
}
}
/// <summary>
/// Adds SQL client instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceSqlClientInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
tracing.AddSqlClientInstrumentation();
}
/// <summary>
/// Adds CodeDesignPlus SDK instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceCodeDesignPlusSdkInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
{
tracing.AddSource("CodeDesignPlus.Net.Mongo.Diagnostics");
tracing.AddSource("CodeDesignPlus.Net.PubSub");
}
}
/// <summary>
/// Adds Redis instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceRedisInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
tracing.AddRedisInstrumentation();
}
/// <summary>
/// Adds Kafka instrumentation for tracing.
/// </summary>
/// <param name="tracing">The tracing builder.</param>
/// <param name="enable">Indicates whether to enable the instrumentation.</param>
private static void AddTraceKafkaInstrumentation(this TracerProviderBuilder tracing, bool enable)
{
if (enable)
tracing.AddConfluentKafkaInstrumentation();
}
}

Pasos para la Visualización de Métricas en Grafana

  1. Asegúrate de que los Microservicios estén en Ejecución: Verifica que los microservicios, OpenTelemetry Collector, Loki y Grafana estén en ejecución. El microservicio puede ser ejecutado de forma local o en un contenedor Docker.

    Docker ps
  2. Accede a Grafana: Abre un navegador y ve a la URL http://localhost:3000 (o la dirección donde se está ejecutando Grafana).

    Grafana Home
  3. Explora los Dashboards: En la barra lateral de Grafana, haz clic en Dashboards (icono de cuatro cuadrados).

    Grafana Dashboards
  4. Visualiza los Dashboards: Observa los dashboards predefinidos, que proporcionan información detallada sobre los microservicios y la infraestructura:

    • ASP.NET Core: Muestra métricas generales de la aplicación ASP.NET Core.
    Grafana ASP.NET Core Dashboard
    • ASP.NET Core Endpoint: Ofrece métricas detalladas de cada endpoint de la API ASP.NET Core, como tiempo de respuesta y número de solicitudes.

      Grafana ASP.NET Core Endpoint Dashboard
    • OpenTelemetry Collector: Visualiza las métricas del OpenTelemetry Collector, como el número de receptores, procesadores y exportadores activos.

    Grafana OpenTelemetry Collector Dashboard
    • Loki Metrics Dashboard: Muestra métricas relacionadas con el funcionamiento interno de Loki.
    Grafana Loki Metrics Dashboard
  5. Analiza las Métricas: Utiliza los paneles de Grafana para analizar el comportamiento del microservicio. Verifica que las métricas sean consistentes con el rendimiento esperado y que no haya errores o anomalías.

  6. Agrega Dashboards Personalizados: Si necesitas métricas adicionales o personalizadas, puedes crear tus propios dashboards. Selecciona el botón Create y crea un nuevo panel.

    Grafana Create Dashboard
  7. Selecciona la fuente de datos de Prometheus y escribe las queries necesarias para visualizar las métricas de tus microservicios.

    Grafana Prometheus Query

Configuración Adicional de Dashboards

El entorno de desarrollo de CodeDesignPlus proporciona los siguientes dashboards de forma predeterminada:

  • ASP.NET Core: Métricas generales de la aplicación ASP.NET Core.
  • ASP.NET Core Endpoint: Métricas detalladas de cada endpoint de la API.
  • OpenTelemetry Collector: Métricas internas del OpenTelemetry Collector.
  • Loki Metrics Dashboard: Métricas internas de Loki.

Puedes agregar más dashboards según tus necesidades. Algunos dashboards populares que puedes añadir son:

  • Node Exporter Full: Muestra métricas del sistema operativo donde se están ejecutando los microservicios (CPU, memoria, disco, red).
  • Docker Engine: Muestra métricas del motor de Docker y el rendimiento de los contenedores.
  • RabbitMQ: Permite monitorear las métricas del broker de mensajes RabbitMQ

Puedes importar los dashboards a Grafana en la opción Import del panel lateral y pegar el id del dashboard que deseas.

Grafana Import Dashboard

Conclusiones

En este tutorial, hemos aprendido cómo monitorear los microservicios de CodeDesignPlus utilizando Grafana. Hemos comprendido el flujo de métricas desde los microservicios, a través de OpenTelemetry y Prometheus, hasta la visualización en Grafana. Ahora, puedes utilizar Grafana para monitorear la salud y el rendimiento de tus microservicios, detectar problemas, optimizar el uso de recursos y recibir alertas.

Esta configuración proporciona una base sólida para la observabilidad de tus microservicios y facilita la gestión de tu sistema.