El inicio tarda una eternidad: la única lista que debes limpiar

¿Te fue útil?

Hay un tipo especial de pavor que surge al ver un servidor “arrancar” durante diez minutos mientras tu pipeline de despliegue caduca y todos fingen que está bien. Los registros se deslizan, los ventiladores giran y tu instancia hace eso de estar técnicamente viva pero emocionalmente indisponible.

Si quieres un inicio más rápido, deja de cazar fantasmas. Hay una lista que importa: el conjunto ordenado de cosas que le pides al sistema que inicie, y el grafo de dependencias que impone el orden. Limpia esa lista y el arranque será rápido. Ignórala y seguirás comprando instancias más grandes para ejecutar el mismo script de inicio lento.

La única lista: qué es realmente

Cuando la gente dice “el inicio tarda una eternidad”, normalmente se refieren a una de estas cosas:

  • Tiempo de arranque: kernel + initramfs + sistema init que te llevan a “multi-user” (o equivalente).
  • Tiempo de disponibilidad del servicio: tu app está “iniciada” pero aún no acepta tráfico.
  • Tiempo de disponibilidad del nodo: en Kubernetes/autoescalado, la máquina existe pero no es programable o falla verificaciones de salud.

En la mayoría de Linux modernos, la lista que necesitas limpiar es visible y editable a través de systemd. Concretamente, es:

  • El conjunto de unidades habilitadas que serán arrastradas por un target (usualmente multi-user.target o graphical.target).
  • El grafo de dependencias entre ellas (Wants/Requires/After/Before, más dependencias implícitas y la salida de generators).
  • Los timeouts a nivel de unidad y las restricciones de orden que convierten un “arranque en paralelo” en “esperas en serie”.

Los sistemas no arrancan despacio porque un servicio sea “lento”. Arrancan despacio porque algo obliga al servicio lento a estar en la ruta crítica. No necesitas héroes; necesitas menos cosas en ese camino.

Una cita que vale la pena tener en una nota adhesiva:

“La esperanza no es una estrategia.” — idea parafraseada atribuida a líderes de fiabilidad y operaciones

Misma energía para el rendimiento del arranque: esperar que el sistema arranque más rápido la próxima vez no es un plan. Medir y podar sí lo es.

Guía de diagnóstico rápido

Este es el orden que uso cuando una instancia tarda en arrancar y la gente ya está escribiendo en el canal de incidentes.

Primero: localiza el cubo de tiempo (firmware/kernel vs initramfs vs espacio de usuario)

  • Si la consola se queda antes de “Starting version … systemd”, sospecha firmware, inicialización del kernel, initramfs, descubrimiento de almacenamiento o fsck.
  • Si systemd arranca rápido pero “A start job is running…” durante 90 segundos, sospecha montajes, esperas de network-online o timeouts.
  • Si el arranque termina pero tu app no está lista, sospecha chequeos de readiness, migraciones, DNS, servicios dependientes o límites de tasa.

Segundo: identifica la cadena crítica

  • Ejecuta systemd-analyze critical-chain y encuentra qué está en la línea hasta default.target.
  • Contrasta con systemd-analyze blame, pero no dejes que el “blame” te engañe: algo puede ser lento sin estar en la ruta crítica.

Tercero: confirma si la demora es por espera o por trabajo

  • Espera: timeouts, reintentos, comprobaciones de dependencias, network-online, fallos de montaje.
  • Trabajo: inicio de unidad ligado a CPU, fsck con I/O, escasez de entropía, bloqueos del gestor de paquetes, pulls de imágenes de contenedor.

Cuarto: corta el grafo, no los atajos

  • Elimina unidades innecesarias del target de inicio.
  • Relaja el orden (After=) si es superstición y no requisito.
  • Convierte dependencias “fuertes” en “blandas” cuando sea seguro (Requires → Wants).
  • Arregla o enmascara lo que falla repetidamente.

Ese es el playbook. Ahora lo haremos concreto con comandos y decisiones.

Mide primero: qué significa “arranque lento”

Las discusiones sobre velocidad de arranque suelen ser teológicas. No discutas; mide. systemd te da datos limpios y estructurados, y el journal te da la verdad fea.

Dos definiciones rápidas que importan en la práctica:

  • Tiempo de espacio de usuario es donde vive la mayor parte de tu afinamiento: servicios, montajes y lógica de dependencias.
  • Ruta crítica es la cadena de unidades cuyos retrasos retrasan directamente alcanzar el target de arranque.

También: “arranque” no es solo systemd. Si tienes cloud-init, ignition, agentes de gestión de configuración, pulls de runtime de contenedores o una app que ejecuta migraciones al inicio, eso puede eclipsar el trabajo del init. El punto sigue siendo el mismo: enumera las cosas que haces al arrancar y elimina las que no necesitas.

Y sí, a veces realmente es el almacenamiento. Un único montaje esperando 90 segundos por un servidor NFS muerto puede hacer que tu app “rápida” parezca que corre en una patata.

Broma #1: El tiempo de arranque es como una reunión con “sync rápido” en el título. No puedes acelerarlo creyendo más fuerte.

Las tareas prácticas de limpieza (comandos, salidas, decisiones)

Estas no son “consejos”. Son tareas. Ejecútalas, lee la salida y toma una decisión. Ese es el trabajo.

Tarea 1: Obtén un desglose de alto nivel del arranque

cr0x@server:~$ systemd-analyze
Startup finished in 3.201s (kernel) + 7.842s (initrd) + 1min 18.331s (userspace) = 1min 29.374s
graphical.target reached after 1min 17.902s in userspace

Qué significa: El espacio de usuario es el problema: 78 segundos después del initrd. Kernel/initrd no son la prioridad.

Decisión: Quédate en el terreno de systemd: cadena crítica, blame, unidades fallidas, montajes, esperas de red.

Tarea 2: Encuentra qué está en la ruta crítica

cr0x@server:~$ systemd-analyze critical-chain
graphical.target @1min 17.902s
└─multi-user.target @1min 17.902s
  └─docker.service @52.104s +25.769s
    └─network-online.target @51.990s
      └─systemd-networkd-wait-online.service @21.411s +30.563s
        └─systemd-networkd.service @20.982s +428ms
          └─systemd-udevd.service @12.441s +8.512s
            └─systemd-tmpfiles-setup-dev.service @11.901s +526ms

Qué significa: La cadena está bloqueada por systemd-networkd-wait-online. Luego Docker también está en la ruta.

Decisión: Decide si realmente necesitas que la “red esté totalmente online” antes de alcanzar tu target. La mayoría de sistemas no la necesitan.

Tarea 3: Ver la lista de “blame” sin adorarlo

cr0x@server:~$ systemd-analyze blame | head -n 15
30.563s systemd-networkd-wait-online.service
25.769s docker.service
10.112s dev-sdb2.device
8.512s systemd-udevd.service
6.902s snapd.service
5.441s cloud-init.service
4.990s apt-daily.service
4.221s systemd-journald.service
3.301s systemd-tmpfiles-setup.service
2.880s systemd-logind.service

Qué significa: Tienes múltiples unidades lentas, pero solo las que están en la cadena crítica retrasan tu target de arranque.

Decisión: Arregla wait-online primero (ruta crítica), luego vuelve a Docker y cualquier otra cosa que te importe.

Tarea 4: Lista de unidades fallidas (a menudo el impuesto silencioso del arranque)

cr0x@server:~$ systemctl --failed
  UNIT                         LOAD   ACTIVE SUB    DESCRIPTION
● mnt-backup.mount             loaded failed failed /mnt/backup
● nfs-client.target            loaded failed failed NFS client services

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

Qué significa: Un montaje y el target de cliente NFS fallaron. En algunas configuraciones, systemd esperará o reintentará, costando tiempo.

Decisión: O arregla el montaje, o haz que no bloquee (timeouts, nofail, automount), o elimínalo del inicio.

Tarea 5: Inspecciona largas esperas en el journal para este arranque

cr0x@server:~$ journalctl -b -0 -p warning..alert --no-pager | tail -n 30
Jan 12 10:04:21 server systemd[1]: mnt-backup.mount: Mount process exited, code=exited, status=32/n/a
Jan 12 10:04:21 server systemd[1]: Failed to mount /mnt/backup.
Jan 12 10:04:21 server systemd[1]: Dependency failed for Local File Systems.
Jan 12 10:04:52 server systemd-networkd-wait-online[418]: Timeout occurred while waiting for network connectivity.
Jan 12 10:04:52 server systemd[1]: systemd-networkd-wait-online.service: Failed with result 'timeout'.

Qué significa: Dos clásicos asesinos de arranque: un fallo de montaje y un timeout de wait-online.

Decisión: Arregla la semántica del montaje y elimina el requisito de wait-online a menos que tu nodo realmente no funcione sin él.

Tarea 6: Identifica qué unidades requieren network-online.target

cr0x@server:~$ systemctl list-dependencies --reverse network-online.target
network-online.target
● └─docker.service
● └─remote-fs.target
● └─myapp.service

Qué significa: Docker, sistemas de archivos remotos y tu app están arrastrando network-online. Por eso la espera bloquea todo.

Decisión: Para cada uno: decide si necesita network.target (red básica) en vez de network-online.target (configurada, “online”). La mayoría de demonios debe tolerar que la red llegue poco después.

Tarea 7: Confirma quién arrastra un montaje lento y si puede ser bajo demanda

cr0x@server:~$ systemctl list-dependencies mnt-backup.mount
mnt-backup.mount
● ├─system.slice
● └─remote-fs-pre.target

Qué significa: Este montaje se trata como parte de la configuración de archivos. Si bloquea, bloquea temprano.

Decisión: Si no es requerido para el arranque, sácalo de la ruta crítica con un automount o nofail y timeouts sensatos.

Tarea 8: Audita fstab en busca de entradas hostiles al arranque

cr0x@server:~$ cat /etc/fstab
UUID=9bb0c7d9-4f4d-4d56-9b27-2cbd71a7dbd6 / ext4 defaults 0 1
server:/exports/backup /mnt/backup nfs defaults 0 0

Qué significa: Ese montaje NFS no tiene nofail, no tiene x-systemd.automount ni opciones de timeout. Se quedará encantado estancando el arranque mientras lo intenta.

Decisión: Si es opcional en el arranque, hazlo opcional. Un patrón práctico:

cr0x@server:~$ sudo sed -i 's#server:/exports/backup /mnt/backup nfs defaults 0 0#server:/exports/backup /mnt/backup nfs nofail,x-systemd.automount,x-systemd.idle-timeout=60,timeo=5,retrans=2 0 0#' /etc/fstab

Seguimiento de la decisión: Tras editar, valida con systemctl daemon-reload y una prueba de montaje (tarea siguiente). No lances cambios no probados en fstab; así es como se consigue un día de “no arranca” remoto.

Tarea 9: Prueba el comportamiento del montaje sin reiniciar

cr0x@server:~$ sudo systemctl daemon-reload
cr0x@server:~$ sudo systemctl restart mnt-backup.automount
cr0x@server:~$ ls -la /mnt/backup
total 8
drwxr-xr-x  2 root root 4096 Jan 12 10:06 .
drwxr-xr-x  4 root root 4096 Jan 12 10:06 ..

Qué significa: Con automount, el montaje se activa al acceder. Si el servidor está caído, verás la demora al acceder, no al arrancar.

Decisión: Para sistemas de archivos remotos no esenciales, el automount suele ser el intercambio correcto: arranque rápido, demora controlada cuando realmente lo tocas.

Tarea 10: Elimina “wait-online” cuando sea superstición

cr0x@server:~$ systemctl is-enabled systemd-networkd-wait-online.service
enabled
cr0x@server:~$ sudo systemctl disable systemd-networkd-wait-online.service
Removed "/etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service".

Qué significa: Desactivar wait-online implica que network-online.target aún puede alcanzarse por otras vías, pero se elimina el paso explícito de “esperar hasta estar online”.

Decisión: Si tienes servicios que realmente requieren la red online antes de arrancar, arregla esos servicios, no todo el arranque. Prefiere lógica de reintentos en el servicio, o ordena solo ese servicio después de network-online, no todo el sistema.

Tarea 11: Encuentra qué servicios están habilitados y probablemente no deberían

cr0x@server:~$ systemctl list-unit-files --state=enabled --no-pager | head -n 25
UNIT FILE                              STATE   PRESET
apt-daily.service                       enabled enabled
apt-daily.timer                         enabled enabled
cloud-init.service                      enabled enabled
cloud-init-local.service                enabled enabled
cloud-config.service                    enabled enabled
cloud-final.service                     enabled enabled
docker.service                          enabled enabled
snapd.service                           enabled enabled
ssh.service                             enabled enabled
systemd-timesyncd.service               enabled enabled

Qué significa: Algunos de estos están bien. Otros son equipaje. Algunos son activamente hostiles a un tiempo de arranque predecible.

Decisión: Para servidores (no escritorios), cuestiona los actualizadores en segundo plano (apt-daily), snap si no lo usas, y cualquier cosa relacionada con cloud-init en imágenes que ya no son de primer arranque.

Tarea 12: Verifica en qué espera un servicio (lee el archivo de unidad como si fuera un contrato)

cr0x@server:~$ systemctl cat myapp.service
# /etc/systemd/system/myapp.service
[Unit]
Description=My App API
After=network-online.target remote-fs.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yml
Restart=on-failure
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target

Qué significa: Tu app está tirando explícitamente de network-online y remote-fs. Si cualquiera falla, tu app se convierte en un ancla de arranque.

Decisión: Si la app puede arrancar sin esos y reintentar conexiones, cambia a:

  • After=network.target (o elimina el orden por completo)
  • Elimina remote-fs.target a menos que realmente necesites montajes remotos
  • Mantén TimeoutStartSec ajustado y significativo

Tarea 13: Busca ciclos de dependencia y callejones sin salida de orden

cr0x@server:~$ systemd-analyze verify /etc/systemd/system/myapp.service
/etc/systemd/system/myapp.service:8: Unknown lvalue 'TimeoutStartSec' in section 'Service'

Qué significa: La verificación detecta errores de configuración que pueden hacer que systemd ignore ajustes que creías activos. En este ejemplo, investigarías por qué (¿systemd antiguo? ¿error tipográfico? ¿secciones sobreescritas?).

Decisión: Trata las advertencias de parsing de unidades como bugs de producción. Arréglalas. Las configuraciones mal leídas crean bucles de “¿por qué sigue lento?”.

Tarea 14: Encuentra el tiempo real consumido en unidades de montaje

cr0x@server:~$ systemd-analyze blame | grep -E '\.mount$|remote-fs' | head -n 20
1min 30.002s mnt-backup.mount
12.443s remote-fs.target

Qué significa: Ese montaje por sí solo cuesta 90 segundos. Esto no es una “pequeña optimización”. Es una situación de “quítalo del arranque”.

Decisión: Muévelo a automount, acorta el timeout, añade nofail o elimínalo por completo. Si es requerido para la corrección, invierte en hacer que el servicio remoto sea fiable y rápido.

Tarea 15: Comprueba si el DNS es la espera oculta de red

cr0x@server:~$ resolvectl status
Global
       Protocols: -LLMNR -mDNS -DNSOverTLS DNSSEC=no/unsupported
resolv.conf mode: stub

Link 2 (ens5)
    Current Scopes: DNS
         Protocols: +DefaultRoute
Current DNS Server: 10.0.0.2
       DNS Servers: 10.0.0.2 10.0.0.3

Qué significa: El DNS parece configurado, pero esto no prueba que sea accesible durante el arranque. Muchas esperas de “network-online” son en realidad “el DNS no está listo”.

Decisión: Si usas un resolvedor local o una dependencia que no está disponible temprano, desacopla tu arranque del DNS evitando montajes por nombre y asegurando que los resolvedores estén disponibles (o usa IPs donde corresponda).

Tarea 16: Inspecciona retrasos en initramfs (almacenamiento y drivers)

cr0x@server:~$ dmesg --color=never | grep -E 'EXT4-fs|fsck|timed out|nvme|scsi|link is not ready' | tail -n 25
[    2.901234] nvme nvme0: I/O 14 QID 0 timeout, reset controller
[    3.112345] nvme nvme0: reset controller
[    8.554321] EXT4-fs (nvme0n1p2): recovery complete

Qué significa: Timeouts o resets a nivel de kernel en el almacenamiento pueden dominar el arranque temprano antes de que systemd tenga voz.

Decisión: Si ves resets/timeouts de controladora, deja de culpar a systemd. Revisa la salud del almacenamiento cloud, drivers/firmware o el dispositivo subyacente. En hosts físicos, extrae SMART y logs de la controladora.

Tarea 17: Comprueba salud de discos y fallos pendientes (aburrido, efectivo)

cr0x@server:~$ sudo smartctl -a /dev/sda | egrep -i 'Reallocated|Pending|Uncorrect|Power_On_Hours|SMART overall'
SMART overall-health self-assessment test result: PASSED
Power_On_Hours: 18234
Reallocated_Sector_Ct: 0
Current_Pending_Sector: 0
Offline_Uncorrectable: 0

Qué significa: No parece estar muriendo. Eso es bueno. No es prueba de rendimiento, pero descarta un arrastre común de arranque: discos reintentando lecturas mientras aparentan estar bien.

Decisión: Si los valores son distintos de cero o aumentan, planea un reemplazo y deja de perseguir “optimizaciones” de software para cubrir fallas de hardware.

Tarea 18: Detecta el “impuesto fsck” en el arranque

cr0x@server:~$ journalctl -b -0 --no-pager | grep -E 'fsck|clean|recovering|UNEXPECTED' | head -n 20
Jan 12 10:03:11 server systemd-fsck[201]: /dev/nvme0n1p2: clean, 245612/6553600 files, 12541021/26214400 blocks

Qué significa: Aquí fsck es rápido y limpio. Si en cambio ves reparaciones largas, tu arranque lento es “mantenimiento de sistema de archivos”, no “inicio de servicios”.

Decisión: Investiga apagados no limpios, problemas de almacenamiento y ajustes del filesystem. Y deja de reiniciar cajas como primer paso de troubleshooting.

Tarea 19: Encuentra los generators que crean unidades al inicio

cr0x@server:~$ systemd-analyze unit-paths
/etc/systemd/system.control
/run/systemd/system.control
/run/systemd/transient
/run/systemd/generator.early
/etc/systemd/system
/run/systemd/system
/run/systemd/generator
/usr/local/lib/systemd/system
/usr/lib/systemd/system
/run/systemd/generator.late

Qué significa: Los generators sintetizan unidades a partir de cosas como fstab, crypttab, kernel cmdline y configuraciones de red. Pueden crear sorpresas.

Decisión: Si sigues teniendo “montajes misteriosos” o targets inesperados, inspecciona /run/systemd/generator* después del arranque para ver qué se generó y por qué.

Tarea 20: Valida qué está realmente habilitado para el target por defecto

cr0x@server:~$ systemctl get-default
graphical.target
cr0x@server:~$ systemctl list-dependencies graphical.target --no-pager | head -n 30
graphical.target
● ├─multi-user.target
● ├─display-manager.service
● └─system.slice

Qué significa: Si esto es un servidor, graphical.target es sospechoso. Podrías estar arrancando una pila GUI que no necesitas.

Decisión: En servidores, configura multi-user.target a menos que tengas un requisito real para una sesión gráfica.

Broma #2: Activar todos los servicios de inicio “por si acaso” es como llevar una cinta de correr a un campamento. Técnicamente posible; espiritualmente equivocado.

Errores comunes: síntomas → causa raíz → solución

Síntoma: “A start job is running for /mnt/…”

Causa raíz: Montaje en tiempo de arranque que no puede satisfacerse (NFS/CIFS/iSCSI caído, DNS incorrecto, VPN aún no arriba), combinado con timeouts por defecto y dependencias rígidas.

Solución: Si es opcional: añade nofail, considera x-systemd.automount, acorta timeouts o elimínalo de fstab. Si es requerido: hace la dependencia fiable y asegura la ruta de red temprana.

Síntoma: El arranque bloquea en network-online, pero la red “funciona eventualmente”

Causa raíz: systemd-networkd-wait-online (o equivalente de NetworkManager) esperando una condición que nunca ocurre: retraso DHCP, carrier ausente, interfaz deshabilitada o requisito de DNS.

Solución: Desactiva wait-online globalmente cuando sea seguro; más a menudo, elimina Wants=network-online.target de servicios que no lo necesitan. Si un servicio lo necesita, aplícalo solo a ese servicio y hazlo robusto (reintentos/backoff).

Síntoma: Todo está “lento” tras instalar un paquete o actualizar la imagen

Causa raíz: Nuevas unidades habilitadas (agentes de telemetría, autoactualizadores, escáneres de seguridad), nuevos timers, o cloud-init ejecutándose en cada arranque porque su estado no se persiste correctamente.

Solución: Audita las unidades habilitadas, compáralas con la línea base y deshabilita lo que no necesitas. Haz cloud-init de una sola ejecución arreglando el comportamiento de metadatos/estado de la instancia.

Síntoma: systemd-analyze blame muestra una unidad lenta, pero critical-chain no

Causa raíz: La unidad es lenta pero se inició en paralelo; no está bloqueando tu target de arranque. La gente la persigue porque está “arriba en la lista”.

Solución: Prioriza la cadena crítica. Solo optimiza unidades en paralelo si compiten por CPU/disco y realmente perjudican la disponibilidad o los SLO.

Síntoma: El servicio de la app se inicia rápido pero los health checks fallan por minutos

Causa raíz: Tu app realiza “trabajo de inicio” después de que el proceso se inicia: migraciones, calentado de caché, descubrimiento costoso de dependencias, pulls de imágenes de contenedor o espera de APIs externas.

Solución: Haz la readiness explícita. Saca el trabajo pesado de la ruta caliente. Añade backoff, timeouts y comprobaciones de dependencias adecuadas. Separa migraciones del arranque web si te importa el tiempo de arranque.

Síntoma: Arranques aleatorios lentos; a veces rápidos, a veces terribles

Causa raíz: Dependencias externas (DNS, NTP, servicio de metadata, montajes remotos), escasez de entropía o interfaces de red que hacen flap.

Solución: Elimina orden rígido, añade cache o alternativas locales y usa timeouts que fallen rápido. También revisa salud de hardware y capa de virtualización.

Síntoma: “Antes era rápido; ahora es lento en el mismo host”

Causa raíz: Overrides de unidad acumulándose, suposiciones obsoletas de salida de generators o un renombrado de montaje/dispositivo (por ejemplo, cambios en etiquetas) causando retrasos en descubrimiento.

Solución: Revisa drop-ins y overrides; ejecuta systemd-delta para ver qué cambió; fija montajes por UUID; limpia unidades personalizadas antiguas.

Síntoma: El arranque cuelga antes de que systemd empiece

Causa raíz: Initramfs esperando el dispositivo root, timeouts de almacenamiento, initramfs roto o regresiones de drivers.

Solución: Usa logs de consola y dmesg, revisa la configuración de initramfs, verifica identificadores del dispositivo root y revierte kernel/initramfs si hace falta. systemd aún no es el culpable.

Tres microhistorias corporativas desde el terreno

1) El incidente causado por una suposición errónea: “Network-online significa ‘Internet’”

En una compañía mediana, un equipo estandarizó su imagen base y añadió una regla simple: “Iniciar la API después de que la red esté online”. ¿Razonable, no? Actualizaron la unidad con After=network-online.target y Wants=network-online.target. Pasó todas las pruebas de staging, porque staging tenía DHCP limpio y una única interfaz.

Producción era más desordenada. Las instancias tenían dos NICs: una para tráfico interno y otra para una red de gestión restringida sin ruta por defecto por diseño. Durante el arranque, la lógica de wait-online de systemd-networkd esperaba “configurado” en ambos enlaces. La NIC de gestión nunca cumplió las condiciones que el servicio esperaba. Wait-online alcanzó su timeout y la cadena de dependencias retuvo la API.

El incidente no fue que la API estuviera caída. Fue que el autoescalado se volvió lento. Los nodos tardaban demasiado en unirse. Los despliegues rodaban despacio. Unos pocos failovers regionales empeoraron las cosas porque dependían de reemplazos rápidos de instancias. Desde afuera parecía que “la capacidad está bien pero nada se recupera”. Desde dentro parecía un arranque que se negaba a terminar.

La solución fue agresivamente poco sexy: cambiar la app para iniciar después de network.target, eliminar el requisito global de wait-online y añadir lógica de reintento para conexiones ascendentes. También afinaron el servicio wait-online para que solo se preocupara por la interfaz que importaba (cuando realmente la necesitaban). El error real fue asumir que “online” era una verdad universal. En redes reales es condicional, y pagas por fingir que no lo es.

2) La optimización que salió mal: “Paralelizamos todo con timeouts agresivos”

Un gran equipo de plataforma se obsesionó con el tiempo de arranque porque manejaban miles de nodos y querían actualizaciones rodantes más rápidas. Fueron a cazar con systemd-analyze blame y encontraron un puñado de servicios de larga duración: logging, métricas y un agente de seguridad. Alguien propuso una “mejora simple”: reducir TimeoutStartSec por todo el parque y eliminar restricciones de orden para que todo arranque concurrentemente.

El despliegue se veía bien por un día. El arranque terminó más rápido. Los dashboards estaban verdes. Luego comenzó la rareza. El agente de seguridad fallaba ocasionalmente al iniciar por un disco lento o contención de CPU durante el arranque. systemd lo marcó como fallado, pero el nodo aún alcanzaba el target y quedó elegible para servir tráfico. El equipo de cumplimiento lo notó primero, lo cual nunca es el mejor tipo de monitoreo.

Peor aún, la canalización de logs a veces iniciaba antes de que el DNS estuviera estable, no resolvía su endpoint upstream y salía. Como había sido “optimizada” para arranque rápido, su estrategia de reinicio era insuficiente. Los nodos subían “con éxito” pero con logs faltantes. Cuando un incidente de producción ocurrió dos semanas después, la mitad de los nodos tenía telemetría incompleta. El análisis de la causa raíz se volvió arqueología.

La corrección fue tratar el rendimiento del arranque como una compensación de SLO, no una carrera de velocidad. Restauraron timeouts sensatos para servicios críticos de seguridad/telemetría, añadieron reinicio/retroceso robusto y reintrodujeron orden donde representaba dependencias reales. Aún mejoraron el tiempo de arranque—eliminando basura de la lista de inicio y arreglando montajes—pero dejaron de hacer trampa convirtiendo servicios importantes en opcionales por accidente.

3) La práctica aburrida pero correcta que salvó el día: “Baselina la lista de unidades y difféala”

Una fintech más pequeña tenía una regla que sonaba a burocracia: cada release de imagen base producía un artefacto de texto con la lista de unidades habilitadas, target por defecto y overrides notables. El proceso de release también lo comparaba con la versión anterior. Si un servicio nuevo quedaba habilitado, alguien tenía que explicar por qué.

Un trimestre, una actualización rutinaria del OS introdujo silenciosamente un nuevo servicio en segundo plano relacionado con la gestión de paquetes. No era malicioso. Ni siquiera estaba mal. Pero ocasionalmente tomaba locks e hacía trabajo de red temprano en el arranque. En algunos nodos, colisionó con la gestión de configuración y retrasó servicios clave.

Puesto que el equipo tenía la baseline, vieron inmediatamente “esta unidad es nueva y está habilitada”. No necesitaron tres días de debate sobre si el proveedor de cloud cambió algo. Simplemente la deshabilitaron en servidores donde no era necesaria en el arranque y movieron el trabajo de actualización a una ventana de mantenimiento controlada.

No pasó nada heroico. No hubo sala de guerra. No hay fanfics de “SRE salva el día”. Solo un proceso pequeño que impidió que la lista de inicio creciera dientes silenciosamente. Ese es el nivel de aburrimiento al que deberías aspirar.

Hechos y contexto histórico que puedes usar

  • El tiempo de arranque solía depender sobre todo del hardware. En sistemas antiguos, BIOS/firmware y discos giratorios dominaban. Ahora el grafo de dependencias en espacios de usuario suele dominar en servidores.
  • SysV init era mayormente secuencial. El paso a init basados en dependencias (no solo systemd) hizo posible el arranque en paralelo, pero también volvió más costosas las dependencias mal especificadas.
  • systemd introdujo activación por socket. Los servicios pueden iniciarse bajo demanda cuando llega una conexión, lo que es una de las formas más limpias de mantenerlos fuera de la ruta crítica.
  • fstab es más antiguo que la mayor parte de tu infraestructura. Es un archivo simple, pero en la era systemd alimenta generators que pueden crear comportamientos complejos de unidades.
  • “Online” de red es ambiguo por diseño. Carrier arriba, IP configurada, ruta por defecto presente, DNS accesible: son hitos distintos, y distintas herramientas definen “online” de forma diferente.
  • Los timeouts por defecto suelen ser conservadores. Un timeout de montaje de 90 segundos pudo tener sentido cuando las redes eran lentas y los servidores pocos. A escala, es un amplificador de outages autoinducido.
  • cloud-init cambió cómo funciona el primer arranque. En imágenes cloud, gran parte del “tiempo de inicio” suele ser “tiempo de configuración de instancia”. Si se vuelve a ejecutar inesperadamente, el arranque se dispara.
  • Los sistemas de archivos con journaling redujeron los largos eventos de fsck, no los eliminaron. Si ves reparaciones frecuentes, suele ser síntoma de apagados no limpios o inestabilidad del almacenamiento.
  • El paralelismo puede aumentar la varianza. Cuando todo empieza a la vez, la contención hace que lo que suele ser rápido se vuelva a veces terrible. Por eso importa pensar en la ruta crítica.

Listas de verificación / plan paso a paso

Fase 1: Establecer una baseline (mismo día)

  1. Capturar la salida de systemd-analyze.
  2. Capturar la salida de systemd-analyze critical-chain para el target por defecto actual.
  3. Guardar systemd-analyze blame (las 50 primeras líneas suelen ser suficientes).
  4. Guardar systemctl --failed y advertencias/errores de journalctl -b.

Objetivo: Saber en qué cubo estás y qué unidad está bloqueando el arranque.

Fase 2: Limpiar la lista (1–3 días, según la política)

  1. Eliminar bloqueadores de arranque: arreglar/hacer opcionales montajes remotos; matar wait-online innecesario; remover targets GUI en servidores.
  2. Reducir unidades habilitadas: deshabilitar servicios que no necesitas en servidores (equipaje de escritorio, agentes no usados, timers de actualización durante el arranque).
  3. Simplificar aristas de dependencia: eliminar líneas After= que codifican superstición; convertir Requires en Wants si es seguro; evitar traer remote-fs y network-online a menos que sea estrictamente necesario.
  4. Establecer timeouts sensatos: acortar timeouts de montaje para recursos opcionales; fijar TimeoutStartSec a un valor que refleje la realidad y falle rápido para servicios no críticos.

Objetivo: Reducir la longitud de la ruta crítica y reducir la varianza.

Fase 3: Hacerlo duradero (continuo)

  1. Baselina unidades habilitadas y dif deltas entre versiones de imagen.
  2. Restringe nuevas unidades habilitadas: exige justificación en la revisión de cambios.
  3. Prueba tiempo de arranque en CI para cambios de imagen base (incluso una prueba básica ayuda).
  4. Para apps, aplica semánticas de readiness: iniciado no es igual a listo.

Objetivo: Prevenir regresiones, no solo arreglar el desastre actual.

Qué evitar (porque te hace perder semanas)

  • Deshabilitar a ciegas servicios “lentos” sin entender qué proveen.
  • Reducir timeouts por todas partes para que el arranque “parezca rápido”. Eso solo barre la fiabilidad bajo la alfombra.
  • Perseguir la primera entrada en blame mientras ignoras critical-chain.
  • Asumir que la parte lenta es tu app cuando el sistema está esperando almacenamiento/red.

Preguntas frecuentes

1) ¿Cuál es “la única lista” si no uso systemd?

Sigue siendo el mismo concepto: el conjunto de acciones de inicio más sus restricciones de orden. En OpenRC son runlevels y dependencias; en scripts init, es el orden rc. La lógica de limpieza no cambia: podar, desacoplar y eliminar esperas rígidas.

2) ¿Es suficiente con systemd-analyze blame?

No. Es útil, pero no es un informe de ruta crítica. Una unidad lenta que arranca en paralelo puede no retrasar alcanzar el target de arranque. Usa critical-chain para encontrar qué está bloqueando.

3) ¿Debería desactivar systemd-networkd-wait-online?

A menudo sí, en servidores. Pero hazlo intencionalmente: verifica qué servicios requieren network-online.target. Si solo un servicio lo necesita, manténlo acotado a ese servicio, no globalmente.

4) ¿Cuál es la forma más segura de manejar montajes NFS/CIFS opcionales?

Usa nofail y x-systemd.automount para que el arranque no bloquee. Luego controla el comportamiento en tiempo de acceso con timeouts razonables. Opcional significa opcional en el arranque.

5) Mi app necesita la base de datos. ¿No significa eso que debe esperar a network-online?

No. Significa que tu app debe poder manejar “base de datos no alcanzable todavía”. Inicia el proceso, reintenta conexiones con backoff y solo marca el servicio como listo cuando las dependencias sean accesibles.

6) ¿Pueden los contenedores hacer lento el arranque aunque systemd sea rápido?

Absolutamente. Los runtimes de contenedores pueden tirar imágenes, configurar backends de almacenamiento y esperar la red. Si tu arranque incluye “bajar una imagen de 2GB en cada nodo”, esa carga forma parte de la lista de inicio ya sea que lo admitas o no.

7) ¿Cómo evito que el tiempo de arranque empeore con el tiempo?

Baselina la lista de unidades habilitadas y haz diff por cada release de imagen. También baselina métricas de tiempo de arranque y alerta por regresiones igual que alertarías por regresiones de latencia.

8) ¿Y si la parte lenta está antes de systemd?

Entonces el ajuste de systemd no ayudará. Usa logs de consola y dmesg para encontrar timeouts de descubrimiento de almacenamiento, esperas de initramfs, problemas de drivers o fsck. Arregla el dispositivo/driver/config subyacente.

9) ¿Cambiar el target por defecto de graphical a multi-user es una ganancia real?

En servidores, sí. Elimina toda una clase de servicios que no necesitas. En escritorios, obviamente no. “Target correcto para el trabajo” es un control real de rendimiento.

10) ¿Cuál es la diferencia entre hacer algo rápido y hacer que no bloquee el arranque?

Rápido significa que se completa pronto. No bloquear significa que puede ser lento sin retrasar la disponibilidad. Para muchas dependencias opcionales, no bloquear es el mejor resultado de ingeniería.

Conclusión: próximos pasos que realmente mueven la aguja

El arranque lento rara vez es misterioso. Suele ser un grafo de dependencias que convirtió un arranque paralelo en esperas serializadas, más un puñado de timeouts que son demasiado generosos para las operaciones modernas.

Haz lo siguiente, en orden:

  1. Ejecuta la guía de diagnóstico rápido e identifica el bloqueador de la cadena crítica.
  2. Elimina bloqueadores de arranque: montajes remotos opcionales pasan a automount/nofail; wait-online se acota o desactiva.
  3. Podar unidades habilitadas para que coincidan con el propósito del servidor. Si no sirve tráfico, ni almacena datos, ni provee seguridad/telemetría que realmente requieres, no tiene lugar en la lista de inicio.
  4. Codifica una baseline de unidades habilitadas y tiempos de arranque, y haz diff por cada cambio de imagen. La regresión es el estado por defecto del universo; necesitas papeleo para luchar contra la física.

Si limpias la lista y la mantienes limpia, el arranque deja de ser un thriller de suspenso. Se vuelve un procedimiento aburrido y repetible. En producción, lo aburrido es una característica.

← Anterior
Ejecutable del servicio antimalware con CPU alta: solución sin desactivar la seguridad
Siguiente →
GPU de hardware: cables de alimentación, carriles PCIe y la mentira de la “compatibilidad”

Deja un comentario