# Observabilidad ## una base para aplicaciones resilientes
**Lucas Di Cunzolo** Director: Miguel Angel Luengo · Codirector: Christian Adrian Rodriguez Asesor profesional: Leandro Di Tommaso
_Licenciatura en Informática — UNLP, Facultad de Informática_ _Abril 2026_ ## Estructura de la presentación 1. **Contexto** — Estado del arte en la industria 2. **Conceptos básicos** — métricas, logs y trazas 3. **OpenTelemetry** — el estándar unificador 4. **Stack LGTM** — Loki, Grafana, Tempo, Mimir 5. **Instrumentación** — WordPress, Redmine y Wagtail 6. **Despliegue en Kubernetes** — KEDA y escalado automático 7. **Conclusiones** ## 1. Contexto El desarrollo de aplicaciones web ha experimentado cambios disruptivos en los últimos años: - Las **metodologías ágiles** aceleraron los ciclos de entrega - Surgió **DevOps** como respuesta a la necesidad de alinear desarrollo y operaciones - La infraestructura evolucionó hacia modelos **cloud-native** y contenedores - Surgieron varios productos (_vendors_) que ofrecían visibilidad usando diversos tipos de datos - Kubernetes estandarizó la gestión de infraestructuras complejas Notes: - 2001: Manifiesto por el Desarrollo Ágil de Software - 2009: DevOps ### La complejidad crece Con arquitecturas distribuidas y microservicios: - Múltiples servicios heterogéneos conviven en el mismo ecosistema - Cada componente puede escalar de forma independiente - Los contenedores son **efímeros**: visualizar logs ya no es trivial - Un incidente puede originarse en cualquier punto de la cadena > _Cuando algo falla en producción, ¿sabemos dónde mirar?_ ### Evolución histórica
--- config: theme: 'forest' themeVariables: primaryColor: '#dfa1a1' secondaryColor: '#a5bee9' tertiaryColor: '#50c9a5' primaryTextColor: '#000000' --- timeline 2012 : SoundCloud ➜ Prometheus : Twitter ➜ Zipkin
─────────
Primer OSS de trazas 2014 : Google ➜ Kubernetes
───────
Primer release pública 2015 : Uber ➜ Jaeger
─────────
Escalabilidad + UI : CNCF ➜ Kubernetes
────────────
Primer proyecto incubado de la CNCF 2016 : CNCF ➜ Prometheus
────────
Segundo proyecto incubado de la CNCF 2018 : CNCF ➜ Prometheus
────────
Proyecto graduado de la CNCF 2019 : OpenTracing + OpenCensus ➜ OpenTelemetry : Grafana ➜ Loki 2020 : Prometheus ➜ OpenMetrics 1.0 : Grafana ➜ Tempo 2022 : Grafana ➜ Mimir 2023 : Grafana adopta OTLP
Notes: - CNCF fundadores: Google, CoreOS, Red Hat, Twitter, Huawei, Intel, Cisco, IBM, Docker, VMware - En marzo salió el primer RC de OpenMetrics 2.0 ## Problemas - Los sistemas modernos exigen **99,9% de disponibilidad** - Los servicios se degradan ante picos de demanda imprevistos - Sin visibilidad interna, diagnosticar un incidente puede llevar horas
#### ¿Cómo comprender el comportamiento de un sistema en su ambiente productivo, independientemente de la tecnología? Notes: - SLO - Que hacer ante eventos demandantes (hotsale, blackfriday), evitar escalado manual ## Objetivo Identificar los mecanismos necesarios para **comprender y reconocer el desempeño** de los sistemas en producción, de forma agnóstica a la tecnología.
Con el fin de poder: - Anticipar potenciales problemas - Determinar bajo qué condiciones escalar un servicio - Reducir el tiempo de diagnóstico ante incidentes - Automatizar la resiliencia mediante telemetría Notes: - MTTR ## Resiliencia Una aplicación es **resiliente** si puede adaptarse ante eventos nuevos sin degradar la calidad del servicio.
Estrategias estudiadas: | Estrategia | Descripción | |---|---| | Arquitecturas distribuidas | Alta disponibilidad mediante múltiples zonas | | Auto-sanado _(self-healing)_ | Health checks + reinicio automático ante fallos | | **Escalado adaptativo** | Escalar horizontal o verticalmente según indicadores |
> _Esta tesina se enfoca en la **adaptabilidad de servicio** como estrategia de resiliencia._ Notes: - Con plataformas como K8S e integraciones con Nubes, las arquitecturas distribuidas se simplifican ## 2. Conceptos básicos > _"Capacidad de determinar el estado interno de un sistema a partir de sus > salidas externas en un tiempo finito" ── Rudolf Emil Kálmán_ Notes: - Proveniente de la teoría del control - Propio de la ingeniería y matemática aplicada - Relacionado con sistemas dinámicos ### Las tres señales
| Señal | Volumen | Característica | |---|---|---| | Métricas | Menor | Agrupables, ideales para alertas y escalado | | Logs | Mayor | Eventos discretos en un instante de tiempo, detalle de operaciones | | Trazas | Mayor | Eventos distribuidos, visibilidad end-to-end |
> _Fuente: CNCF TAG Observability Whitepaper_ ## Métricas Valores numéricos que representan el estado de un recurso en un instante de tiempo. Compuestas por: **nombre** · **timestamp** · **valor** · **labels**
Conjuntos de métricas estándar: | Método | Siglas | Aplica a | |---|---|---| | **USE** | Utilización · Saturación · Errores | Recursos (CPU, memoria, red) | | **RED** | Rate · Errors · Duration | Servicios web | | **Golden Signals** | Latencia · Tráfico · Errores · Saturación | Sistemas distribuidos (Google SRE) | ## Logs Describen **eventos discretos** que ocurren en un instante de tiempo. Características clave: - Representados por timestamp + mensaje (texto plano o estructurado) - Deben escribirse a **stdout/stderr** (factor 11 de Twelve-Factor App) - Formato estructurado (JSON, Logfmt) facilita el procesamiento centralizado
Formatos comunes: **CLF** (Nginx/Apache) · **Logfmt** · **Syslog** (RFC 3164 / RFC 5424) ## Trazas Describen el **flujo completo de un requerimiento** desde que ingresa al sistema hasta que retorna al usuario. Unidad mínima: el **Span** — representa una operación con duración medible
gantt dateFormat x axisFormat %Lms section GET /api/posts [52ms] GET /api/posts :0, 52 wpdb.query SELECT :5, 15 wpdb.query SELECT :15, 20 wpdb.connect :20, 29
### Correlación de señales Las tres señales pueden relacionarse entre sí mediante metadatos compartidos: | Mecanismo | Descripción | |---|---| | **Ventana temporal** | Filtrar las tres señales por el mismo instante | | **Request / Trace ID** | Navegar de logs a la traza exacta del requerimiento | | **Exemplars** | Enlace directo desde una métrica a la traza que la generó |
> _La correlación transforma datos aislados en información accionable_ ### Correlación de señales - Ejemplo práctico
> Fuente: CNCF TAG Observability Whitepaper ## 3. OpenTelemetry **El estándar unificador de telemetría en entornos cloud-native**
Proyecto de la **CNCF** (Cloud Native Computing Foundation), fusión de OpenTracing y OpenCensus en 2019. Unifica las tres señales bajo un único protocolo: **OTLP** _(OpenTelemetry Protocol)_ > _Antes de OTel: un vendor diferente por cada señal, vendor lock-in en cada capa_ Notes: - Sin OTel, uno está a la merced de que datos expone - Multiplicidad de vendor para conseguir la imagen completa ## Componentes de OpenTelemetry
| Componente | Rol | |---|---| | **API** | Interfaz para instrumentar código, agnóstica al backend | | **SDK** | Implementación de la API con pipelines de exportación | | **Auto-instrumentación** | Intercepta frameworks sin modificar el código fuente | | **OTel Collector** | Agente intermediario: recibe, procesa y exporta señales | | **OTLP** | Protocolo de transporte unificado (gRPC / HTTP) | ### OTel Collector Desacopla la generación de telemetría del almacenamiento:
flowchart LR A[Aplicaciones] -->|OTLP| R[Receiver] subgraph Outer[
Collector] R --> P[Processor
batch · atributos · filtros] P --> E[Exporter] end E --> M[(Mimir
métricas)] E --> L[(Loki
logs)] E --> T[(Tempo
trazas)]
Ventajas: - Cambiar el backend **sin tocar las aplicaciones** - El collector puede escalar horizontalmente - Buffer local ante indisponibilidad de las bases de datos - Conector `spanmetrics` ➜ deriva métricas RED directamente desde trazas ## Instrumentación automática vs manual
**Automática** _(zero-code instrumentation)_ - Intercepta frameworks mediante hooks, monkey-patching o metaprogramación - No requiere modificar el código fuente - Soporte varía según el lenguaje y framework
**Manual** - Instala el SDK e incorpora llamadas explícitas para crear spans - Mayor control y granularidad - Necesaria cuando no hay auto-instrumentador disponible
> _En esta tesina: automática en PHP y Python · manual en Ruby_ Notes: - Los casos de Java y .NET son similares, siendo los más maduros ## 4. Stack LGTM Arquitectura de observabilidad open-source propuesta por **GrafanaLabs**
| Componente | Señal | Rol | |---|---|---| | **L**oki | Logs | Almacenamiento indexado por etiquetas | | **G**rafana | — | Visualización y correlación unificada | | **T**empo | Trazas | Almacenamiento eficiente multi-formato | | **M**imir | Métricas | Almacenamiento compatible con API de Prometheus |
El **OTel Collector** actúa como intermediario central mediante OTLP ## Grafana Mimir Almacenamiento de métricas de **alta cardinalidad** y retención configurable - Compatible con la API de Prometheus (PromQL) - Acepta protocolo OTLP desde noviembre 2023 - Escala horizontalmente para grandes volúmenes
Usado en esta tesina como fuente de métricas para el escalado horizontal: ```promql sum(rate(traces_spanmetrics_calls_total{service_name="
", span_name="/"}[1m])) ``` ## Grafana Loki Almacenamiento de logs liviano: indexa **solo etiquetas**, no el contenido
Comparación con Elasticsearch (ELK): | | Loki | Elasticsearch | |---|---|---| | Indexado | Solo labels | Contenido completo | | Costo almacenamiento | Bajo | Alto | | Integración Grafana | Nativa | Plugin | | Consulta | LogQL | KQL / Lucene | ## Grafana Tempo Almacenamiento de trazas con integración nativa en Grafana - Admite formatos: **OTLP · Jaeger · Zipkin** - Navegación directa desde métricas y logs hacia trazas específicas - Sampling configurable: head-based, tail-based, probabilístico ## Arquitectura completa
flowchart LR WP["WordPress
PHP / OTLP HTTP :4318"] RM["Redmine
Ruby / OTLP HTTP :4318 & Fluentd :8006"] WG["Wagtail
Python / OTLP gRPC :4317"] OC["OTel Collector"] MM[("Mimir")] LK[("Loki")] TP[("Tempo")] GF["Grafana"] WP --> OC RM --> OC WG --> OC OC --> MM & LK & TP MM & LK & TP --> GF
El conector `spanmetrics` genera métricas RED a partir de trazas, **sin instrumentación adicional** Alternativamente, se puede utilizar la componente `Metrics-generator` de `Tempo` ## 5. Instrumentación Tres aplicaciones desarrolladas en lenguajes y frameworks diferentes
| Aplicación | Lenguaje | Framework | Año | Instrumentación | |---|---|---|---|---| | **WordPress** | PHP | — | 2003 | Automática | | **Redmine** | Ruby | Rails | 2006 | Manual | | **Wagtail** | Python | Django | 2014 | Automática |
> _Ninguna fue diseñada teniendo en cuenta los 12 factores ni la observabilidad_ ## WordPress — PHP Instrumentación automática sin tocar el código fuente de WordPress **Dependencias:** 1. Extensiónes nativa PHP: `opentelemetry` · `protobuf` 2. Paquetes Composer: `opentelemetry-auto-wordpress` + SDK + exporter OTLP **Activación transparente:** ```ini ; otel.php.ini auto_prepend_file = ${OTEL_AUTOLOAD_PATH} ``` El intérprete ejecuta el autoload antes de cualquier script de WordPress, inicializando el SDK de forma completamente transparente. ## Wagtail — Python Instrumentación con **cero modificaciones** al código fuente ```bash # Durante la construcción de la imagen opentelemetry-bootstrap -a install # Entrypoint del contenedor CMD ["opentelemetry-instrument", "uwsgi", "/app/etc/uwsgi.ini"] ``` El wrapper `opentelemetry-instrument` intercepta el proceso antes de que la aplicación comience a procesar peticiones. ## Redmine — Ruby Instrumentación **manual** por falta de auto-instrumentador oficial en Ruby **Inicializador** `config/initializers/otel.rb`: ```ruby if ENV['OTEL_EXPORTER_OTLP_ENDPOINT'].present? require 'opentelemetry/sdk' require 'opentelemetry/exporter/otlp' require 'opentelemetry/instrumentation/all' OpenTelemetry::SDK.configure do |c| c.use_all() c.logger = Rails.logger end end ``` La librería `opentelemetry-instrumentation-all` instrumenta ActiveRecord, Action Pack, Net::HTTP y Redis mediante **monkey-patching**. ### Redmine — Fluentd para logs El SDK de Ruby **no soportaba exportar logs vía OTLP** al momento de implementar. El formatter incluye `trace_id` y `span_id` en cada línea de log: ```ruby [3|10|11] if ENV['FLUENTD_URL'] uri = URI.parse ENV['FLUENTD_URL'] config.logger = LevelFluentLogger.new(nil, host: uri.host, port: uri.port, use_nonblock: true, wait_writeable: false) config.logger.formatter = proc do |severity, datetime, progname, message| map = { level: severity } map[:message] = message if message map[:progname] = progname if progname map[:service] = uri.path[1..-1] if uri.path[1..-1] if ENV['OTEL_EXPORTER_OTLP_ENDPOINT'].present? map[:span_id] = OpenTelemetry::Trace.current_span.context.hex_span_id map[:trace_id] = OpenTelemetry::Trace.current_span.context.hex_trace_id end map end stdout_logger = ActiveSupport::Logger.new(STDOUT) config.logger.extend(ActiveSupport::Logger.broadcast(stdout_logger)) end ``` Esto preserva la **correlación entre logs y trazas** en Grafana. ## Contenerización Cada aplicación sigue el patrón de **imagen dual** (multi-stage build):
flowchart TD CF["Containerfile
multi-stage"] APP["stage: app
aplicación instrumentada"] NGX["stage: nginx
proxy reverso + archivos estáticos"] CF --> APP CF --> NGX
Toda la configuración se inyecta por **variables de entorno** (factor 3 de Twelve-Factor App): ```bash OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318 OTEL_SERVICE_NAME=wordpress OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production ``` ## 6. Despliegue en Kubernetes Objetivo: demostrar el **escalado automático impulsado por telemetría** en un entorno equivalente al productivo ## Escalado automático con KEDA **KEDA** (Kubernetes Event-Driven Autoscaling) escala Deployments en respuesta a métricas externas al clúster. ```yaml triggers: - type: prometheus metadata: serverAddress: http://lgtm-distributed-mimir-nginx.observability.svc/prometheus metricName: wagtail_request_rate threshold: "5" query: > sum(rate( traces_spanmetrics_calls_total{service_name="wagtail", span_name="/"}[1m] )) ``` Escala entre **1 y 3 réplicas** cuando supera **5 req/s por réplica** ### La métrica `traces_spanmetrics_calls_total` Generada automáticamente por el conector `spanmetrics` del OTel Collector **a partir de las trazas**, sin instrumentación adicional.
flowchart TD A["Trazas de la app"] --> B["OTel Collector
spanmetrics connector"] B --> C["traces_spanmetrics_calls_total"] C --> D[("Mimir")] E["KEDA"] --> D
> _La misma telemetría que se consulta en Grafana alimenta la lógica de escalado_ ## Prueba de carga con Locust Ingresar al sitio
Locust
Luego, visualizar los datos en
Grafana
### El ciclo observable en Grafana 1. **Tasa de peticiones en ascenso** → panel RED muestra el incremento en req/s 2. **KEDA evalúa el umbral** → consulta Mimir cada pocos segundos 3. **Scale-up** → nuevos pods pasan por `Pending → ContainerCreating → Running` 4. **Latencia se estabiliza** → el balanceador distribuye el tráfico entre réplicas 5. **Scale-down** → tras el `cooldownPeriod`, KEDA reduce a una réplica
> _Este ciclo cierra el argumento central: la observabilidad no solo describe > el sistema, sino que puede **actuar sobre él** de forma autónoma_ ## 7. Conclusiones ### Objetivo cumplido Se instrumentaron tres aplicaciones en lenguajes distintos **sin modificar su código fuente**, centralizando la telemetría en un stack open-source unificado. Las pruebas fueron desplegadas en 2 entornos: - **Docker Compose** — desarrollo local e inspección de trazas - **Kubernetes (Kind)** — escalado automático impulsado por telemetría ## Sobre las señales de la observabilidad Las tres señales son **complementarias**, no redundantes: | Señal | Valor | |---|---| | **Métricas** | Estado general del sistema · insumo para alertas y escalado | | **Logs** | Detalle de eventos en la aplicación | | **Trazas** | Flujo completo de un requerimiento entre todos los componentes |
El valor emergente aparece al **correlacionarlas**: navegar de una alerta en métricas hasta la traza del requerimiento afectado y sus logs exactos reduce significativamente el **MTTR** _(Mean Time To Resolution)_. ## Sobre OpenTelemetry Resuelve la fragmentación histórica de herramientas propietarias: - Protocolo de transporte unificado **OTLP** para las tres señales - SDKs para los principales lenguajes de programación - Auto-instrumentación que elimina la necesidad de modificar el código - El **OTel Collector** desacopla la recolección del almacenamiento
Su adopción por **GrafanaLabs, New Relic y Datadog** confirma que OTLP se proyecta como la interfaz universal de la telemetría en la industria. ## Sobre la observabilidad y la resiliencia > _La adaptación automática solo es posible si el sistema > tiene visibilidad sobre su propio estado._
En la PoC, KEDA escala cada Deployment en función de `traces_spanmetrics_calls_total`, derivada de las trazas: - Sin cambios adicionales en la instrumentación - La misma telemetría que diagnostica un problema **lo resuelve** - Demuestra que la observabilidad es una **base para la resiliencia** ## Trabajos futuros - **Rollbacks automatizados** impulsados por telemetría post-despliegue - **Service mesh** (Istio / Linkerd) para trazas y métricas a nivel de red - **Profiling** como cuarta señal (en desarrollo activo en OTel) - Extensión a arquitecturas **multi-cluster** y entornos cloud ## Gracias
**Lucas Di Cunzolo** Director: Miguel Angel Luengo Codirector: Christian Adrian Rodriguez Asesor profesional: Leandro Di Tommaso
_Licenciatura en Informática — UNLP, Facultad de Informática_ _Abril 2026_