Integración UPS y ZFS: qué protege realmente un apagado limpio

¿Te fue útil?

Se va la luz. Los ventiladores se detienen. Tu teléfono se enciende. Y te queda esa lenta sensación de aprensión: ¿ZFS “lo manejó”,
o solo te compraste un fin de semana de importaciones de pool, vdevs degradados y explicaciones incómodas?

Un apagado limpio disparado por la UPS es uno de esos controles aburridos y poco glamorosos que marcan la diferencia entre “perdimos energía”
y “perdimos confianza”. Pero no protege lo que la mayoría piensa que protege. Protege la consistencia y la
previsibilidad, no el hardware, no la física, y definitivamente no la creencia de que RAID es un campo de fuerza.

Qué protege realmente un apagado limpio (y qué no)

Definamos “apagado limpio” como lo hace producción: el SO y los servicios se detienen en una secuencia ordenada, ZFS
vacía y confirma lo que necesita, y el pool se exporta o al menos queda en un estado consistente y conocido.
La UPS es solo el mensajero. El flujo de apagado es la protección.

Lo que protege

  • Carga de reproducción del ZFS intent log (ZIL): Con una detención ordenada, reduces la cantidad de trabajo sincrónico
    pendiente de reproducir en el momento de la importación. Menos reproducción significa menos latencia de arranque y menos sorpresas para apps que odian
    las ventanas de recuperación.
  • Oportunidades de coherencia a nivel de aplicación: Las bases de datos pueden hacer checkpoint, vaciar buffers o dejar de aceptar escrituras.
    Un sistema de ficheros puede ser consistente tras un fallo y aun así ser inconsistente para la aplicación. Un apagado limpio te permite arreglar la segunda parte.
  • Comportamiento de arranque/importación predecible: Un apagado limpio evita importaciones largas “colgadas”, recuperación intensa de txg y
    el juego de “¿por qué el pool tarda 20 minutos en importarse?”.
  • Reducción de probabilidad de fallos en cascada: Si la energía oscila o la UPS se agota en medio del caos, quieres la máquina
    ya apagada, no medio escribiendo metadatos mientras la batería agoniza.
  • Personas y proceso: Un apagado limpio hace que las alertas se disparen en el orden correcto, los logs se escriban y puedas
    distinguir entre “corte de energía” y “tuvimos un incidente de almacenamiento”.

Lo que no protege

  • Datos que nunca se confirmaron: Si una aplicación acumuló escrituras en buffer y nunca hizo fsync, también puede perderse en un apagado limpio
    a menos que la app participe (o el SO lo fuerce deteniendo servicios correctamente).
  • Fallas de hardware causadas por eventos de energía: Sobretensiones, bajadas de tensión y fuentes de alimentación baratas aún pueden hacer daño. Una UPS ayuda,
    pero no es un talismán.
  • Mala suposición sobre “sync=disabled”: Si desactivaste sync por benchmarks, un apagado limpio no resucitará escrituras reconocidas que estaban en RAM.
  • Caches de escritura de firmware/controladora sin protección contra pérdida de energía: Si tu HBA o disco miente sobre flushes,
    tu sistema de ficheros puede hacer todo bien y aun así perder datos. ZFS no puede vencer a la física.
  • Corrupción silenciosa que ya existía: ZFS detectará muchas corrupciones y reparará cuando exista redundancia,
    pero un apagado limpio no convierte un disco malo en bueno retroactivamente.

Una cita que sigue pareciendo escritura operativa: “Todo falla, todo el tiempo.” — Werner Vogels.
La jugada adulta es decidir qué fallos vuelven aburridos.

Broma #1: Una UPS es como un paraguas—útil, pero si intentas detener un huracán con él, solo te mojarás más y te pondrás más furioso.

Consistencia ante fallos en ZFS en términos operativos

ZFS es transaccional. Prepara cambios y luego los confirma en grupos de transacciones (txg). Cuando un txg se confirma, las estructuras en disco
se actualizan de forma diseñada para ser consistentes tras un fallo. Esa es la promesa central: puedes perder
cambios recientes que no se confirmaron, pero no deberías obtener un sistema de ficheros medio actualizado que necesite una reconstrucción tipo fsck.

La trampa es que “consistente” no significa “sin tiempo de inactividad” ni “sin pérdida de datos”. Es “sin despropósitos estructurales”. Y la
segunda trampa es que el resto de la pila—el ZIL, el SLOG, la aplicación, el hipervisor, la red—
aún puede conspirar para alargar tu día.

Las partes que importan durante la pérdida de energía

  • TXG (transaction group): Agrupa datos y metadatos sucios, luego los confirma. Un fallo significa: el último txg confirmado es seguro;
    el txg en vuelo se descarta o se reproduce según sea necesario.
  • ZIL (ZFS Intent Log): Solo relevante para escrituras síncronas. Almacena registros de intención para que tras un fallo,
    ZFS pueda reproducir lo que se prometió como “confirmado” a las apps que usan fsync/O_DSYNC.
  • SLOG (dispositivo de log separado): Dispositivo opcional para almacenar el ZIL más rápido (y de forma más segura, si tiene protección ante pérdida de energía).
    No es una caché de escritura para todo. Es un registro especializado para escrituras síncronas.
  • ARC: Caché en RAM. Excelente para rendimiento. Inútil para durabilidad cuando se va la energía.
  • L2ARC: Caché de lectura secundaria. No es una herramienta de durabilidad. Al reiniciar es principalmente “agradable, pero frío otra vez”.

Seis a diez hechos rápidos y contexto histórico (porque ops tiene memoria)

  1. ZFS se creó en Sun Microsystems a principios de los 2000 para reemplazar la separación tradicional entre gestor de volúmenes y sistema de ficheros,
    porque esa separación causaba dolores operativos reales a escala.
  2. Los sistemas de ficheros tradicionales a menudo dependían de fsck tras apagados no limpios; el modelo copy-on-write de ZFS se diseñó para evitar ese
    ciclo de reconstrucción manteniendo el estado en disco autoconsistente.
  3. El “ZIL” no es un journal para todas las escrituras; es específicamente para la semántica de escrituras síncronas. Esa distinción aún confunde a la gente
    y alimenta compras erróneas de SLOG.
  4. Los arrays de almacenamiento empresariales históricamente usaban cache de escritura con batería para reconocer escrituras de forma segura; la ruta síncrona de ZFS es
    un enfoque en software que aún depende del comportamiento honesto de los flushes del hardware.
  5. Los primeros SSDs de consumo eran notoriamente proclives a falsear la finalización de escrituras y carecer de condensadores para el flush, lo que hacía que “sync”
    fuera menos significativo de lo que la gente asumía.
  6. OpenZFS se convirtió en una continuación impulsada por la comunidad tras la etapa de Oracle con ZFS en Sun; las mejores prácticas operativas se difundieron entre proveedores y por informes de incidentes.
  7. El auge de la virtualización y de NFS/iSCSI llevó a que la semántica síncrona fuera más común en laboratorios domésticos y entornos SMB, aumentando la
    importancia real de la corrección de ZIL/SLOG.
  8. “Integración UPS” solía significar cables seriales y demonios de proveedor; ahora es mayormente USB HID y herramientas UPS en red (NUT),
    lo que es más sencillo—y más fácil de configurar mal.

El apagado limpio no se trata de hacer a ZFS “más consistente”. ZFS ya está diseñado para ser consistente ante fallos.
El apagado limpio sirve para reducir la reproducción, reducir la ambigüedad en la recuperación y dar tiempo a las aplicaciones para cerrar correctamente sus operaciones.

Objetivos de integración UPS: el contrato que quieres

No trates la integración UPS como “instalar un demonio y esperar”. Trátalo como un contrato con tres cláusulas:
detectar eventos de energía, decidir según el tiempo de ejecución, y apagar en el orden correcto. Si no puedes resumir tu contrato en una frase,
no tienes uno—tienes vibras.

Cláusula 1: Detectar el evento de energía de forma fiable

USB es conveniente. USB también es lo primero que empieza a fallar cuando hubs, cables baratos y actualizaciones del kernel se cruzan.
Si esto es producción, prefiere una UPS en red o un servidor NUT dedicado que se mantenga arriba más tiempo que cualquier host individual.

Cláusula 2: Decidir basándose en el runtime, no en teatro de porcentaje de batería

El porcentaje de batería no es un plan. Es una sensación con números. Quieres estimaciones de tiempo de ejecución, más un margen de seguridad,
y quieres que el disparador de apagado ocurra mientras la UPS aún esté estable. No quieres descubrir un error tipográfico en tu script de apagado
en modo brownout.

Cláusula 3: Apagar en el orden correcto

Para ZFS, “orden correcto” normalmente significa: detener las apps que generan escrituras, vaciar/detener las exportaciones de almacenamiento en red, y luego apagar el SO.
Si ejecutas VMs sobre ZFS, el hipervisor necesita tiempo para apagarlas limpiamente antes de que el host caiga.

Broma #2: Lo único más optimista que “lo arreglaremos después del corte” es “la UPS se encargará”.

Plan de diagnóstico rápido

Cuando alguien dice “tuvimos un evento de energía y ZFS está lento/raro”, quieres un triage rápido que encuentre el cuello de botella
en minutos, no en horas. Este es el orden que suele pagar la factura.

Primero: confirma qué tipo de apagado tuviste realmente

  • ¿Fue un apagado ordenado por systemd, o una pérdida de energía brutal?
  • ¿Disparó el demonio de la UPS? ¿Llamó al comando de apagado? ¿Llegó el host a poweroff?
  • ¿El pool se importó automáticamente o esperó/se colgó?

Segundo: comprueba la salud del pool y si estás reproduciendo o resilverizando

  • ¿El pool está ONLINE, DEGRADED o importándose lentamente?
  • ¿Se está ejecutando un scrub/resilver y está detrayendo IO?
  • ¿Hay errores de checksum (que cambian toda la conversación)?

Tercero: decide si el problema es latencia de escrituras síncronas (ZIL/SLOG) o IO general

  • Si las apps se quejan de latencia en fsync, céntrate en la salud del dispositivo SLOG, la profundidad de cola y el comportamiento de flush.
  • Si todo está lento, mira la latencia de vdev, un disco muriéndose, resets del controlador o un pool atascado en recuperación.

Cuarto: verifica el orden de detención de servicios

  • ¿Se detuvieron las exportaciones NFS/iSCSI antes de que ZFS y la red se apagaran?
  • ¿Recibieron las bases de datos la señal de parada y tuvieron tiempo para hacer checkpoint?
  • ¿Se apagaron las VMs, o el host cayó debajo de ellas?

Tareas prácticas: comandos, salidas, decisiones (12+)

Estas son las tareas que realmente ejecuto tras eventos de energía o durante trabajos de integración UPS. Cada una tiene: un comando, salida realista,
lo que significa la salida y la decisión que tomas. Los comandos asumen Linux + OpenZFS; ajusta rutas para tu distro.

Task 1: Confirmar que el último apagado fue limpio (journald)

cr0x@server:~$ journalctl -b -1 -u systemd-shutdown --no-pager | tail -n 20
Dec 26 01:12:41 server systemd-shutdown[1]: Syncing filesystems and block devices.
Dec 26 01:12:44 server systemd-shutdown[1]: Sending SIGTERM to remaining processes...
Dec 26 01:12:46 server systemd-shutdown[1]: Sending SIGKILL to remaining processes...
Dec 26 01:12:47 server systemd-shutdown[1]: Unmounting file systems.
Dec 26 01:12:48 server systemd-shutdown[1]: Deactivating swaps.
Dec 26 01:12:48 server systemd-shutdown[1]: Detaching loop devices.
Dec 26 01:12:49 server systemd-shutdown[1]: All filesystems unmounted.
Dec 26 01:12:49 server systemd-shutdown[1]: Powering off.

Significado: Esto parece una ruta de apagado ordenada. Si hubiera sido pérdida de energía, a menudo verías truncamiento abrupto de logs.

Decisión: Si esto es limpio, céntrate menos en “si ZFS se corrompió” y más en “si las apps se detuvieron limpiamente y si la UPS disparó correctamente”.

Task 2: Verificar si el demonio UPS registró eventos “on battery” y “low battery” (NUT)

cr0x@server:~$ journalctl -u nut-monitor --since "today" --no-pager | egrep -i "on battery|low battery|shutdown" | tail -n 20
Dec 26 01:10:02 server upsmon[2314]: UPS ups@localhost on battery
Dec 26 01:12:05 server upsmon[2314]: UPS ups@localhost battery is low
Dec 26 01:12:06 server upsmon[2314]: Executing automatic power-fail shutdown

Significado: Se detectaron eventos de UPS y se actuaron. Si solo ves “on battery” pero no shutdown, tus umbrales de disparo están mal.

Decisión: Si “battery is low” ocurre demasiado tarde (justo antes de la pérdida de energía), aumenta el margen de apagado (umbral de runtime) y vuelve a probar.

Task 3: Consultar el estado de la UPS en vivo (NUT upsc)

cr0x@server:~$ upsc ups@localhost
battery.charge: 96
battery.runtime: 2480
battery.voltage: 27.3
device.mfr: APC
device.model: Smart-UPS 1500
input.voltage: 121.0
output.voltage: 120.0
ups.status: OL
ups.load: 22

Significado: ups.status: OL significa con alimentación en línea. Runtime está en segundos aquí. La carga es modesta.

Decisión: Usa runtime (battery.runtime) como entrada para la decisión de apagado. Configura el apagado cuando el runtime baje por debajo de tu ventana requerida + margen.

Task 4: Confirmar el estado del pool y contadores de errores

cr0x@server:~$ sudo zpool status -x
all pools are healthy

Significado: No hay problemas conocidos. Esto es lo que deseas después de un corte.

Decisión: Si está sano, no empieces “rituales de recuperación” que añadan riesgo. Procede a la verificación a nivel de aplicación y comprobaciones de rendimiento.

Task 5: Estado completo del pool con errores de vdev (después de un incidente grave)

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: DEGRADED
status: One or more devices has experienced an error resulting in data corruption.
action: Restore the file in question if possible. Otherwise restore the entire pool from backup.
  scan: scrub repaired 0B in 00:12:31 with 2 errors on Thu Dec 26 01:44:09 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        DEGRADED     0     0     0
          raidz2-0                  DEGRADED     0     0     0
            sda                     ONLINE       0     0     0
            sdb                     ONLINE       0     0     0
            sdc                     ONLINE       0     0     0
            sdd                     ONLINE       0     0     2  (repairing)

errors: Permanent errors have been detected in the following files:
        tank/data/app.db

Significado: Esto ya no es “solo un corte de energía”. Tienes errores de checksum y un archivo marcado como permanentemente dañado.

Decisión: Detén la aplicación afectada, restaura ese archivo desde backups/snapshots e investiga el disco sdd (SMART, cableado, resets de controlador). No minimices los errores de checksum.

Task 6: Comprobar si hay resilver/scrub en curso y su ventana de impacto

cr0x@server:~$ sudo zpool status tank | sed -n '1,20p'
  pool: tank
 state: ONLINE
  scan: resilver in progress since Thu Dec 26 01:20:12 2025
        312G scanned at 1.02G/s, 88.4G issued at 289M/s, 3.50T total
        88.4G resilvered, 2.46% done, 03:18:44 to go

Significado: Está ocurriendo un resilver y robará ancho de banda e IOPS.

Decisión: Si esto es una carga de producción, considera programar trabajos IO-intensivos fuera de la ventana de resilver y ajusta zfs_resilver_delay/zfs_scan_idle solo si entiendes los tradeoffs.

Task 7: Verificar historial de importación y si el pool fue exportado

cr0x@server:~$ sudo zpool history -il tank | tail -n 20
2025-12-26.01:12:48 zpool export tank
2025-12-26.01:12:49 system: shutdown initiated by upsmon
2025-12-26.01:18:02 zpool import tank

Significado: Alguien (o la automatización) exportó el pool antes del apagado. Esa es una higiene excelente y reduce la ambigüedad de importación.

Decisión: Si no ves exports durante eventos de apagado, considera añadir una exportación controlada en la ruta de apagado de la UPS—con cuidado, y respetando el orden.

Task 8: Confirmar ajustes de sincronización de datasets (evitar “rápido pero inseguro” accidental)

cr0x@server:~$ sudo zfs get -r sync tank | head -n 15
NAME                 PROPERTY  VALUE     SOURCE
tank                 sync      standard  default
tank/data            sync      standard  inherited from tank
tank/data/postgres   sync      standard  local
tank/vm              sync      disabled  local

Significado: tank/vm tiene sync=disabled. Ese dataset está reconociendo escrituras sin garantizar durabilidad.

Decisión: Si tank/vm aloja discos de VM o bases de datos, cámbialo a standard (o always donde corresponda) e invierte en un SLOG adecuado si la latencia sync es la causa.

Task 9: Ver si siquiera tienes un SLOG y cuál es

cr0x@server:~$ sudo zpool status tank | egrep -A3 "logs|cache|special"
logs
  nvme0n1p2            ONLINE       0     0     0

Significado: Hay un dispositivo de log dedicado. Bien—si es del tipo correcto.

Decisión: Valida que el SLOG tenga protección ante pérdida de energía (PLP). Si no la tiene, has creado un dispositivo de “fast crash”.

Task 10: Confirmar salud del dispositivo SLOG e historial de errores (SMART)

cr0x@server:~$ sudo smartctl -a /dev/nvme0 | egrep -i "model|percentage used|media|power cycles|unsafe shutdowns" 
Model Number:                       INTEL SSDPE2KX040T8
Percentage Used:                    3%
Media and Data Integrity Errors:    0
Power Cycles:                       38
Unsafe Shutdowns:                   7

Significado: “Unsafe Shutdowns” distinto de cero es común en la vida útil de un dispositivo, pero si sube con cada corte, estás fallando rutinariamente en apagar limpiamente.

Decisión: Correlaciona los contadores de apagados inseguros con outages y pruebas UPS. Si aumentan durante pruebas planeadas, tu disparador de apagado es demasiado tarde o el orden es incorrecto.

Task 11: Revisar logs del kernel por resets de unidad/controlador alrededor del corte

cr0x@server:~$ dmesg -T | egrep -i "reset|link is down|I/O error|ata[0-9]" | tail -n 20
[Thu Dec 26 01:10:11 2025] ata3: link is slow to respond, please be patient (ready=0)
[Thu Dec 26 01:10:15 2025] ata3: COMRESET failed (errno=-16)
[Thu Dec 26 01:10:19 2025] sd 2:0:0:0: [sdd] tag#18 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
[Thu Dec 26 01:10:19 2025] blk_update_request: I/O error, dev sdd, sector 812345672 op 0x1:(WRITE) flags 0x0 phys_seg 1 prio class 0

Significado: Esto no es ZFS dramatizando; es el kernel indicándote que la ruta de almacenamiento fue inestable.

Decisión: Trátalo primero como un problema de hardware/cableado/controladora. Los errores de ZFS a menudo son consecuencia de errores en el transporte.

Task 12: Medir latencia del pool rápidamente (iostat) y decidir si estás limitado por escrituras síncronas

cr0x@server:~$ sudo zpool iostat -v tank 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        2.01T  1.49T    110    980  12.8M  94.1M
  raidz2-0                  2.01T  1.49T    110    980  12.8M  94.1M
    sda                         -      -     30    220  3.1M  21.1M
    sdb                         -      -     28    235  3.2M  22.4M
    sdc                         -      -     27    245  3.3M  23.0M
    sdd                         -      -     25    280  3.2M  27.6M
logs                             -      -      0    600  0.0K  52.0M
  nvme0n1p2                      -      -      0    600  0.0K  52.0M
--------------------------  -----  -----  -----  -----  -----  -----

Significado: El dispositivo de log está tomando una cantidad significativa de operaciones de escritura/ancho de banda—signo clásico de carga intensiva en síncrono. Si la latencia es alta aquí, las apps la sentirán.

Decisión: Si las quejas de rendimiento coinciden con la actividad del log, céntrate en el rendimiento/PLP del SLOG y en si la carga realmente necesita escrituras síncronas.

Task 13: Comprobar el historial de eventos ZFS por pistas de importación/reproducción

cr0x@server:~$ sudo zpool events -v | tail -n 25
TIME                           CLASS
Dec 26 2025 01:18:02.412345678 sysevent.fs.zfs.pool_import
  pool: tank
  guid: 1234567890123456789
Dec 26 2025 01:18:04.998877665 sysevent.fs.zfs.config_sync
  pool: tank

Significado: Puedes ver eventos de importación y su temporización; esto ayuda a correlacionar “el arranque se sintió lento” con operaciones reales de importación.

Decisión: Si los eventos de importación son frecuentes y asociados a fallos, arregla la fiabilidad del apagado antes de perseguir micro-optimizaciones.

Task 14: Verificar que NFS/iSCSI se detuvieron limpiamente antes del apagado

cr0x@server:~$ systemctl status nfs-server --no-pager
● nfs-server.service - NFS server and services
     Loaded: loaded (/lib/systemd/system/nfs-server.service; enabled)
     Active: active (running) since Thu 2025-12-26 01:18:22 UTC; 12min ago
       Docs: man:rpc.nfsd(8)
   Main PID: 1842 (rpc.nfsd)
     Status: "running"

Significado: Está en ejecución ahora, pero aún necesitas comprobar si se detuvo antes del último apagado.

Decisión: Extrae logs del arranque anterior para ver la temporización de la parada del servicio. Si NFS permaneció activo mientras ZFS intentaba silenciarse, tienes que arreglar el orden.

Task 15: Validar el ordenamiento de systemd para el hook de apagado disparado por la UPS

cr0x@server:~$ systemctl list-dependencies shutdown.target --no-pager | head -n 25
shutdown.target
● ├─systemd-remount-fs.service
● ├─systemd-poweroff.service
● ├─umount.target
● ├─final.target
● └─systemd-shutdown.service

Significado: Esto muestra la ruta de apagado. Tu demonio UPS debería disparar un apagado normal, no un “kill -9 a todo y reza”.

Decisión: Si tu integración UPS evita systemd (scripts personalizados que llaman a poweroff de forma extraña), refactoriza a un apagado estándar para que los servicios puedan detenerse correctamente.

Task 16: Probar el disparador de apagado sin apagar realmente (NUT upsmon -c fsd)

cr0x@server:~$ sudo upsmon -c fsd
Network UPS Tools upsmon 2.8.0
FSD set on UPS [ups@localhost]

Significado: Esto simula el manejo de “forced shutdown”. Dependiendo de la configuración, puede iniciar el apagado inmediatamente.

Decisión: Ejecuta esto durante una ventana de mantenimiento y observa el orden de detención de servicios y el comportamiento de exportación del pool. Si es caótico, arréglalo antes del próximo corte real.

Tres microhistorias corporativas desde el terreno

Microhistoria 1: El incidente causado por una suposición errónea

Una empresa mediana operaba un host de virtualización respaldado por ZFS para servicios internos. Tenían una UPS. Tenían confianza.
También tenían una suposición crítica: “Si la UPS está conectada por USB, el apagado siempre ocurrirá”.

El día que falló no fue dramático—solo una breve caída de tensión y un generador que tardó más de lo esperado en arrancar.
El host no se apagó. La UPS intentó avisar, pero el dispositivo USB se enumeró de forma distinta tras una actualización del kernel,
y el demonio de monitorización estaba silenciosamente observando la ruta de dispositivo equivocada. No hubo alertas, porque “el demonio UPS está en ejecución” era
su único chequeo de salud.

Tras volver la energía, el pool ZFS se importó. Sin corrupción. Todos se relajaron demasiado pronto. Luego el sistema de ficheros de la VM mostró
consistencia a nivel de ficheros pero inconsistencia a nivel de aplicación: una base de datos que había reconocido escrituras dependía de
semánticas de flush del host que no habían verificado. La VM arrancó, la BD se quejó, y el “corto evento de energía”
se volvió un incidente escalonado mientras los equipos discutían si era “almacenamiento” o “la app”.

La solución fue aburrida: añadieron un servidor NUT en una máquina pequeña con energía estable, usaron monitorización en red y añadieron
una validación periódica explícita: consultar el estado de la UPS y alertar si la UPS desaparece o el demonio reporta datos obsoletos.
También auditaron los ajustes sync de datasets y dejaron de pretender que USB equivale a fiabilidad.

Microhistoria 2: La optimización que salió mal

Otro equipo usaba ZFS para un datastore NFS. El rendimiento era “aceptable” hasta que llegó una nueva carga: una granja de builds que hacía muchas
operaciones de metadatos y exigía latencia predecible. El equipo persiguió benchmarks y encontró el interruptor mágico: sync=disabled
en el dataset. La latencia bajó. Los gráficos se veían bien. Hubo una ronda de felicitaciones, que siempre debe considerarse una señal de alerta en monitorización.

Meses después, ocurrió un evento de energía. La UPS inició un apagado limpio y el host se apagó con gracia. Se felicitaron de nuevo.
Luego los usuarios reportaron artefactos de build desaparecidos y jobs “exitosos” que produjeron salidas rotas.
Nada estaba estructuralmente corrupto. ZFS era consistente. Sin embargo, los datos a nivel de aplicación incluían escrituras reconocidas que habían
permanecido en RAM y nunca llegaron a almacenamiento estable—porque le dijeron a ZFS que mintiera en su nombre.

El postmortem fue incómodo porque el outage fue corto y el sistema “se apagó limpiamente”. Esa es la trampa:
un apagado limpio te protege de ciertos modos de fallo, pero no puede protegerte de desactivar intencionalmente garantías de durabilidad.
La optimización había convertido “pérdida de energía rara” en “incidente de integridad de datos eventual”.

La remediación fue volver a habilitar sync y añadir un SLOG adecuado con PLP. Además separaron cargas:
los datasets de caché de build tuvieron ajustes distintos que el almacenamiento de artefactos. El tuning de rendimiento pasó de “activar un bit peligroso” a
“diseñar niveles de almacenamiento como adultos”.

Microhistoria 3: La práctica aburrida pero correcta que salvó el día

Un equipo de servicios financieros ejecutaba iSCSI con respaldo ZFS para algunos sistemas internos que importaban más de lo que parecían.
Su integración UPS no era llamativa. Estaba documentada, probada trimestralmente y tratada como parte del change management.
Tenían una regla: cada ruta de apagado debe poder probarse sin tirar del enchufe.

Usaron un servidor NUT dedicado y configuraron clientes para iniciar el apagado cuando el runtime bajara de un umbral que incluía
“tiempo para detener servicios” más margen. El procedimiento de apagado detuvo primero los targets iSCSI, luego dijo a los servicios de aplicación que pararan,
luego permitió que ZFS se tranquilizara. No exportaban pools manualmente en scripts aleatorios; confiaban en el orden estándar de apagado,
y donde añadieron hooks, lo hicieron como unidades systemd con dependencias claras.

Cuando ocurrió un corte real—más largo de lo habitual—los sistemas se apagaron de forma predecible, con logs limpios. Al volver la energía, el arranque fue aburrido.
Las importaciones fueron rápidas. No hubo resilvers. No hubo errores misteriosos. Los usuarios en su mayor parte no notaron nada.

Lo mejor: durante la revisión post-incidente, nadie discutió qué había pasado, porque los logs lo dejaban claro y el procedimiento se había ensayado.
“Aburrido” fue el criterio de éxito, y lo consiguieron.

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

1) Síntoma: la importación del pool tarda una eternidad después de los cortes

Causa raíz: apagados no limpios repetidos que implican más trabajo de recuperación; a veces agravado por un disco marginal o resets de controlador.

Solución: verifica que la UPS dispare antes; revisa journalctl para un apagado limpio; inspecciona dmesg por resets de enlace; sustituye cables/HBA inestables antes de tunear ZFS.

2) Síntoma: las apps reportan “corrupción de base de datos” pero el estado de ZFS está limpio

Causa raíz: inconsistencia a nivel de aplicación debida a sync deshabilitado, falta de fsync, o pérdida abrupta de energía de una VM.

Solución: restaura desde backups/snapshots; vuelve a habilitar sync; asegura el orden de apagado de VMs; valida ajustes de BD (modo de durabilidad) y semánticas de almacenamiento.

3) Síntoma: clientes NFS se cuelgan durante el outage y vuelven con handles obsoletos

Causa raíz: orden de apagado incorrecto: las exportaciones seguían activas mientras el almacenamiento desaparecía, o los clientes no ven un paro limpio del servidor.

Solución: orden en systemd: detén nfs-server (o el target iSCSI) temprano en el apagado; asegura que la UPS dispare un apagado estándar, no un script kill.

4) Síntoma: la UPS “funciona” en tiempos normales pero falla en cortes reales

Causa raíz: monitorización presente pero no validada; fragilidad USB; demonio en ejecución pero desconectado del dispositivo.

Solución: alerta sobre la frescura de la telemetría UPS; prefiere UPS en red; realiza pruebas FSD simuladas; registra líneas de log esperadas y compruébalas.

5) Síntoma: la latencia de escrituras síncronas se dispara tras añadir un SLOG

Causa raíz: el dispositivo SLOG es más lento o carece de PLP, provocando stalls en flush; o está en un bus compartido con contención.

Solución: elige un SSD/NVMe empresarial con PLP; aíslalo; verifica con zpool iostat y SMART del dispositivo; elimina un SLOG malo en vez de sufrirlo.

6) Síntoma: aparecen errores de checksum tras eventos de energía

Causa raíz: corrupción real por un disco moribundo, ruta de energía inestable o problemas de controlador; a veces expuesto por un scrub tras reboot.

Solución: trátalo como incidente de hardware; ejecuta pruebas SMART; reubica/reemplaza componentes; restaura archivos corruptos desde copias buenas; vuelve a scrubear tras las reparaciones.

7) Síntoma: el sistema se apaga demasiado tarde y la batería muere a mitad del apagado

Causa raíz: umbral de apagado configurado en “batería baja” en vez de “tiempo suficiente para terminar el apagado”, o estimación de runtime no calibrada.

Solución: configura apagado sobre runtime restante con margen; mide la duración real del apagado; incluye tiempo para apagar VMs y exportar almacenamiento.

8) Síntoma: después del corte, el pool está ONLINE pero el rendimiento es terrible

Causa raíz: resilver/scrub en curso, o un disco con alta latencia; ARC frío; o las apps están reproduciendo su propia recuperación.

Solución: comprueba la línea de scan en zpool status; inspecciona IO por vdev en zpool iostat -v; identifica dispositivo lento; comunica la ventana de recuperación esperada a los propietarios de apps.

Listas de verificación / plan paso a paso

Paso a paso: construir una integración UPS que realmente te proteja

  1. Decide el objetivo: “El host se apaga limpiamente antes de que la UPS alcance X segundos de runtime; las apps paran en orden; las importaciones son rápidas.”
  2. Mide el tiempo de apagado: cronometra una parada completa de servicios y poweroff. Añade margen. No adivines.
  3. Elige arquitectura: si hay múltiples hosts, ejecuta un servidor de monitorización UPS (NUT) dedicado y haz que los clientes se suscriban.
  4. Configura triggers basados en runtime, no en porcentaje: establece el apagado cuando runtime < (tiempo de apagado medido + margen).
  5. Valida el orden de servicios: detén primero servicios intensivos en escritura (bases de datos, hipervisores), luego exportaciones (NFS/iSCSI), y finalmente el SO.
  6. Audita las opciones de durabilidad de ZFS: encuentra cualquier dataset con sync=disabled y justifícalo por escrito.
  7. Valida la corrección del SLOG: si usas SLOG, exige PLP y monitoriza la salud del dispositivo.
  8. Prueba sin cortar la energía: simula FSD y verifica logs y comportamiento esperados.
  9. Alerta sobre la frescura de la telemetría UPS: si el demonio no puede leer el estado de la UPS, quieres saberlo antes del corte.
  10. Haz una comprobación post-prueba de importación: tras cada prueba, revisa zpool status, errores y tiempos de importación.

Lista de respuesta tras un outage: después de que vuelva la energía

  1. Comprueba si fue limpio: logs del boot anterior (journalctl -b -1).
  2. Comprueba la salud del pool: zpool status -x y luego zpool status -v si algo parece raro.
  3. Revisa errores del kernel: dmesg por resets y errores de I/O.
  4. Comprueba scrub/resilver: espera impacto de rendimiento y estima tiempo de finalización.
  5. Valida datasets críticos: confirma ajustes de sync, presencia de SLOG y errores de checksum.
  6. Luego valida aplicaciones: recuperación de BD, integridad de VMs y reconexiones de clientes.

Preguntas frecuentes (FAQ)

1) ¿Un apagado limpio evita la corrupción de ZFS?

Reduce el riesgo y el trabajo de recuperación, pero ZFS está diseñado para ser consistente ante fallos incluso sin ello. El apagado limpio protege principalmente
la coherencia a nivel de aplicación, reduce la reproducción del ZIL y evita caos de hardware/transporte durante la pérdida de energía.

2) Si ZFS es consistente ante fallos, ¿por qué molestarse con una UPS?

Porque consistente ante fallos no es “sin consecuencias”. Las importaciones pueden ser más lentas, las apps pueden perder trabajo reconocido (según ajustes),
y las pérdidas duras repetidas estresan el hardware. Además: tus objetivos de disponibilidad suelen incluir “no reinicios inesperados”.

3) ¿Es obligatorio un SLOG para la seguridad?

No. Un SLOG es una herramienta de rendimiento para cargas síncronas. La seguridad viene de semánticas sync correctas y hardware que haga flush honestamente.
Si añades un SLOG, debe ser fiable (idealmente con PLP) o puedes empeorar las cosas.

4) ¿Qué hace realmente sync=disabled?

Indica a ZFS que reconozca las escrituras síncronas sin esperar a que se confirmen de forma segura. Obtienes velocidad y pierdes durabilidad. Si tu app cree que confirmó datos, puede estar equivocada tras un fallo—even con un apagado limpio si el timing sale mal.

5) ¿Debería exportar el pool durante el apagado?

Puede ayudar haciendo la siguiente importación más limpia, pero debes hacerlo en el orden correcto. Si los servicios aún tienen ficheros abiertos o
clientes escriben, exportar puede colgar o fallar. Prefiere el orden estándar de apagado; añade hooks de exportación solo si puedes probarlos.

6) ¿Por qué inició un scrub mi pool tras el reboot?

Algunos sistemas o admins programan scrubs y coinciden con el reinicio; en otros casos lo ejecutas manualmente para validar.
Hacer scrub tras un outage es una buena práctica cuando el evento fue no limpio o sospechas inestabilidad de hardware—espera impacto en rendimiento.

7) La UPS dice 40%. ¿Por qué murió antes?

Los cambios de carga, la edad de la batería, la temperatura y la calibración afectan el runtime. El porcentaje no es un predictor fiable con carga variable.
Basar decisiones en estimaciones de runtime y hacer pruebas controladas periódicas para calibrar.

8) NUT vs apcupsd: ¿cuál debo usar?

Si tienes una sola UPS APC conectada a un host, apcupsd es sencillo. Si tienes múltiples hosts, proveedores mixtos de UPS,
o quieres un servidor de monitorización en red, NUT suele ser la mejor opción.

9) ¿Cómo sé si mi orden de apagado es correcto?

Lo pruebas. Simula un apagado forzado (ventana de mantenimiento), luego inspecciona logs para confirmar: las apps se pararon primero, las exportaciones se detuvieron,
ZFS no estaba ocupado, y el host se apagó con tiempo de sobra.

10) Tras un outage, ¿debo ejecutar inmediatamente zpool scrub?

Si el apagado fue limpio y zpool status -x está sano, a menudo puedes esperar al calendario regular.
Si el apagado fue no limpio, o ves errores de I/O, o ejecutas cargas críticas, haz scrub antes—después de estabilizar el hardware.

Conclusión: pasos siguientes que evitan sorpresas a las 3 a.m.

Un apagado limpio disparado por UPS no concede inmortalidad a discos, bases de datos o malas ideas. Te compra un aterrizaje controlado:
menos promesas en vuelo, menos trabajo de recuperación y un sistema que se comporta de forma predecible cuando vuelven las luces.
Eso es lo que estás pagando.

  1. Mide tu tiempo real de apagado (incluyendo VM/app stop) y establece disparadores basados en runtime con margen.
  2. Valida la telemetría de la UPS (alertas de frescura) y prefiere monitorización en red para entornos multi-host.
  3. Audita ajustes de durabilidad ZFS y deja de usar sync=disabled como estrategia de rendimiento para datos importantes.
  4. Verifica la realidad del SLOG: PLP, monitorización de salud y eliminación si es el dispositivo equivocado.
  5. Ensaya: realiza pruebas de apagado simuladas y confirma que los logs muestran una parada ordenada y un comportamiento de importación limpio.

Si haces esas cinco cosas, los cortes de energía se convierten en una molestia en lugar de un giro de guion. Y ese es todo el sentido.

← Anterior
Ubuntu 24.04: Alta carga pero “nada usa CPU” — la trampa del iowait y cómo confirmarla
Siguiente →
Problemas de MTU/MSS en VPN de oficina: por qué se bloquean archivos grandes (SMB/RDP) y cómo solucionarlo

Deja un comentario