Aprende los métodos prácticos de Brendan Gregg (USE, RED, flame graphs) para investigar latencia y cuellos de botella en producción con datos, no con conjeturas.

Brendan Gregg es una de las voces más influyentes en rendimiento de sistemas, especialmente en el mundo Linux. Ha escrito libros ampliamente usados, creado herramientas prácticas y—lo más importante—compartido métodos claros para investigar problemas reales en producción. Los equipos adoptan su enfoque porque funciona bajo presión: cuando la latencia sube y todos quieren respuestas, necesitas una manera de pasar de “quizá es X” a “es definitivamente Y” con el mínimo dramatismo.
Una metodología de rendimiento no es una única herramienta o un comando ingenioso. Es una forma repetible de investigar: una lista de verificación sobre qué mirar primero, cómo interpretar lo que ves y cómo decidir el siguiente paso.
Esa repetibilidad es lo que reduce las conjeturas. En lugar de depender de quien tenga más intuición (o la opinión más ruidosa), sigues un proceso consistente que:
Muchas investigaciones de latencia se torcen en los primeros cinco minutos. La gente salta directo a arreglos: “añadir CPU”, “reiniciar el servicio”, “aumentar la caché”, “afinar el GC”, “debe ser la red”. A veces esas acciones ayudan—a menudo enmascaran la señal, desperdician tiempo o introducen nuevos riesgos.
Los métodos de Gregg te empujan a retrasar las “soluciones” hasta que puedas responder preguntas más simples: ¿qué está saturado? ¿qué está fallando? ¿qué se hizo más lento—throughput, encolamiento o operaciones individuales?
Esta guía te ayuda a acotar el alcance, medir las señales correctas y confirmar el cuello de botella antes de optimizar. El objetivo es un flujo de trabajo estructurado para investigar latencia y problemas de perfilado en producción, de modo que los resultados no dependan de la suerte.
La latencia es un síntoma: los usuarios esperan más a que termine el trabajo. La causa suele estar en otro lugar—contención de CPU, esperas en disco o red, contención de locks, recolección de basura, encolamiento o retrasos en dependencias remotas. Medir solo la latencia te dice que existe dolor, no dónde se origina.
Estas tres señales están acopladas:
Antes de afinar, captura las tres en la misma ventana temporal. Si no, podrías “arreglar” la latencia dejando caer trabajo o fallando más rápido.
La latencia media oculta los picos que los usuarios recuerdan. Un servicio con 50 ms de promedio puede tener frecuentes bloqueos de 2 s.
Rastrea percentiles:
También vigila la forma de la curva de latencia: un p50 estable con un p99 en aumento a menudo indica paradas intermitentes (p. ej., contención de locks, problemas de I/O, pausas stop-the-world) más que una desaceleración general.
Un presupuesto de latencia es un modelo de contabilidad simple: “Si la solicitud debe terminar en 300 ms, ¿dónde puede gastarse ese tiempo?” Divídelo en cubos como:
Este presupuesto enmarca la primera tarea de medición: identifica qué cubo creció durante el pico y luego investiga esa área en lugar de afinar a ciegas.
El trabajo de latencia se descarrila cuando el “problema” se describe como el sistema está lento. Los métodos de Gregg empiezan antes: fuerza la cuestión a una pregunta específica y comprobable.
Escribe dos frases antes de tocar herramientas:
Esto evita que optimices la capa equivocada—por ejemplo, CPU del host—cuando el dolor está aislado a un endpoint o una dependencia downstream.
Escoge una ventana que coincida con la queja e incluye, si es posible, un periodo de comparación “bueno”.
Define explícitamente el alcance de tu investigación:
Ser preciso aquí hace que los pasos siguientes (USE, RED, perfilado) sean más rápidos porque sabrás qué datos deberían cambiar si tu hipótesis es correcta.
Anota despliegues, cambios de configuración, desplazamientos de tráfico y eventos de infra—pero no asumas causalidad. Escríbelos como “Si X, entonces esperaríamos Y”, para poder confirmar o rechazar rápidamente.
Un pequeño registro evita trabajo duplicado entre compañeros y facilita las transiciones.
Time | Question | Scope | Data checked | Result | Next step
Incluso cinco líneas como esta pueden convertir un incidente estresante en un proceso repetible.
El método USE (Utilization, Saturation, Errors) es la lista de verificación rápida de Gregg para escanear los “cuatro grandes” recursos—CPU, memoria, disco (almacenamiento) y red—para que dejes de adivinar y empieces a acotar el problema.
En lugar de mirar docenas de dashboards, hazte las mismas tres preguntas para cada recurso:
Aplicado consistentemente, esto se vuelve un inventario rápido de dónde existe “presión”.
Para CPU, la utilización es el % de CPU ocupado, la saturación se manifiesta como presión en la run-queue o hilos esperando para ejecutarse, y los errores pueden incluir throttling (en contenedores) o interrupciones mal comportadas.
Para memoria, la utilización es la memoria usada, la saturación aparece como paginación o recolecciones de basura frecuentes, y los errores incluyen fallos de asignación o eventos OOM.
Para disco, la utilización es el tiempo de busy del dispositivo, la saturación es la profundidad de cola y el tiempo de espera de lectura/escritura, y los errores son errores de I/O o timeouts.
Para red, la utilización es el throughput, la saturación son drops/colas/latencia y los errores son retransmisiones, resets o pérdida de paquetes.
Cuando los usuarios reportan lentitud, las señales de saturación suelen ser las más reveladoras: colas, tiempo de espera y contención tienden a correlacionar más directamente con la latencia que la simple utilización.
Las métricas de nivel de servicio (como latencia de petición y tasa de errores) te dicen el impacto. USE te dice dónde mirar a continuación identificando qué recurso está bajo tensión.
Un bucle práctico es:
El método RED te mantiene anclado a la experiencia del usuario antes de sumergirte en gráficas del host.
RED evita que persigas métricas “interesantes” del sistema que no afectan a los usuarios. Fuerza un bucle más cerrado: ¿qué endpoint está lento, para qué usuarios y desde cuándo? Si Duration sube solo en una ruta mientras la CPU global está estable, ya tienes un punto de partida más afilado.
Un hábito útil: mantener RED desglosado por servicio y endpoints principales (o métodos RPC clave). Eso facilita distinguir una degradación amplia de una regresión localizada.
RED te dice dónde duele. USE te ayuda a probar qué recurso es responsable.
Ejemplos:
Mantén el diseño enfocado:
Si quieres un flujo de incidentes consistente, empareja esta sección con el inventario USE en /blog/use-method-overview para que puedas moverte de “los usuarios lo sienten” a “este recurso es la restricción” con menos idas y venidas.
Una investigación de rendimiento puede explotar en docenas de gráficos e hipótesis en minutos. La mentalidad de Gregg es mantenerlo estrecho: tu trabajo no es "recoger más datos", sino hacer la siguiente pregunta que elimine la incertidumbre más rápido.
La mayoría de los problemas de latencia están dominados por un único costo (o una pequeña pareja): un lock caliente, una dependencia lenta, un disco sobrecargado, un patrón de pausas de GC. Priorizar significa cazar ese costo dominante primero, porque recortar 5% en cinco lugares raramente mueve la latencia visible por el usuario.
Una prueba práctica: “¿Qué podría explicar la mayor parte del cambio de latencia que vemos?” Si una hipótesis solo puede explicar una porción pequeña, es una pregunta de menor prioridad.
Usa top-down cuando respondes “¿Los usuarios están impactados?” Empieza por endpoints (señales estilo RED): latencia, throughput, errores. Esto ayuda a evitar optimizar algo que no está en la ruta crítica.
Usa bottom-up cuando el host está claramente enfermo (síntomas estilo USE): saturación de CPU, presión de memoria descontrolada, espera de I/O. Si un nodo está al tope, perderás tiempo mirando percentiles de endpoints sin entender la restricción.
Cuando suena una alerta, elige una rama y mantente en ella hasta confirmarla o falsarla:
Limítate a un pequeño conjunto inicial de señales, y profundiza solo cuando algo se mueva. Si necesitas una lista para mantener el foco, enlaza tus pasos a un runbook como /blog/performance-incident-workflow para que cada nueva métrica tenga un propósito: responder una pregunta específica.
El perfilado en producción puede parecer riesgoso porque toca el sistema en vivo—pero a menudo es la manera más rápida de reemplazar el debate por evidencia. Logs y dashboards pueden decirte qué es lento. El perfilado te dice dónde se va el tiempo: qué funciones consumen más, qué hilos esperan y qué rutas de código dominan durante el incidente.
El perfilado es una herramienta de “presupuesto de tiempo”. En lugar de debatir teorías (“es la base de datos” vs “es el GC”), obtienes evidencia como “45% de las muestras de CPU estaban en parsing JSON” o “la mayoría de las solicitudes están bloqueadas por un mutex”. Eso reduce el siguiente paso a una o dos correcciones concretas.
Cada uno responde a una pregunta diferente. Latencia alta con baja CPU a menudo apunta a tiempo off-CPU o contención de locks más que hotspots de CPU.
Muchos equipos empiezan bajo demanda y luego pasan a siempre activo cuando confían en la seguridad y ven problemas recurrentes.
El perfilado seguro en producción trata de controlar el costo. Prefiere muestreo (no trazar cada evento), mantén ventanas de captura cortas (por ejemplo, 10–30 segundos) y mide el overhead en un canario primero. Si no estás seguro, empieza con muestreo de baja frecuencia y aumenta solo si la señal es demasiado ruidosa.
Los flame graphs visualizan dónde se fue el tiempo muestreado durante una ventana de perfilado. Cada “caja” es una función (o frame de stack), y cada stack muestra cómo la ejecución llegó a esa función. Son excelentes para detectar patrones rápido—pero no te dicen automáticamente “el bug está aquí”.
Un flame graph generalmente representa muestras on-CPU: tiempo que el programa estuvo realmente corriendo en un núcleo. Puede resaltar paths de código que consumen CPU, parsing ineficiente, serialización excesiva o hotspots que realmente queman CPU.
No muestra directamente esperas por disco, red, retrasos del scheduler o tiempo bloqueado por un mutex (eso es off-CPU y requiere otro tipo de perfilado). Tampoco prueba causalidad para la latencia visible al usuario a menos que lo conectes a un síntoma acotado.
La caja más ancha es tentadora de culpar, pero pregúntate: ¿es un hotspot que puedes cambiar, o simplemente “tiempo pasado en malloc, GC o logging” porque el verdadero problema está aguas arriba? También vigila el contexto faltante (JIT, inlining, símbolos) que puede hacer que una caja parezca culpable cuando solo es el mensajero.
Trata un flame graph como una respuesta a una pregunta acotada: qué endpoint, qué ventana temporal, qué hosts y qué cambió. Compara flame graphs “antes vs después” (o “saludable vs degradado”) para la misma ruta de solicitud para evitar ruido de perfilado.
Cuando la latencia sube, muchos equipos miran el % de CPU primero. Es comprensible—pero a menudo indica en la dirección equivocada. Un servicio puede estar “solo al 20% de CPU” y aun así ser dolorosamente lento si sus hilos pasan la mayor parte del tiempo sin ejecutarse.
El % de CPU responde “qué tan ocupado está el procesador”. No responde “¿dónde se fue el tiempo de mi solicitud?”. Las solicitudes pueden quedarse atascadas mientras los hilos esperan, están bloqueados o son aparcados por el scheduler.
Una idea clave: el tiempo de reloj de pared de una solicitud incluye tanto trabajo on-CPU como esperas off-CPU.
El tiempo off-CPU suele esconderse detrás de dependencias y contención:
Unas pocas señales suelen correlacionar con cuellos off-CPU:
Estas señales te dicen “estamos esperando”, pero no en qué se está esperando.
El perfilado off-CPU atribuye tiempo a la razón por la que no estábamos corriendo: bloqueo en syscalls, espera en locks, sleep o des-scheduling. Eso es potente para trabajo de latencia porque convierte desaceleraciones vagas en categorías accionables: “bloqueado en mutex X”, “esperando read() de disco” o “atascado en connect() a un upstream”. Una vez que puedes nombrar la espera, puedes medirla, confirmarla y arreglarla.
El trabajo de rendimiento a menudo falla en el mismo momento: alguien ve una métrica sospechosa, la declara “el problema” y empieza a afinar. Los métodos de Gregg te empujan a desacelerar y probar qué está limitando el sistema antes de cambiar nada.
Un cuello de botella es el recurso o componente que actualmente limita el throughput o impulsa la latencia. Si lo alivias, los usuarios ven mejora.
Un hot spot es donde se gasta tiempo (por ejemplo, una función que aparece frecuentemente en un perfil). Los hotspots pueden ser cuellos de botella reales—o simplemente trabajo ocupado que no afecta la ruta lenta.
Ruido es todo lo que parece significativo pero no lo es: jobs de background, picos puntuales, artefactos de muestreo, efectos de caché o “talkers” que no correlacionan con el problema visible al usuario.
Empieza por capturar una instantánea limpia antes: el síntoma visible (latencia o tasa de errores) y las señales candidatas principales (saturación de CPU, profundidad de colas, I/O de disco, contención de locks, etc.). Luego aplica un cambio controlado que debería afectar solo a la causa sospechada.
Ejemplos de pruebas causales:
La correlación es una pista, no un veredicto. Si “la CPU sube cuando la latencia sube”, verifica cambiando la disponibilidad de CPU o reduciendo trabajo de CPU y observa si la latencia sigue.
Anota: qué se midió, el cambio exacto realizado, los resultados antes/después y la mejora observada. Esto convierte una victoria puntual en un playbook reutilizable para el próximo incidente—y evita que la “intuición” reescriba la historia después.
Los incidentes de rendimiento se sienten urgentes, que es precisamente cuando se cuela la conjetura. Un flujo ligero y repetible te ayuda a pasar de “algo está lento” a “sabemos qué cambió” sin dar vueltas.
Detectar: alertar sobre latencia y errores visibles para el usuario, no solo CPU. Avisar cuando p95/p99 cruza un umbral sostenido.
Priorizar: responde inmediatamente tres preguntas: qué está lento, cuándo empezó y quién está afectado? Si no puedes nombrar el alcance (servicio, endpoint, región, cohorte), no estás listo para optimizar.
Medir: recoge evidencia que acote el cuello de botella. Prefiere capturas acotadas en el tiempo (por ejemplo, 60–180 segundos) para poder comparar “malo” vs “bueno”.
Arreglar: cambia una cosa a la vez y vuelve a medir las mismas señales para confirmar la mejora y descartar efecto placebo.
Mantén un dashboard compartido que todos usen durante incidentes. Hazlo aburrido y consistente:
El objetivo no es graficar todo; es acortar el tiempo hasta el primer hecho.
Instrumenta los endpoints que más importan (checkout, login, búsqueda), no todos. Para cada uno, acuerda: p95 esperado, tasa máxima de errores y dependencia clave (BD, caché, tercero).
Antes del próximo outage, acuerda un kit de captura:
Documenta esto en un runbook corto (p. ej., /runbooks/latency), incluyendo quién puede ejecutar capturas y dónde se almacenan los artefactos.
La metodología de Gregg es fundamentalmente sobre cambio controlado y verificación rápida. Si tu equipo crea servicios usando Koder.ai (una plataforma guiada por chat para generar e iterar apps web, backend y móviles), dos características encajan bien con esa mentalidad:
Aunque no generes nuevo código durante un incidente, esos hábitos—diffs pequeños, resultados medibles y reversibilidad rápida—son los mismos que Gregg promueve.
Son las 10:15 y tu dashboard muestra que el p99 de la API sube de ~120ms a ~900ms durante el tráfico pico. La tasa de errores está plana, pero los clientes reportan solicitudes “lentas”.
Comienza centrado en el servicio: Rate, Errors, Duration.
Segmentas Duration por endpoint y ves una ruta dominando el p99: POST /checkout. El Rate sube 2×, los errores son normales, pero la Duration se dispara cuando aumenta la concurrencia. Eso apunta a encolamiento o contención, no a una falla directa.
Luego comprueba si la latencia es tiempo de cómputo o espera: compara el “handler time” de la aplicación vs el tiempo total de la petición (o spans upstream vs downstream si tienes tracing). El handler time es bajo, el tiempo total es alto—las solicitudes están esperando.
Inventaria los cuellos probables: Utilización, Saturación, Errores para CPU, memoria, disco y red.
La utilización de CPU está solo en ~35%, pero la run queue y los context switches suben. Disco y red parecen estables. Ese desajuste (CPU baja, mucha espera) es un clásico: los hilos no consumen CPU—están bloqueados.
Capturas un perfil off-CPU durante el pico y encuentras mucho tiempo en un mutex alrededor de una caché compartida de “validación de promociones”.
Reemplazas el lock global por un lock por clave (o un camino de lectura sin lock), despliegas y observas que el p99 vuelve a la línea base mientras el Rate se mantiene alto.
Checklist post-incidente: