Tecnología

eBPF para profiling continuo: Parca y Beyla

eBPF para profiling continuo: Parca y Beyla

Actualizado: 2026-05-03

El profiling continuo basado en eBPF transforma la forma en que se investigan los problemas de rendimiento: en lugar de instrumentar manualmente cada aplicación o recurrir a pprof en el momento del incidente, un agente cargado en el kernel Linux genera flame graphs de CPU para todos los procesos del nodo constantemente, con un overhead real de menos del 1 %. El stack moderno en 2024 combina tres herramientas con roles complementarios: Parca[1] para profiling de CPU a nivel de clúster, Grafana Beyla[2] para auto-instrumentación de HTTP/gRPC sin cambios en el código, y Grafana Pyroscope[3] para profiling profundo por lenguaje.

Puntos clave

  • Parca despliega un DaemonSet que genera perfiles de CPU para todos los procesos del nodo via eBPF, sin tocar las aplicaciones.
  • Beyla instrumenta automáticamente peticiones HTTP y gRPC en el kernel, generando métricas RED y trazas OpenTelemetry sin SDK.
  • Pyroscope complementa con profiling a nivel de lenguaje más detallado para servicios críticos específicos.
  • El overhead combinado del stack completo es del 1-2 % de CPU y 1-3 GB de RAM por nodo.
  • La correlación entre perfiles de Parca y trazas de Tempo en Grafana permite pasar de “esta traza tardó 800 ms” a “en este intervalo, el 60 % de la CPU fue al GC”.

El problema que resuelve el profiling continuo

El modo tradicional de profiling ad-hoc tiene dos problemas estructurales. El primero es que el problema ya no está cuando llegas: la mayoría de regresiones de rendimiento son intermitentes o se manifiestan solo bajo carga específica. Un pico de latencia a las 3 de la mañana que no se reproduce en el momento del análisis genera tickets sin resolución.

El segundo es que la instrumentación manual tiene coste de fricción alto: añadir pprof a un servicio Go, configurar py-spy para Python o instalar agentes JVM requiere tiempo de ingeniería, aprobaciones de cambio y en algunos casos reinicio del servicio.

eBPF resuelve ambos problemas: el agente siempre está activo, capturando datos antes, durante y después del incidente, y no requiere modificar las aplicaciones. El flamegraph del momento exacto del incidente existe siempre, porque el profiling nunca paró.

Parca: CPU profiling cluster-wide

Parca[1] instala dos componentes en Kubernetes:

  • Parca Agent (DaemonSet): un proceso por nodo que usa eBPF para capturar call stacks de todos los procesos con una frecuencia configurable (por defecto, 19 Hz).
  • Parca Server: almacena los perfiles, los indexa por servicio y permite queries en tiempo real y comparativas históricas.
helm install parca parca/parca --namespace monitoring
helm install parca-agent parca/parca-agent 
  --namespace monitoring 
  --set "config.relabelings[0].sourceLabels[0]=__meta_kubernetes_pod_label_app" 
  --set "config.relabelings[0].targetLabel=service_name"

Lo que hace Parca diferente de los perfiladores tradicionales es el stack unwinding sin frame pointer. Para lenguajes compilados como Go, Rust y C++, Parca usa DWARF debug info para reconstruir la pila de llamadas completa aunque el compilador haya eliminado los frame pointers por optimización. Para lenguajes interpretados como Python y Node.js, Parca puede capturar frames del intérprete.

La interfaz de Parca permite:

  • Flame graphs interactivos por servicio, pod o nodo.
  • Comparativas entre dos intervalos de tiempo (“¿qué cambió entre ayer y hoy?”).
  • Queries de PromQL sobre los perfiles para alertas basadas en rendimiento.

Beyla: auto-instrumentación HTTP y gRPC

Grafana Beyla[2] opera en una capa diferente a Parca. Donde Parca captura el tiempo de CPU, Beyla intercepta las llamadas al sistema de red en el kernel para generar:

  • Métricas RED (Rate, Errors, Duration) para cada servicio HTTP/gRPC automáticamente.
  • Trazas OpenTelemetry que se pueden enviar directamente a Grafana Tempo o a cualquier backend OTLP.
  • Service graphs que muestran las dependencias entre servicios basándose en el tráfico real observado.

La ventaja es que esto funciona sin modificar el código de las aplicaciones, sin añadir SDKs, sin reiniciar servicios:

helm install beyla grafana/beyla 
  --set env.BEYLA_AUTO_INSTRUMENT_TARGET="*" 
  --set env.OTEL_EXPORTER_OTLP_ENDPOINT="http://tempo:4317"

Beyla usa uprobes y kprobes de eBPF para interceptar las llamadas TLS y las llamadas al sistema relacionadas con sockets. Para Go, puede incluso detectar cuándo se usa net/http directamente sin TLS y extraer las cabeceras HTTP del buffer de memoria del proceso antes de que se cifren.

Comparado con OpenTelemetry con SDK manual: Beyla cubre el 80 % del valor con el 0 % del overhead de instrumentación. Los casos donde el SDK manual sigue siendo necesario son la propagación de contexto de traza a través de sistemas de mensajería y el enriquecimiento de spans con metadatos de negocio específicos.

Pyroscope: profiling profundo por lenguaje

Grafana Pyroscope[3] (originalmente independiente, ahora parte de Grafana Labs) es la capa de profiling más detallada del stack. Donde Parca usa eBPF para el nivel de sistema operativo, Pyroscope tiene agentes nativos por lenguaje que pueden capturar información más específica:

  • Para Go: goroutine counts, heap allocations, mutex contention —no solo CPU time.
  • Para Python: line-level profiling, memory allocations, coroutines.
  • Para JVM: JIT compilation overhead, GC pause detail, object allocation by type.
  • Para Rust: profiling con perf annotations o via Parca/eBPF.

El patrón de uso típico es Parca para cobertura amplia y Pyroscope con agente nativo solo en los servicios más críticos o más difíciles de depurar:

# Pyroscope en Python: agente de lenguaje para mayor detalle
import pyroscope

pyroscope.configure(
    application_name="mi-servicio-python",
    server_address="http://pyroscope:4040",
    sample_rate=100,
    detect_subprocesses=False,
    oncpu=True,
    gil_only=False,
    enable_logging=True,
)

Grafana: correlación entre perfiles, trazas y métricas

La integración del stack completo en Grafana es donde el valor compuesto emerge. Con Grafana Tempo para trazas, Prometheus para métricas y Parca/Pyroscope para perfiles, Grafana permite:

  1. Identificar una traza lenta en Tempo.
  2. Hacer clic en el intervalo de tiempo de esa traza.
  3. Ver el flame graph de Parca correspondiente a ese intervalo exacto.
  4. Identificar qué función específica consumió más CPU durante esa traza.

Este flujo —de “la request tardó 800 ms” a “el 60 % de ese tiempo fue en esta función de serialización”— es imposible sin la correlación temporal entre perfiles y trazas. Es la versión moderna de lo que perf + trace hacía de forma manual y costosa.

Diagrama del ciclo de vida de un programa eBPF: carga en el kernel, verificación de seguridad por el verifier y compilación JIT, que es la base técnica sobre la que Parca y Beyla capturan perfiles y trazas sin instrumentar aplicaciones

Overhead real del stack

Una preocupación razonable es el overhead de tener profiling continuo siempre activo. Los números reales observados en producción:

  • Parca Agent: 0,5-1 % de CPU por nodo. ~200 MB de RAM por agente.
  • Beyla: 0,3-0,8 % de CPU para servicios con tráfico medio.
  • Parca Server: depende del número de nodos y la retención; típicamente 1-2 GB de RAM + almacenamiento en disco.

El overhead total de 1-2 % de CPU y 1-3 GB de RAM por nodo es aceptable para la mayoría de clusters de producción donde los nodos tienen 16-32 GB de RAM. Para nodos con restricciones severas de recursos —edge computing industrial, por ejemplo— el overhead puede ser relevante y debe evaluarse caso a caso.

La observabilidad de aplicaciones LLM añade una dimensión particular: el overhead de vLLM en GPU es visible en los perfiles de CPU de Parca cuando hay cuellos de botella en la CPU host (serialización, preprocessing), lo que complementa las métricas nativas de GPU de vLLM.

Compatibilidad y requisitos

Los requisitos del stack:

  • Kernel Linux 5.8+ para todas las funcionalidades de eBPF necesarias. Kernels 5.15+ recomendados.
  • BTF (BPF Type Format) habilitado en el kernel: disponible por defecto en distribuciones modernas (Ubuntu 20.04+, RHEL 8+, Alpine 3.14+).
  • Kubernetes 1.24+ para la versión más reciente de Parca y Beyla.

Para distribuciones con kernels más antiguos —común en entornos enterprise con RHEL 7 o CentOS 7— el stack eBPF no está disponible. En esos entornos, la alternativa es Pyroscope con agentes nativos de lenguaje sin el componente eBPF.

Conclusión

El profiling continuo basado en eBPF elimina la fricción operativa más frustrante de la observabilidad de rendimiento: la imposibilidad de perfilar lo que ya ocurrió. Parca + Beyla + Pyroscope, integrados en Grafana, proporcionan cobertura completa de CPU, trazas y perfiles a nivel de lenguaje con un overhead aceptable y sin modificar las aplicaciones. El resultado es que los problemas de rendimiento dejan de ser investigaciones forenses con evidencia incompleta y pasan a ser análisis con datos temporalmente exactos de lo que ocurrió.

¿Te ha resultado útil?
[Total: 15 · Media: 4.3]
  1. Parca
  2. Grafana Beyla
  3. Grafana Pyroscope

Escrito por

CEO - Jacar Systems

Apasionado de la tecnología, la infraestructura cloud y la inteligencia artificial. Escribe sobre DevOps, IA, plataformas y software desde Madrid.