El peor sistema de alertas es un ser humano que te paga. Llega tarde, incompleto y cargado de emoción.
“Tu sitio está roto” no es un síntoma. Es una acusación.
Ejecutar producción sin monitorización es como volar sin instrumentos y llamarlo “ágil”.
Puedes hacerlo hasta el momento en que no puedes, y entonces descubres el verdadero significado de “tiempo medio para demostrar inocencia”.
Qué significa realmente “sin monitorización” (y por qué pasa)
“Sin monitorización” rara vez significa literalmente nada. Normalmente significa sin monitorización que ayude durante un incidente.
Puede haber paneles que nadie mira, logs que nadie puede consultar y una página de estado actualizada por alguien que grita desde el otro lado de la sala.
En la práctica, “sin monitorización” es uno de estos modos de fallo:
- Sin señal externa: nada verifica el servicio desde fuera, así que el éxito interno te engaña.
- Sin enrutamiento de alertas: existen métricas, pero nadie recibe páginas, o las alertas van a un buzón que murió en 2019.
- Sin golden signals: recopilas CPU y RAM, pero no latencia, errores, saturación o tráfico.
- Sin correlación: tienes métricas, logs y trazas, pero no comparten identificadores, sincronización temporal o retención.
- Sin ownership: “equipo de plataforma” es un alias de correo, no un equipo; SRE es “quien tenga más contexto”.
- Sin presupuestos: la monitorización más barata es “lo añadiremos más tarde”, que también es la más cara.
La razón por la que ocurre raramente es la ignorancia. Son los incentivos. Entregar funciones es visible. Prevenir outages es invisible.
Hasta el día en que se vuelve extremadamente visible.
Aquí está la verdad dura: si no puedes responder “¿está caído?” en menos de 60 segundos, no tienes monitorización.
Tienes intuiciones.
Hechos e historia que explican el lío actual
La observabilidad no apareció porque a los ingenieros les gusten los gráficos. Apareció porque la producción seguía incendiándose y los humanos se cansaron.
Algunos puntos de contexto concretos que importan:
- SNMP (finales de los 80) hizo posible sondear dispositivos de red a escala, pero también normalizó “sondear es monitorizar” incluso cuando las aplicaciones eran el problema.
- Época Nagios (2000s) popularizó los checks “¿está arriba?” y patrones de página al fallo; genial para hosts, mediocre para sistemas distribuidos.
- El libro SRE de Google (mediados de los 2010s) impulsó SLOs y presupuestos de errores a las operaciones mainstream, reelaborando la confiabilidad como una característica de producto, no como un hobby.
- Microservicios (2010s) multiplicaron los modos de fallo: una petición de usuario ahora toca 10–100 componentes, convirtiendo los “logs en la máquina” en arqueología.
- Bases de series temporales y almacenamiento barato hicieron viable conservar métricas de alta resolución, pero también habilitaron el anti-patrón de recopilar todo y no entender nada.
- Orquestación de contenedores cambió “servidor caído” por “pod reprogramado”, lo cual es bueno, hasta que te das cuenta de que la reprogramación puede esconder un crash loop durante semanas.
- Grandes outages en la nube enseñaron a las empresas que “la nube es el ordenador de otra persona” también significa “el dominio de los outages de otra persona.” Aún necesitas instrumentación.
- Cultura moderna de incidentes pasó de la culpa al pensamiento sistémico—al menos en las empresas que quieren mantener a los ingenieros empleados más de una rotación de on-call.
Una idea parafraseada, porque se mantiene cierta a través de décadas: “La esperanza no es una estrategia.”
— idea atribuida al Gen. Gordon R. Sullivan, citada a menudo en la cultura de operaciones.
La realidad técnica de “el cliente es el pager”
Cuando un cliente te dice que estás caído, ya son ciertas tres cosas:
- Perdiste tiempo: el incidente empezó antes del reporte. Tu reloj de MTTR ya está corriendo.
- Perdiste fidelidad: los síntomas del cliente están filtrados por navegadores, redes e interpretación humana.
- Perdiste confianza: descubrieron tu fallo antes que tú, y eso no es un buen momento de marca.
El problema operativo no es solo la detección. Es triage.
Monitorizar no son “gráficos.” Es la capacidad de responder rápidamente una secuencia de preguntas sobre producción:
- ¿El servicio está caído o solo lento?
- ¿El problema es global o regional, un tenant o todos los tenants?
- ¿Comenzó después de un deploy, un cambio de config o un pico de carga?
- ¿El cuello de botella es CPU, memoria, disco, red, latencia de dependencia o un lock?
- ¿Se está degradando (fuga) o es súbito (crash)?
- ¿Estamos empeorando la situación con tormentas de retry, autoscaling o bucles de failover?
Sin monitorización, terminas haciendo “forense en producción” bajo presión: SSH a máquinas, tail de logs, conjeturas, reinicios, esperanza.
Eso funciona ocasionalmente, mayormente cuando el problema se arregla trivialmente con un reboot. No escala, y es una forma excelente de crear un segundo incidente.
Broma #1: Ejecutar sin monitorización es como conducir de noche con las luces apagadas porque “la carretera se ve bien en el estacionamiento.”
Por qué “nos daremos cuenta rápido” casi siempre falla
Los equipos asumen que los usuarios reportarán outages rápido. A veces lo hacen. A veces no.
Los outages más silenciosos suelen ser los más dañinos:
- Fallos parciales: un endpoint API falla, una región falla o un segmento de clientes falla.
- Fallos lentos: la latencia sube poco a poco hasta que los clientes se van en lugar de quejarse.
- Errores de corrección de datos: las respuestas son rápidas y erróneas. No obtienes quejas; obtienes auditorías.
- Fallos de jobs en background: facturación, email, exports, ETL. Nadie lo revisa hasta fin de mes.
La monitorización no es solo tiempo de actividad. Es sobre corrección, rendimiento y capacidad.
Es sobre saber que el sistema está haciendo lo correcto, a la velocidad correcta, para las personas correctas.
Playbook de diagnóstico rápido: primeras/segundas/terceras comprobaciones
Este es el playbook de “el cliente dice que estamos caídos”. El objetivo no es ser ingenioso; es ser rápido, repetible y difícil de arruinar.
Buscas el cuello de botella y el radio de blast.
Primero: confirma el síntoma desde afuera
- Comprueba el endpoint público desde dos redes (tu red corporativa y un hotspot de teléfono) para eliminar problemas locales de DNS/VPN.
- Captura el estado HTTP, la latencia y un request ID si está disponible.
- Decide: ¿es caída dura (connection refused/timeouts) o caída suave (500s/lento)?
Segundo: determina el radio de blast
- ¿Es una región/zona? ¿Un cliente/tenant? ¿Un endpoint?
- Revisa primero los componentes de borde: DNS, balanceador de carga, ingress, CDN, expiración de certificados.
- Decide: ¿es un problema de enrutamiento de tráfico o de capacidad de la aplicación?
Tercero: aisla la categoría del cuello de botella
- Cómputo: CPU al máximo, carga alta, cola de ejecución alta.
- Memoria: kills por OOM, tormentas de swap, crecimiento de RSS.
- Disco: sistemas de ficheros llenos, iowait alto, picos de latencia, RAID/ZFS degradado.
- Red: pérdida de paquetes, agotamiento de conntrack, tráfico mal enrutado, stalls en handshake TLS.
- Dependencias: BD saturada, caché caída, API upstream lenta, retrasos en resolución DNS.
Cuarto: detener la hemorragia de forma segura
- Rollback del último deploy/config si se correlaciona con el inicio.
- Limitar tasa o shedding de carga (devolver 429/503) en vez de fundirse.
- Escalar solo si estás seguro de no amplificar una falla de dependencia.
- Decide: mitigar ahora, diagnosticar después de que vuelva la estabilidad.
Quinto: preservar la evidencia
- Snapshot de logs, captura del estado de procesos, registrar timestamps.
- Asegúrate de que los relojes del sistema estén bien; la deriva temporal arruina la correlación.
- Decide: qué necesitamos para un postmortem, antes de “reiniciar lo arregla”.
Tareas prácticas: comandos, salidas y decisiones
A continuación hay tareas concretas que puedes ejecutar durante un incidente. Cada una tiene: un comando, salida representativa, qué significa y la decisión que tomas.
Elige las que correspondan a tu stack; no te disfraces de mago de Linux si estás en servicios gestionados. Pero aprende la forma de las señales.
Task 1: Confirmar que DNS devuelve lo esperado
cr0x@server:~$ dig +short api.example.com
203.0.113.10
Qué significa: Obtienes un registro A. Si está vacío, devuelve una IP inesperada o cambia entre consultas, podrías tener problemas de propagación DNS o split-horizon.
Decisión: Si DNS parece incorrecto, deja de tocar la app. Arregla el enrutamiento (registro, TTL, zona, health checks) o evita con una IP conocida para depuración.
Task 2: Comprobar validez de TLS y handshake desde fuera
cr0x@server:~$ echo | openssl s_client -servername api.example.com -connect api.example.com:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Jan 10 00:00:00 2026 GMT
notAfter=Apr 10 23:59:59 2026 GMT
Qué significa: Si esto falla en conectar o muestra un certificado expirado, tu “outage” podría ser una falla en la rotación de certificados.
Decisión: Si el certificado expiró o la cadena está rota, prioriza arreglar el certificado sobre depurar la app; ningún escalado arregla criptografía.
Task 3: Medir comportamiento del endpoint (estado + latencia)
cr0x@server:~$ curl -sS -o /dev/null -w "code=%{http_code} total=%{time_total} connect=%{time_connect} ttfb=%{time_starttransfer}\n" https://api.example.com/health
code=503 total=2.413 connect=0.012 ttfb=2.390
Qué significa: Connect rápido, TTFB lento implica que el servidor aceptó la conexión pero no pudo responder rápido—latencia de app o dependencia, no red pura.
Decisión: Trátalo como “caída suave” y enfócate en saturación o timeouts de dependencias en vez de DNS o firewall.
Task 4: Identificar si el host está sobrecargado (CPU/cola de ejecución)
cr0x@server:~$ uptime
14:02:11 up 36 days, 3:18, 2 users, load average: 38.12, 35.77, 29.05
Qué significa: Load average muy por encima del número de CPUs indica muchas tareas ejecutables o bloqueadas. “Bloqueadas” a menudo significa espera I/O, no CPU.
Decisión: Revisa inmediatamente iowait y uso por proceso; no solo agregues CPUs y esperes.
Task 5: Ver CPU, iowait y saturación rápidamente
cr0x@server:~$ mpstat -P ALL 1 3
Linux 6.5.0 (app-01) 02/02/2026 _x86_64_ (16 CPU)
02:02:15 PM all %usr %sys %iowait %idle
02:02:16 PM all 12.3 6.1 62.4 19.2
02:02:17 PM all 10.9 5.7 64.0 19.4
02:02:18 PM all 11.1 5.9 63.2 19.8
Qué significa: Alto %iowait significa que las CPUs están inactivas pero esperando disco. Tu problema es latencia de almacenamiento o saturación del disco.
Decisión: Deja de escalar instancias de app como primer movimiento; encuentra qué está golpeando el disco (logs, BD, swap, compactions) y mitiga.
Task 6: Encontrar los mayores consumidores de CPU y memoria
cr0x@server:~$ ps -eo pid,comm,%cpu,%mem,rss --sort=-%cpu | head
PID COMMAND %CPU %MEM RSS
7321 java 380 12.4 2068420
914 nginx 45 0.6 98120
5210 node 33 2.1 349812
Qué significa: Un proceso Java usando varios núcleos fuertemente sugiere trabajo bound por CPU o un bucle fuera de control.
Decisión: Si está limitado por CPU y se correlaciona con un pico de tráfico, considera shedding, reducir concurrencia o rollback. Si es inesperado, captura stack traces antes de reiniciar.
Task 7: Comprobar kills por OOM (muerte silenciosa del servicio)
cr0x@server:~$ dmesg -T | tail -n 8
[Mon Feb 2 13:58:41 2026] Out of memory: Killed process 5210 (node) total-vm:4123456kB, anon-rss:1765432kB, file-rss:0kB, shmem-rss:0kB
[Mon Feb 2 13:58:41 2026] oom_reaper: reaped process 5210 (node), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB
Qué significa: El kernel mató un proceso. Tu servicio puede “reiniciarse” aleatoriamente, flapping o desaparecer.
Decisión: Mitiga reduciendo uso de memoria, ajustando límites, añadiendo RAM o corrigiendo fugas. También añade alertas en eventos OOM; no son sutiles, solo ignorados.
Task 8: Comprobar espacio en disco (la clásica y aburrida caída)
cr0x@server:~$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p2 200G 200G 0 100% /
Qué significa: Disco lleno. Espera efectos secundarios extraños: escrituras fallidas, procesos atascados, riesgo de corrupción de BD, fallos en logging, fallos del gestor de paquetes.
Decisión: Libera espacio de forma segura: borra logs antiguos, rota, mueve artefactos, expande disco. Luego arregla la causa raíz (políticas de retención, logs descontrolados, core dumps gigantes).
Task 9: Encontrar qué está consumiendo disco ahora mismo
cr0x@server:~$ sudo du -xhd1 /var | sort -h
120M /var/cache
2.1G /var/lib
38G /var/log
Qué significa: /var/log es enorme. Eso suele ser el incidente de “encendimos logging debug”.
Decisión: Rota/trunca los mayores responsables, luego establece niveles de log sensatos y rotación. Si necesitas logs debug, envíalos fuera de la máquina con retención.
Task 10: Comprobar latencia y saturación del disco (donde se esconden las caídas)
cr0x@server:~$ iostat -xz 1 3
Linux 6.5.0 (app-01) 02/02/2026 _x86_64_ (16 CPU)
avg-cpu: %user %system %iowait %idle
11.2 5.8 63.7 19.3
Device r/s w/s rkB/s wkB/s await svctm %util
nvme0n1 12.0 850.0 512.0 98432.0 48.3 1.2 99.8
Qué significa: %util cerca de 100% y await alto significa que el dispositivo está saturado; las escrituras se encolan y todo se ralentiza.
Decisión: Identifica el escritor (checkpoint de la BD, flood de logs, job de backup). Límitalo, muévelo o escala almacenamiento. No finjas que esto es “solo CPU.”
Task 11: Validar salud del servicio bajo systemd
cr0x@server:~$ systemctl status nginx --no-pager
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled)
Active: active (running) since Mon 2026-02-02 13:40:07 UTC; 21min ago
Qué significa: El proceso está corriendo. Eso no significa que el servicio funcione; podría estar deadlocked o devolviendo errores.
Decisión: Si está “active” pero los usuarios fallan, revisa salud upstream, conteos de conexiones y logs. No te detengas aquí y declares victoria.
Task 12: Revisar logs recientes por errores obvios
cr0x@server:~$ journalctl -u nginx -S "-15 min" --no-pager | tail -n 8
Feb 02 13:55:10 app-01 nginx[914]: connect() failed (111: Connection refused) while connecting to upstream, client: 198.51.100.33, server: api.example.com, request: "GET /v1/orders HTTP/2.0", upstream: "http://127.0.0.1:8080/v1/orders"
Qué significa: Nginx no puede alcanzar el upstream en 127.0.0.1:8080. Eso es probable un crash de la app, fallo de bind o firewall local.
Decisión: Investiga el servicio upstream: puerto escuchando, crash loop, OOM, config. Arregla la app primero; nginx es solo el mensajero.
Task 13: Confirmar que un puerto está escuchando (y por quién)
cr0x@server:~$ ss -lntp | grep ':8080'
LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("java",pid=7321,fd=123))
Qué significa: El puerto está abierto y es propiedad del proceso Java. Si nadie escucha, el error upstream está explicado.
Decisión: Si no escucha, revisa logs de crash y config. Si escucha, sospecha que la app está bloqueada o dependiente; sondea localmente.
Task 14: Health check local evitando el balanceador
cr0x@server:~$ curl -sS -o /dev/null -w "code=%{http_code} total=%{time_total}\n" http://127.0.0.1:8080/health
code=500 total=0.083
Qué significa: La app responde rápido pero devuelve 500: error interno, mala config, dependencia fallida o startup incompleto.
Decisión: Busca stack traces y fallos de dependencia; no pierdas tiempo en depuración de red.
Task 15: Comprobar conectividad de la base de datos rápidamente (ejemplo PostgreSQL)
cr0x@server:~$ psql -h db-01 -U app -d appdb -c "select now(), count(*) from pg_stat_activity;"
now | count
-------------------------------+-------
2026-02-02 14:02:44.221+00 | 198
Qué significa: La BD es accesible y tiene 198 conexiones activas. Si eso está cerca de tu límite de conexiones, estás coqueteando con un outage auto-infligido.
Decisión: Si las conexiones son altas, habilita pooling, reduce concurrencia o mata queries fuera de control. Si es inaccesible, trata la BD como incidente primario.
Task 16: Identificar contención de locks (ejemplo PostgreSQL)
cr0x@server:~$ psql -h db-01 -U app -d appdb -c "select wait_event_type, wait_event, count(*) from pg_stat_activity where state='active' group by 1,2 order by 3 desc;"
wait_event_type | wait_event | count
-----------------+---------------------+-------
Lock | transactionid | 62
Client | ClientRead | 21
Qué significa: Muchas sesiones esperando locks indica que la base de datos está bloqueada, no “lenta”. Tu app se encola detrás de la contención.
Decisión: Encuentra la query bloqueadora y remédiala (terminar sesión, revertir deploy, ajustar índices/transacciones). Escalar servidores de app aumentará la presión y lo empeorará.
Task 17: Revisar errores de red a nivel kernel
cr0x@server:~$ netstat -s | egrep -i 'listen|overflow|dropped' | head
124 times the listen queue of a socket overflowed
124 SYNs to LISTEN sockets dropped
Qué significa: Tu servidor está descartando conexiones entrantes. Esto se ve como “timeouts aleatorios” desde los clientes.
Decisión: Aumenta settings de backlog, ajusta colas de accept, reduce trabajo por petición o escala horizontalmente. También confirma que la app puede realmente atender.
Task 18: Comprobación de integridad de almacenamiento (ejemplo ZFS)
cr0x@server:~$ sudo zpool status
pool: tank
state: DEGRADED
status: One or more devices has experienced an unrecoverable error.
scan: scrub repaired 0B in 01:12:33 with 0 errors on Mon Feb 2 01:10:02 2026
config:
NAME STATE READ WRITE CKSUM
tank DEGRADED 0 0 0
mirror-0 DEGRADED 0 0 0
sda ONLINE 0 0 0
sdb FAULTED 9 12 0 too many errors
errors: No known data errors
Qué significa: Tu pool está degradado. El rendimiento puede caer, puede haber resilver pendiente y otro fallo de disco podría convertirse en pérdida de datos.
Decisión: Reemplaza el disco fallado, planifica el impacto de resilver y considera limitar jobs pesados. Además: añade monitorización de salud del pool ayer mismo.
Task 19: Comprobar si estás haciendo swap (un asesino silencioso de latencia)
cr0x@server:~$ free -m
total used free shared buff/cache available
Mem: 64000 61200 300 210 2500 900
Swap: 16000 15850 150
Qué significa: El swap está casi lleno; el sistema probablemente está thrashing. La latencia se vuelve aleatoria, sube iowait y todo parece endemoniado.
Decisión: Reduce presión de memoria inmediatamente (reinicia workers con fuga, escala RAM, afina caches). A largo plazo: establece límites, dimensiona correctamente y alerta sobre uso de swap.
Broma #2: Si tu única alerta es un email de cliente, felicidades—has construido un sistema de monitorización distribuido alimentado por ansiedad humana.
Tres micro-historias del mundo corporativo (anonimizadas y plausibles)
Micro-historia 1: El incidente causado por una suposición errónea
Una empresa SaaS mediana ejecutaba un único servicio “API” detrás de un balanceador. Tenían métricas de host: CPU, memoria y disco.
No tenían checks sintéticos ni alertas por tasa de errores. La rotación de on-call era de dos desarrolladores y una persona de infra que además gestionaba backups.
Una mañana de lunes, un cliente reportó que las subidas de archivos fallaban. El equipo asumió “problema de almacenamiento”, porque uploads y storage están conectados en la cabeza de todos.
Hicieron SSH a los hosts de app, comprobaron uso de disco (bien), revisaron la página de estado del object store (green) y reiniciaron los workers de subida solo para “limpiarlo”.
Eso empeoró las cosas, porque los reinicios cayeron las subidas en vuelo y provocaron retries de cliente.
El problema real fue una deriva de reloj en un nodo tras una migración de hipervisor. Los handshakes TLS fallaban intermitentemente porque el nodo creía estar en el futuro.
El balanceador seguía enviando una fracción del tráfico de subida a ese nodo. CPU, memoria y disco parecían normales. El servicio estaba “up”.
Desde el navegador del cliente, era una ruleta rusa.
La solución fue simple: restaurar NTP, drenar el nodo y reintroducirlo. La lección no fue solo “NTP importa” (que sí).
La lección fue que el modelo mental del equipo era demasiado estrecho: asumieron que todo fallo aparece como saturación de recursos.
Sin métricas de éxito a nivel de petición y checks externos, estaban ciegos ante fallos de corrección.
Después añadieron dos cosas: una prueba sintética de subida cada minuto y una alerta por errores de handshake TLS en el borde.
No cien paneles. Dos señales que mapeaban el dolor del usuario.
Micro-historia 2: La optimización que salió mal
Otra compañía, presionada por costos, decidió “optimizar” el logging. Pasaron de enviar logs de aplicación fuera a logs locales con un shipper por lotes.
La propuesta sonaba bien: menos llamadas de red, menor costo de ingestión y “podemos enviar en bloque”.
Durante un pico de tráfico, el shipper por lotes no pudo seguir. Los logs se acumularon localmente. El disco se llenó lentamente, luego de golpe.
Cuando el disco llegó al 100%, la base de datos empezó a fallar checkpoints y la app empezó a lanzar errores que no podía escribir en sus propios logs.
El equipo no vio los errores porque estaban atrapados detrás del mismo problema de disco que los causaba.
Los clientes reportaron timeouts. El equipo escaló la capa API, lo cual aumentó el tráfico de escritura y el volumen de logs, llenando los discos más rápido.
Bucle de realimentación positivo clásico: “escalar para arreglarlo” se convirtió en “escalar para acelerarlo”.
El postmortem fue claro: el buffering local sin cuotas estrictas es un DoS que te programas a ti mismo.
La optimización correcta habría incluido reservas de disco duro, limitación de tasa de logs y comportamiento de backpressure (descartar logs debug primero, no la base de datos).
Finalmente implementaron límites de volumen por servicio y conservaron un stream mínimo de errores enviado en tiempo real.
Micro-historia 3: La práctica aburrida pero correcta que salvó el día
Un equipo de plataforma interno empresarial gestionaba un servicio cercano a pagos. No eran glamorosos. Eran los que decían “no” mucho.
Su monitorización también era aburrida: checks sintéticos, alertas por tasa de error, percentiles de latencia y timeouts de dependencias. Tenían runbooks.
Un deploy del jueves introdujo una fuga de conexiones sutil hacia una base de datos downstream. Las conexiones se acumularon lentamente.
Porque tenían un dashboard de pool de conexiones y una alerta de “saturación del pool”, el on-call recibió una página antes de que los clientes notaran nada.
La alerta no decía “algo es raro”. Decía “pool BD al 90% y subiendo.”
La respuesta fue igualmente aburrida: hicieron rollback inmediatamente, verificaron que el pool se drenó y luego re-desplegaron con un arreglo detrás de un feature flag.
También limitieron la tasa del endpoint más afectado para reducir presión mientras validaban.
Los clientes nunca presentaron tickets. El negocio nunca organizó una war room. El equipo no recibió elogios, que es el mayor cumplido en ingeniería de confiabilidad.
Su práctica no fue genial; fue disciplinada: alertas que coinciden con el impacto al usuario y autoridad para hacer rollback sin comités.
Errores comunes: síntoma → causa raíz → arreglo
Cuando no tienes monitorización, caes en trampas previsibles. Aquí están las que más veo, enmarcadas de forma que puedas actuar durante un incidente.
1) “El servicio está corriendo” pero los usuarios obtienen errores
- Síntoma:
systemctl statusdice active; los clientes ven 500/503. - Causa raíz: Falla de dependencia, agotamiento de thread pool o la app devuelve errores mientras el proceso sigue vivo.
- Arreglo: Añadir health checks que validen dependencias; alertar por tasa de errores y latencia, no por existencia de proceso.
2) Timeouts aleatorios que “desaparecen” tras reiniciar
- Síntoma: Timeouts bajo carga; reiniciar ayuda temporalmente.
- Causa raíz: Fuga de recursos (conexiones, file descriptors, memoria) o límites del kernel (backlog de escucha, conntrack).
- Arreglo: Alertar sobre uso de FD, conteo de conexiones y descartes de red del kernel; aplicar límites y añadir pooling.
3) Solo se queja un cliente
- Síntoma: “Está caído para nosotros, no para otros.”
- Causa raíz: Problema de datos específico del tenant, enrutamiento geográfico, desequilibrio de shard o diferencias en políticas de auth.
- Arreglo: Añadir métricas por tenant/por región y trazabilidad; implementar checks canary sintéticos desde varias regiones.
4) Todo está lento, CPU baja
- Síntoma: CPU baja, latencia alta.
- Causa raíz: iowait de disco, contención de locks o latencia de dependencias upstream.
- Arreglo: Rastrear iowait y await de disco; alertar sobre latencia de dependencias; añadir monitorización de locks en BD.
5) Escalar lo empeora
- Síntoma: Añades instancias, la tasa de errores aumenta.
- Causa raíz: Tormenta de thundering herd/retries o saturación de una dependencia compartida (BD, cache, filesystem).
- Arreglo: Implementar backoff exponencial con jitter, circuit breakers y límites por endpoint; alertar sobre saturación de dependencias.
6) La caída “comienza” cuando los clientes la notan
- Síntoma: Sin timestamp interno; hora de inicio vaga.
- Causa raíz: Sin monitorización sintética externa, sin línea de tiempo de eventos (marcadores de deploy), retención de logs mala.
- Arreglo: Añadir sintéticos y anotaciones de deploy; retener logs/métricas el tiempo suficiente para ver tendencias (no solo los últimos 15 minutos).
7) Health checks pasan mientras el tráfico real falla
- Síntoma: /health returns 200; /checkout fails.
- Causa raíz: Health checks superficiales que no ejercitan dependencias reales o rutas de usuario.
- Arreglo: Añadir checks por capas: liveness (proceso), readiness (dependencia) y transacciones sintéticas (ruta real de usuario).
Listas de verificación / plan paso a paso
Paso a paso: pasar de “nada” a “los clientes no son tu monitorización”
- Define qué significa “caído” para tus usuarios. Elige uno o dos journeys de usuario (login, checkout, petición API) y mídelo.
- Añade checks sintéticos externos. Ejecútalos desde al menos dos redes/regiones. Alerta por fallo y por regresión de latencia.
- Adopta las golden signals por servicio. Tráfico, errores, latencia, saturación. Si no puedes nombrarlas, no puedes alertarlas.
- Instrumenta request IDs. Cada petición recibe un ID de correlación en el borde y los logs lo incluyen de extremo a extremo.
- Crea una página mínima de on-call. Una página, no diez: estado actual, último deploy, tasa de error, p95 de latencia, salud de dependencias.
- Alerta sobre síntomas, no causas. “Spike de 500s” es un síntoma. “CPU 70%” es trivia.
- Establece ownership. Cada alerta tiene un equipo y un runbook. Si nadie lo posee, pageará a todos y no ayudará a nadie.
- Define retención y cuotas. Los logs llenan discos. Las métricas consumen presupuesto. Decide la retención necesaria para depurar tendencias y regresiones.
- Sincronización temporal y relojes. NTP/chrony en todos lados. Si el tiempo está mal, la observabilidad es ficción.
- Practica rollback. Haz que el rollback sea rutinario, no un ritual sagrado que requiere aprobaciones mientras producción arde.
- Escribe postmortems que cambien sistemas. Si la acción es “tener más cuidado”, escribiste un diario, no un artefacto de ingeniería.
- Revisa alertas mensualmente. Elimina alertas ruidosas. Añade las faltantes. La monitorización es un sistema vivo, no un proyecto de una sola vez.
Lista para incidentes: cuando un cliente reporta una caída
- Confirmar externamente (código de estado, latencia, texto de error).
- Registrar hora, región del cliente, endpoint, request ID si es posible.
- Comprobar último deploy/cambio de config.
- Revisar borde: DNS, TLS, salud del load balancer, expiración de certificados.
- Revisar app: logs de error, conectividad a dependencias, saturación (CPU/mem/disco/red).
- Mitigar: rollback, shedding de carga, deshabilitar features no críticas.
- Preservar evidencia: logs, snapshots del sistema, salida de top, info de locks de BD.
- Comunicar: un propietario, un canal, actualización clara hacia clientes.
Checklist de construir bien: monitorización mínima viable (MVM)
- Sintético externo: un endpoint “real”, un endpoint “health”.
- Métricas de servicio: tasa de peticiones, tasa de errores, p95 de latencia, saturación (profundidad de cola, thread pool, conexiones BD).
- Métricas de dependencias: latencia BD, tasa de aciertos de caché, timeouts de upstream.
- Métricas de host: uso de disco, iowait, presión de memoria, descartes de red.
- Eventos: marcadores de deploy, cambios de config, eventos de escalado.
- Higiene de alertas: paginar solo por síntomas que afecten al usuario; lo demás es ticket o dashboard.
Preguntas frecuentes
1) ¿No está bien “sin monitorización” si la app es pequeña?
Las apps pequeñas fallan de formas pequeñas, y luego crecen. La monitorización no es cuestión de tamaño; es cuestión de tiempo para diagnosticar.
Incluso una sola VM se beneficia de alertas por disco lleno y un check sintético básico.
2) ¿Cuál es la primera señal de monitorización que debería añadir?
Un check sintético externo del journey de usuario más importante, con latencia y código de estado registrados.
Si falla, haces page. Si se ralentiza, investigas antes de que falle.
3) ¿Por qué las gráficas de CPU y memoria parecen inútiles durante outages?
Porque muchos outages son sobre dependencias y saturación en otro lugar: latencia de disco, contención de locks o descartes de red.
Las gráficas de host son necesarias pero no suficientes; son los signos vitales, no el diagnóstico.
4) ¿Cómo evitamos la fatiga de alertas?
Pager solo por síntomas que impacten al usuario y umbrales accionables. Todo lo demás se convierte en ticket o dashboard.
Si una alerta no lleva a una decisión, es ruido vestido de responsabilidad.
5) ¿Necesito trazas distribuidas para ser un verdadero SRE?
No. Necesitas claridad. El tracing ayuda en microservicios, pero puedes avanzar mucho con request IDs, alertas de tasa de errores y métricas de latencia de dependencias.
Añade tracing cuando la correlación sea tu cuello de botella.
6) ¿Cuál es el set mínimo de dashboards que realmente ayuda?
Un dashboard por servicio crítico: tráfico, errores, p95/p99 de latencia, saturación y dependencias principales.
Además un dashboard de “borde”: salud de DNS/TLS/LB y checks sintéticos.
7) ¿Cómo manejamos los “outsages parciales” cuando solo algunos usuarios se quejan?
Segmenta tus señales: por región, por tenant, por endpoint y por versión de build.
Los outages parciales son lo que sucede cuando tu monitorización agrega la verdad.
8) ¿Deben los health checks tocar la base de datos?
Los readiness checks deben validar dependencias críticas, incluida la base de datos, pero con cuidado: deben ser ligeros y limitados en tasa.
Usa una consulta simple o una comprobación de conexión, no una transacción completa.
9) ¿Y si no podemos instalar agentes por política de seguridad?
Aún puedes hacer mucho con monitorización black-box (sintéticos), endpoints de métricas a nivel de aplicación y envío central de logs mediante colectores aprobados.
Las políticas de seguridad deben cambiar arquitectura, no eliminar visibilidad.
10) ¿Cómo convences a la dirección de financiar monitorización?
No vendas “observabilidad.” Vende reducción del coste de outages y resolución más rápida de incidentes.
Muestra un timeline de un incidente reciente y resalta cuánto tiempo se perdió adivinando. Haz visible el desperdicio.
Conclusión: próximos pasos que puedes hacer esta semana
Si te enteraste de una caída por un cliente, trátalo como un defecto de producción, no como un mal día.
La solución no es un tablero más bonito. Es construir un sistema que te diga la verdad de forma rápida y consistente.
Haz estos pasos en orden:
- Añade un check sintético externo que mida código de estado y latencia para un endpoint real.
- Crea una alerta de paging en tasa de errores (no en CPU) y enrútala a un calendario de on-call real.
- Instrumenta request IDs y asegúrate de que los logs los incluyan de extremo a extremo.
- Alerta por disco lleno, kills por OOM y timeouts de dependencias—porque estos son los “asesinos silenciosos” que encuentran los clientes primero.
- Escribe un runbook corto para los tres modos de fallo principales que realmente hayas visto (disco lleno, saturación de BD, crash loops).
Luego haz la parte aburrida: mantenlo. La monitorización que no se mantiene se vuelve decorativa.
Y la monitorización decorativa es solo una forma cara de enterarte de que estás caído por un cliente—otra vez.