Pruebas de pérdida de energía en ZFS: cómo validar la seguridad sin perder datos

¿Te fue útil?

Las pruebas de pérdida de energía son una de esas tareas que todo el mundo promete hacer «el próximo trimestre», justo después de terminar «una migración más».
Entonces salta un interruptor, un PDU se reinicia, o un técnico desconecta el cable equivocado y de repente estás aprendiendo la verdad de tu almacenamiento en directo.

ZFS es famosa por su resiliencia, pero no puede salvarte de todas las mentiras que cuenta el hardware—especialmente en torno a las cachés de escritura y los reconocimientos de «sí, lo vacié».
Esta guía explica cómo validar la seguridad con seriedad, sin convertir los datos de producción en un experimento de feria de ciencias.

Qué estás probando realmente (y qué no)

«Pruebas de pérdida de energía» se usa como si fuera una sola cosa. No lo es. Estás validando una cadena de promesas:
el sistema operativo, el HBA, el firmware del disco, la política de caché y el diseño del pool tienen que ponerse de acuerdo sobre qué significa «durable».
ZFS está en el medio intentando mantener la honestidad. A veces lo consigue. A veces el hardware la hace quedar mal.

Esto es lo que estás probando:

  • Consistencia ante crash: tras una pérdida abrupta, que el pool se importe limpiamente y los metadatos estén coherentes.
  • Durabilidad de escrituras síncronas: que los datos reconocidos como sync estén realmente en soportes estables.
  • Comportamiento de ZIL/SLOG bajo estrés: cuánto pierdes en vuelo y si la reproducción es limpia.
  • Flujo de recuperación: cuánto tardan las personas en restaurar el servicio sin empeorar la situación.
  • Veracidad de tu pila de almacenamiento: si flushes, barriers y FUA se respetan de punta a punta.

Lo que no estás demostrando:

  • Que la corrupción nunca puede ocurrir. Estás reduciendo probabilidades y mejorando la detección.
  • Que las escrituras asíncronas son durables. Si tu app escribe en async, estás probando «mejor esfuerzo», no garantías.
  • Que RAIDZ es una copia de seguridad. No lo es, y ZFS no discutirá contigo sobre eso.

Una cita que vale la pena tener pegada en el monitor. La línea citada de Peter Drucker (idea parafraseada):
Lo que se mide se gestiona.
En almacenamiento, lo que se mide también se cree. Así que mide correctamente.

Hechos y contexto que cambian decisiones

Esto no es trivia. Son las razones por las que ciertos montajes «obvios» son silenciosamente peligrosos.

  1. ZFS es copy-on-write (CoW): nunca sobrescribe bloques en vivo en su lugar, por eso la consistencia del pool tras un crash suele ser excelente.
  2. ZFS suma checksums a todo (metadatos y datos): detecta la corrupción incluso cuando el disco devuelve basura con cara de satisfacción.
  3. El ZIL existe aunque no haya SLOG: la intención de transacción síncrona se registra en algún lado; un dispositivo de log dedicado solo cambia dónde.
  4. SLOG no es una caché de escritura: acelera las escrituras síncronas; no hace que las escrituras asíncronas sean seguras y no reemplaza la necesidad de RAM.
  5. Las cachés de escritura a veces mienten: ciertos discos/SSDs tienen cachés volátiles que pueden reconocer escrituras antes de que sean persistentes, a menos que la protección ante pérdida de energía (PLP) sea real y esté habilitada.
  6. Barriers y flushes son un contrato: Linux + controlador + dispositivo deben respetar la semántica de cache flush/FUA. Un eslabón débil hace que «sync» sea teatro costoso.
  7. Los scrubs de ZFS no son fsck: un scrub es verificación de integridad mediante checksums y reparación mediante redundancia. No es una herramienta genérica de «arregla mi pool».
  8. Los bugs por pérdida de energía suelen ser bugs de tiempo: la misma prueba puede pasar 99 veces y fallar en la 100 porque el fallo vive en una pequeña ventana de carrera.
  9. Los primeros ZFS popularizaron checksums de extremo a extremo en operaciones: no fue el primer sistema de archivos en hacerlo, pero sí el que muchos equipos SRE encontraron con furia y luego se negaron a dejar.

Broma #1: Los ingenieros de almacenamiento no creen en fantasmas. Creemos en «latencia inexplicada» y en «se arregló tras un reboot», que es básicamente lo mismo con mejores gráficas.

Modelo de amenazas: modos de fallo que importan

Trata la pérdida de energía como una herramienta de inyección de fallos que además es dramática. Apuntas a clases específicas de fallos.
Si no les pones nombre, harás una «prueba», te sentirás productivo y no aprenderás nada.

1) Crash sin mentiras del almacenamiento (el «crash bueno»)

El kernel se detiene. Se corta la energía. Los dispositivos se detienen al instante. Al reiniciar, ZFS reproduce los intent logs, retrocede al último TXG consistente,
y pierdes como mucho los últimos segundos de trabajo asíncrono. El trabajo síncrono sobrevive.

2) Crash con caché volátil que miente (el «crash malo»)

Tu dispositivo o controlador reconoció escrituras que estaban en una caché volátil. La pérdida de energía las hace desaparecer.
ZFS pudo haberlas creído durables, así que ahora tienes bloques faltantes que pueden manifestarse como errores de checksum, errores permanentes en scrub,
o—el peor caso—corrupción silenciosa si la mentira coincide con una ruta de checksum válida (raro, pero no construyas política sobre «raro»).

3) Crash durante resilver/scrub (el «crash de estrés»)

Esto prueba operaciones de metadatos de larga duración y su reanudabilidad. ZFS suele ser sólido aquí, pero tu cuello de botella puede cambiar:
un scrub puede amplificar IO y revelar problemas de colas, bugs de firmware de controlador o discos débiles.

4) Pérdida parcial de energía / brownout (el «crash raro»)

Un estante cae, otro sigue vivo. Una PSU sobrevive. Los expanders SAS se reinician. NVMe se resetea.
Estos son los cortes donde los logs parecen una escena del crimen y descubres si multipath y timeouts son sensatos.

5) Errores humanos en la recuperación (el «crash más común»)

Un pool limpio puede convertirse en un desastre por una importación impaciente con flags incorrectos o por «arreglar» lo que no está roto.
Las pruebas de pérdida de energía deben incluir un runbook de recuperación, no solo cortar la energía.

Construye un laboratorio que diga la verdad

Si pruebas en un SSD de portátil con un solo pool y una carga amable, estás probando la tranquilidad emocional del equipo, no el sistema.
El laboratorio no tiene que ser caro, pero debe ser honesto.

Reglas para un entorno de prueba de confianza

  • Misma clase de almacenamiento que en producción: mismos modelos de SSD/HDD, mismo HBA, misma familia de firmware. «Suficientemente parecido» es donde los datos van a morir.
  • Misma filosofía de ashift y recordsize: no «optimices» el laboratorio con tamaños de bloque distintos y esperes un comportamiento de fallo idéntico.
  • Corte de energía reproducible: un outlet PDU conmutado, un relé o power-off por IPMI. Tirar de un cable al azar no es ciencia reproducible.
  • Registro de consola fuera de banda: consola serie, IPMI SOL o al menos logs persistentes del journal. Quieres los últimos 2 segundos.
  • Pruebas con tiempo limitado: define qué significa «pasar» antes de empezar. De lo contrario seguirás probando hasta aburrirte.

Qué deberías reflejar de producción

Refleja la topología del pool, el número de vdevs y si usas SLOG dedicado. Refleja tu política de sync.
Refleja la compresión y la elección de atime. Y sí, refleja tus peores cargas de trabajo.

Qué no deberías reflejar

No reflejes la falta de monitorización de producción. El laboratorio es donde añades instrumentación extra.
Quieres ver la cadencia de commit de TXG, la actividad del ZIL, el comportamiento de flush de dispositivos y las distribuciones de latencia.

Cargas de trabajo y métricas: deja de usar “dd” y empieza a medir

«Escribí un archivo grande y parecía bien» no es una prueba. Es una nana.
Tu carga debe incluir escrituras sync, churn de metadatos, IO aleatorio pequeño y rendimiento sostenido. También concurrencia.

Comportamientos clave para activar

  • Presión de commit síncrono: bases de datos, NFS con sync, apps que hacen fsync con frecuencia.
  • Actualizaciones de metadatos: tormentas de create/unlink, snapshots, clones, cambios de propiedades de dataset.
  • Actividad del mapa de espacio: liberaciones, reescrituras y patrones de fragmentación.
  • Lectura/escritura mixta bajo carga: porque los cortes no esperan a que termine tu job por lotes.

Métricas que importan durante la prueba

  • Distribución de latencias de escritura sync: p50/p95/p99, no solo la media.
  • Tiempo de commit de TXG: commits largos pueden extender la ventana de pérdida de datos asíncronos e indicar problemas con flush de dispositivos.
  • Utilización de ZIL/SLOG: con qué frecuencia y cuánto se usa.
  • Errores de checksum y de IO: tras el reboot y después del scrub.
  • Tiempo de import y tiempo de replay: el impacto operativo importa.

Broma #2: Si tu plan de prueba de pérdida de energía es «desenchufa y espera», felicitaciones—has reinventado el chaos engineering, pero con menos dashboards.

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

Estas son comprobaciones y procedimientos de grado producción que puedes ejecutar en laboratorio y—con cuidado—en producción para validación.
Cada tarea incluye: comando, qué significa la salida y qué decisión tomar.
Los ejemplos asumen OpenZFS en Linux. Ajusta nombres de dispositivos y nombres de pool.

Task 1: Identificar salud del pool y topología

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:12:41 with 0 errors on Tue Dec 24 02:10:12 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          raidz2-0                  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N0  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N1  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N2  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N3  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N4  ONLINE       0     0     0
            ata-WDC_WD80EFZX-68UW8N5  ONLINE       0     0     0

errors: No known data errors

Significado de la salida: quieres ONLINE, cero errores y un scrub reciente sin reparaciones.

Decisión: Si ya tienes errores de checksum, para. Arregla la salud base antes de inyectar fallos.

Task 2: Comprobar la política sync del dataset (la verificación de “nos saltamos la seguridad?”)

cr0x@server:~$ sudo zfs get -o name,property,value -s local,default sync tank
NAME  PROPERTY  VALUE
tank  sync      standard

Significado de la salida: standard respeta las solicitudes sync de la app; disabled miente a las apps; always fuerza sync para todas las escrituras.

Decisión: Para validar seguridad, prueba temporalmente con sync=always en los dataset(s) importantes para verificar la durabilidad real.

Task 3: Verificar si tienes un SLOG y cuál es

cr0x@server:~$ sudo zpool status tank | sed -n '1,80p'
  pool: tank
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0
        logs
          nvme0n1p1 ONLINE       0     0     0

Significado de la salida: Una sección logs indica un dispositivo SLOG separado.

Decisión: Si dependes del rendimiento sync o de NFS sync, valida la protección ante pérdida de energía del SLOG y su latencia.

Task 4: Confirmar propiedades clave del dataset que afectan el comportamiento ante fallos

cr0x@server:~$ sudo zfs get -o name,property,value recordsize,compression,atime,logbias,primarycache tank/data
NAME       PROPERTY     VALUE
tank/data  recordsize   128K
tank/data  compression  lz4
tank/data  atime        off
tank/data  logbias      latency
tank/data  primarycache all

Significado de la salida: logbias=latency tiende a usar más el SLOG para escrituras sync; throughput empuja más al pool principal.

Decisión: Para bases de datos, logbias=latency con un SLOG PLP es razonable; de lo contrario podrías pagar una penalización de latencia sin beneficio.

Task 5: Confirmar la política de caché de escritura y el riesgo de “caché volátil” en SSD/NVMe

cr0x@server:~$ sudo nvme id-ctrl /dev/nvme0n1 | egrep -i 'vwc|oncs|wzsl'
vwc     : 0x1
oncs    : 0x5f
wzsl    : 0x0

Significado de la salida: vwc: 0x1 indica caché de escritura volátil presente. Eso no es automáticamente malo—pero plantea la pregunta: ¿tiene la unidad PLP?

Decisión: Si el dispositivo tiene caché volátil y no PLP, no lo uses como SLOG. Trata las afirmaciones de durabilidad sync como dudosas hasta demostrar lo contrario.

Task 6: Comprobar la configuración de caché de escritura SATA (donde a veces comienzan las mentiras)

cr0x@server:~$ sudo hdparm -W /dev/sda | head -n 2
/dev/sda:
 write-caching =  1 (on)

Significado de la salida: La caché de escritura está habilitada. Muchos discos son seguros; algunos no lo son; los controladores también pueden interferir.

Decisión: Si no puedes verificar la protección ante pérdida de energía, considera deshabilitar la caché de escritura para las pruebas (aceptando caída de rendimiento), o usa discos empresariales con PLP.

Task 7: Verificar que ZFS ve ashift y que es sensato

cr0x@server:~$ sudo zdb -C tank | egrep 'ashift|vdev_tree' | head -n 20
        vdev_tree:
            type: 'root'
            id: 0
            guid: 1234567890123456789
            ashift: 12

Significado de la salida: ashift: 12 significa sectores de 4K. Un ashift incorrecto puede causar amplificación de escritura patológica y commits de TXG largos.

Decisión: Si ashift está mal, arréglalo reconstruyendo el pool. No lo racionalices; al pool no le importan tus sentimientos.

Task 8: Línea base de latencia de IO y colas antes de empezar a romper cosas

cr0x@server:~$ iostat -x 1 3
Linux 6.8.0 (server)   12/26/2025  _x86_64_  (16 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           2.31    0.00    1.12    0.45    0.00   96.12

Device            r/s     rkB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wkB/s   wrqm/s  %wrqm w_await wareq-sz  aqu-sz  %util
sda              0.00      0.00     0.00   0.00    0.00     0.00   12.00   512.00     0.00   0.00    7.20    42.67    0.09   8.40
nvme0n1          0.00      0.00     0.00   0.00    0.00     0.00   80.00 10240.00    0.00   0.00    0.45   128.00    0.04   2.10

Significado de la salida: Observa w_await, aqu-sz y %util. Un SLOG con await alto durante pruebas sync es una bandera roja.

Decisión: Si la línea base ya está saturada, tu prueba de pérdida de energía medirá más «cuánto estábamos sobrecargados» que la corrección.

Task 9: Generar una carga sync-intensa que realmente llame a fsync

cr0x@server:~$ sudo fio --name=syncwrite --directory=/tank/data/test \
  --rw=randwrite --bs=4k --size=2G --iodepth=1 --numjobs=4 \
  --fsync=1 --direct=1 --time_based --runtime=60 --group_reporting
syncwrite: (groupid=0, jobs=4): err= 0: pid=22310: Fri Dec 26 10:12:41 2025
  write: IOPS=410, BW=1640KiB/s (1679kB/s)(96.1MiB/60001msec)
    clat (usec): min=650, max=42000, avg=2400.12, stdev=1100.55
    lat (usec): min=670, max=42120, avg=2420.88, stdev=1102.10

Significado de la salida: Con --fsync=1 e iodepth=1, fuerzas puntos de durabilidad frecuentes.

Decisión: Usa esta carga durante cortes de energía para validar si las escrituras sync reconocidas sobreviven.

Task 10: Rastrear latencia de ZFS y estadísticas de colas durante la prueba

cr0x@server:~$ sudo zpool iostat -v tank 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        1.20T  5.80T     20    450  2.5M  1.7M
  raidz2-0  1.20T  5.80T     20    210  2.5M  1.2M
    sda         -      -      3     35   420K   220K
    sdb         -      -      3     35   420K   220K
    sdc         -      -      3     35   420K   220K
    sdd         -      -      3     35   420K   220K
logs            -      -      -    240     -   520K
  nvme0n1p1     -      -      -    240     -   520K

Significado de la salida: Si las escrituras se acumulan en logs bajo presión sync, estás usando el SLOG como previsto. Si no, tu carga puede no ser sync, o logbias/sync difieren.

Decisión: Si el SLOG está saturado, espera alta latencia sync. Considera SLOG espejo o mejor dispositivo, no un pool más grande.

Task 11: Validación pre-crash: haz snapshot de un dataset marcador para poder probar qué sobrevivió

cr0x@server:~$ sudo zfs snapshot -r tank/data@pre_cut_01

Significado de la salida: No haber salida significa que funcionó. Ahora tienes un estado de referencia conocido y bueno.

Decisión: Siempre haz snapshot antes de cortar la energía. Convierte «creo que cambió» en un diff real.

Task 12: Tras el crash: importa el pool de forma segura y observa la reproducción

cr0x@server:~$ sudo zpool import
   pool: tank
     id: 1234567890123456789
  state: ONLINE
 action: The pool can be imported using its name or numeric identifier.
 config:

        tank        ONLINE
          raidz2-0  ONLINE
            sda     ONLINE
            sdb     ONLINE
            sdc     ONLINE
            sdd     ONLINE
        logs
          nvme0n1p1 ONLINE
cr0x@server:~$ sudo zpool import -o readonly=on -N tank

Significado de la salida: Importar readonly primero te permite inspeccionar sin escribir nuevo estado inmediatamente.

Decisión: Si ves advertencias sobre dispositivos faltantes o UNAVAIL, detente e investiga cableado/resets de controlador antes de importar en modo lectura-escritura.

Task 13: Comprobar el último transaction group conocido y errores en el historial de eventos

cr0x@server:~$ sudo zpool history -i tank | tail -n 25
2025-12-26.10:14:03 zpool import -o readonly=on -N tank
2025-12-26.10:14:21 zpool export tank
2025-12-26.10:15:10 zpool import tank

Significado de la salida: Puedes correlacionar imports/exports con la línea de tiempo de la prueba. Exports/imports inesperados pueden indicar watchdogs o automatización interviniendo.

Decisión: Si un agente «útilmente» importa/exporta, desactívalo durante la prueba. Determinismo gana a sorpresas.

Task 14: Ejecutar un scrub e interpretar el resultado

cr0x@server:~$ sudo zpool scrub tank
cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 00:16:22 with 0 errors on Fri Dec 26 10:32:18 2025
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            sda     ONLINE       0     0     0
            sdb     ONLINE       0     0     0
            sdc     ONLINE       0     0     0
            sdd     ONLINE       0     0     0
        logs
          nvme0n1p1 ONLINE       0     0     0

errors: No known data errors

Significado de la salida: «0 errors» tras un crash es lo que quieres. Si ves bytes reparados, investiga si era preexistente o inducido.

Decisión: Cualquier error de checksum tras una prueba controlada es una señal grave: sospecha de mentiras de flush, un SLOG malo o un problema de controlador.

Task 15: Comparar estado pre/post corte usando snapshots (probar límites de pérdida de datos)

cr0x@server:~$ sudo zfs snapshot -r tank/data@post_cut_01
cr0x@server:~$ sudo zfs diff -FH tank/data@pre_cut_01 tank/data@post_cut_01 | head
M	/tank/data/test/file0001
M	/tank/data/test/file0002
-	/tank/data/test/tmp_8831

Significado de la salida: Puedes ver exactamente qué cambió. Si tu aplicación afirma que hizo fsync y falta, tienes una brecha de durabilidad.

Decisión: Falta de datos que se fsyncearon no es «pérdida esperada». Es un bug o una mentira. Escala a validación de hardware.

Task 16: Revisar logs del kernel por resets de almacenamiento y fallos de flush

cr0x@server:~$ sudo journalctl -b -k | egrep -i 'zfs|nvme|sd |scsi|reset|timeout|flush' | tail -n 40
Dec 26 10:15:18 server kernel: nvme nvme0: controller reset occurred
Dec 26 10:15:19 server kernel: sd 0:0:0:0: [sda] Synchronize Cache(10) failed: Result: hostbyte=DID_OK driverbyte=DRIVER_SENSE
Dec 26 10:15:20 server kernel: ZFS: Loaded module v2.2.4-1
Dec 26 10:15:27 server kernel: ZFS: pool tank imported, checkpoint disabled

Significado de la salida: Fallos en Synchronize Cache o resets de controlador alrededor del crash son donde la verdad se filtra.

Decisión: Si los flushes fallan, no confíes en la durabilidad sync. Arregla firmware, modo HBA o reemplaza dispositivos.

Cómo cortar la energía de forma segura (y qué no hacer)

El objetivo es simular un corte manteniendo la capacidad de recuperar y analizar. No es momento para danza interpretativa con cables de alimentación.
Elige un método reproducible que no introduzca variables extra.

Métodos preferidos (más reproducibles)

  • Outlet PDU conmutado: corta la energía del host dejando la red y el logging intactos en otro lado.
  • Apagado de chasis por IPMI: consistente, registrado y amigable para remoto. No es «puro», pero es suficiente para muchos escenarios.
  • Corte de CA controlado por relé: lo más cercano a «real» manteniendo reproducibilidad.

Métodos que crean más confusión que información útil

  • Desconectar PSUs al azar en sistemas redundantes: eso es una prueba de fallo de PSU, no de pérdida de energía. Útil, pero llama a las cosas por su nombre.
  • Machacar el botón de reset: introduce ruido humano en el timing; pasarás el postmortem debatiendo segundos.
  • Provocar kernel panic como única prueba: prueba recuperación ante crash, no pérdida de energía. Es otro modo de fallo.

Preparación del corte: cómo es la «buena higiene»

Inicia la carga. Deja que alcance estado estable. Haz snapshot. Registra estadísticas base. Luego corta la energía en una frontera conocida (por ejemplo, 30 segundos dentro de una carga sync).
La intención no es aleatoria. Lo aleatorio es para atacantes y balanceadores de carga.

Guion de diagnóstico rápido

Tras una prueba de crash—o un corte real—quieres respuestas rápido. Este es el camino mínimo para identificar el cuello de botella y el riesgo.
Hazlo en orden. Saltarte pasos es cómo conviertes un incidente menor en uno caro.

Primero: ¿se puede importar el pool limpiamente y qué piensa ZFS que pasó?

  • Ejecuta zpool import y zpool status -v tras la importación.
  • Busca dispositivos faltantes, pool suspendido o errores de checksum.
  • Decisión: Si el pool está DEGRADED o los errores son distintos de cero, trátalo como un incidente de integridad de datos, no como un problema de rendimiento.

Segundo: revisa logs del kernel por resets, timeouts y fallos de flush

  • Usa filtros de journalctl -b -k para nvme/sd/scsi/reset/timeout/flush.
  • Decisión: Fallos de flush o resets repetidos apuntan a hardware/firmware/controlador. No ajustes ZFS para «trabajar alrededor» de mentiras.

Tercero: determina si la latencia sync es el dolor (SLOG o pool principal)

  • Ejecuta carga sync (fio con fsync) y observa zpool iostat -v y iostat -x.
  • Decisión: Si el dispositivo logs está caliente y con alta latencia, el SLOG es el cuello de botella. Si los vdevs principales están calientes, el layout o discos limitan.

Cuarto: valida integridad con un scrub (no adivines)

  • Inicia zpool scrub, luego monitorea con zpool status.
  • Decisión: Cualquier error de checksum post-crash significa que tu cadena de durabilidad está rota. Escala antes de volver a ejecutar pruebas.

Quinto: prueba límites de durabilidad a nivel de aplicación

  • Compara snapshots o marcadores de la app (IDs de transacción, posiciones WAL, números de secuencia).
  • Decisión: Si la app perdió commits reconocidos, la pila de almacenamiento reconoció escrituras que no persistió realmente.

Tres mini-historias corporativas desde el campo

Mini-historia 1: El incidente causado por una suposición equivocada

Una empresa mediana migró un servicio interno crítico a ZFS. Buena decisión. También lo movieron a «NVMe rápido» para el SLOG.
La lógica era simple: NVMe es moderno, moderno es durable, y la especificación tiene palabras como «flush».

Sus exportaciones NFS estaban configuradas con semántica sync. El equipo de aplicaciones celebró: la latencia bajó, los dashboards se pusieron más verdes,
y todos decidieron en silencio que el problema de almacenamiento estaba resuelto para siempre. Entonces ocurrió un evento de energía en el edificio—breve, agudo y real.
Los hosts se reiniciaron. Los pools se importaron. No había errores obvios.

Dos días después, empezó la rareza: un puñado de archivos tenía versiones antiguas. No faltaban. No estaban obviamente corruptos. Simplemente… viajaron en el tiempo.
Se detectó porque un ingeniero comparó artefactos generados con un manifiesto de build que hacía fsync al terminar.
El equipo de almacenamiento sospechó inicialmente un bug de la app. El equipo de apps sospechó del almacenamiento. Todos se sospecharon entre sí, lo cual es normal.

El avance vino de una línea de log aburrida: fallos ocasionales de cache flush y resets de controlador durante ráfagas intensas de sync.
El «NVMe rápido» era un dispositivo de consumo con caché de escritura volátil y sin protección real ante pérdida de energía.
Podía aceptar escrituras sync rápidamente y luego perderlas cuando la energía desaparecía. ZFS hizo lo que le dijeron. El dispositivo hizo lo que quiso.

Reemplazaron el SLOG por un dispositivo empresarial con PLP y repitieron las pruebas de corte de energía. El viaje en el tiempo paró.
La lección no fue «NVMe malo». Fue «no asumas durabilidad porque el marketing dijo ‘data center’ en algún lado de la caja».

Mini-historia 2: La optimización que salió mal

Otra organización tenía una carga de escrituras intensa y odiaba la latencia sync. Alguien propuso un ajuste «pragmático»:
poner sync=disabled en el dataset porque «nuestra app está replicada de todos modos».
No fue un villano con bigote. Fue un ingeniero bienintencionado tratando de alcanzar un SLO de latencia con presupuesto limitado.

La mejora de rendimiento fue dramática. Tan dramática que el cambio se propagó de un dataset a varios otros.
Sobrevivió varios trimestres, lo que significa que sobrevivió varias capas de revisión, porque nadie quiere ser la persona que reintroduce latencia.
Tenían UPS. Tenían PSUs redundantes. Tenían fe.

Entonces llegó una actualización de firmware de almacenamiento y una secuencia de reboots de hosts. Un host cayó en medio de una ráfaga de escrituras.
La replicación no los salvó porque el stream de replicación también provenía de la misma realidad con «sync-disabled».
Perdieron un fragmento de transacciones reconocidas. No todas. Lo suficiente para causar desajustes irreconciliables.

El postmortem fue duro pero útil. Habían optimizado la capa equivocada: eliminaron el contrato de honestidad del sistema de archivos en lugar de
invertir en un SLOG adecuado y asegurarse de que la semántica de durabilidad de la aplicación coincidiera con la realidad.
La solución no fue solo volver a poner sync. Fue auditar cada dataset, alinear semánticas de las apps y volver a probar con inyección de fallos.

El remate seco: cumplieron el SLO de latencia hasta que tuvieron que explicar a finanzas por qué desaparecieron facturas, que es más difícil de graficar.

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

Una tercera empresa usaba ZFS para almacenamiento de VM. Nada fancy. Espejos para vdevs, un SLOG espejado con PLP y un calendario mensual de scrub.
También tenían un ritual: cada trimestre, ejecutar una prueba controlada de corte de energía en staging después de ciclos de parcheo.
No era trabajo emocionante. Nadie fue promovido por ello. Así es como sabes que era la práctica correcta.

Un trimestre, tras una actualización del kernel, su prueba de corte en staging provocó un retraso en la importación del pool y un puñado de errores de checksum en el scrub.
No era catastrófico, pero inaceptable. Como esto era staging, tuvieron tiempo. Revirtieron, hicieron bisect y descubrieron
una interacción driver/firmware que causaba rarezas ocasionales en NCQ/flush en un subconjunto de SSD SATA bajo alta presión sync.

Cambiaron el firmware de los discos y ajustaron una configuración del controlador. La prueba volvió a pasar. Luego parchearon producción.
Un mes después, un corte real de energía afectó a un rack por un evento eléctrico ascendente. Producción se recuperó limpiamente.

Nadie fuera de infra lo notó. Ese es el punto. La prueba trimestral «aburrida» convirtió un apagón sorpresa en un reboot rutinario.
La reputación del equipo se construyó con la ausencia de incidentes visibles, que es el único tipo honesto.

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

1) Síntoma: cargas sync son rápidas y luego tras el crash faltan datos

Causa raíz: caché de escritura volátil reconoció escrituras sin persistencia (sin PLP), o flush/FUA no se honró a través del camino del controlador.

Solución: usa SLOG con PLP; verifica que el controlador esté en modo IT/HBA; actualiza firmware; confirma que los comandos de flush aparecen como exitosos en logs; vuelve a probar con sync=always.

2) Síntoma: el pool se importa pero el scrub encuentra errores de checksum tras cada prueba de corte

Causa raíz: la caché de escritura del dispositivo miente o hardware inestable (resets de controlador, cable/backplane malo), o el corte causa escrituras parciales que la redundancia no puede reparar.

Solución: inspecciona journalctl por resets/timeouts; reemplaza componentes dudosos; desactiva la caché de escritura para comparar en pruebas; valida la entrega de energía y la redundancia de PSU.

3) Síntoma: la importación cuelga mucho tiempo tras el crash

Causa raíz: retardos en enumeración de dispositivos, timeouts de multipath, o un dispositivo de log lento/no responde (problemas de SLOG pueden detener la reproducción).

Solución: revisa logs de arranque del kernel por timeouts de dispositivos; confirma que el SLOG está presente y sano; considera eliminar el dispositivo de log defectuoso (en laboratorio) solo tras análisis cuidadoso.

4) Síntoma: latencia sync terrible, pero SLOG parece inactivo

Causa raíz: la carga no es realmente sync (no hay fsync/O_DSYNC), o sync y logbias de dataset no son lo que piensas, o las opciones de export/mount NFS difieren.

Solución: genera una carga sync conocida (fio con fsync); verifica propiedades del dataset; valida ajustes de export/mount NFS; observa zpool iostat -v.

5) Síntoma: tras el crash, las aplicaciones se quejan pero ZFS dice “No known data errors”

Causa raíz: las expectativas de durabilidad a nivel de aplicación exceden lo que realmente solicitaron (writes async, falta de fsync), o bug de la aplicación en el orden de operaciones.

Solución: instrumenta la app: confirma puntos de fsync, comportamiento WAL o marcadores de commit; usa diffs de snapshot alrededor de marcadores conocidos; no culpes a ZFS hasta probar que la app lo pidió.

6) Síntoma: el scrub tarda una eternidad o causa colapso de rendimiento tras un crash

Causa raíz: el pool ya está cerca de saturación, o un dispositivo lento lastra el vdev; el evento de energía expuso un disco débil.

Solución: identifica dispositivos lentos vía iostat -x y zpool iostat -v; reemplaza rezagados; considera añadir vdevs (no solo «discos más grandes») si necesitas IOPS.

7) Síntoma: “zpool status” muestra errores de escritura pero no errores de checksum

Causa raíz: problemas a nivel de transporte (cables, HBA, expander) o timeouts de dispositivo en lugar de corrupción.

Solución: revisa SMART/NVMe error logs, mensajes del kernel y cableado; no persigas checksums cuando el bus está en llamas.

Listas de verificación / plan paso a paso

Paso a paso: ciclo seguro de prueba de pérdida de energía (reproducible)

  1. Elige los dataset(s) objetivo: prueba lo que importa, no todo el pool por defecto.
  2. Salud base del pool: zpool status -v debe estar limpio; preferible scrub reciente.
  3. Registra la configuración: captura zpool get all y zfs get all para los datasets relevantes; guarda salidas con timestamps.
  4. Habilita recolección de evidencia: asegúrate de journal persistente, syslog remoto o captura de consola fuera de banda.
  5. Crea un marcador: un archivo pequeño o ID de transacción de app escrito con fsync; snapshot @pre_cut.
  6. Inicia la carga: usa fio con fsync para comportamiento sync; opcionalmente ejecuta una segunda carga mixta en paralelo.
  7. Observa estado estable: recolecta 60–120 segundos de zpool iostat -v y iostat -x.
  8. Corta la energía: vía PDU/IPMI/relé; registra la hora exacta y el método.
  9. Restaura la energía: arranca; evita importar read-write automáticamente si puedes.
  10. Importa solo lectura primero: inspecciona salida de zpool import; luego importa normalmente si está sano.
  11. Valida marcadores: comprueba archivos marcador, diffs de snapshot y consistencia a nivel de app.
  12. Scrub: ejecuta zpool scrub, verifica cero errores.
  13. Documenta: registra pasar/fallar y qué cambió. Si no puedes explicarlo, no lo probaste.

Checklist: condiciones de “no proceder”

  • Errores de checksum existentes antes de la prueba.
  • Fallos de flush o resets de dispositivo en logs del kernel durante operación normal.
  • Dispositivo SLOG sin PLP verificado usado para cargas sync críticas.
  • Pool ya funcionando a alta utilización donde los resultados estarán dominados por sobrecarga.

Checklist: evidencia a capturar en cada ejecución

  • zpool status -v antes y después.
  • zfs get para sync/logbias/recordsize/compression de los datasets probados.
  • zpool iostat -v durante la carga.
  • Logs del kernel alrededor del reboot: resets de controlador, timeouts, fallos de flush.
  • Diff de snapshot alrededor de un marcador conocido.
  • Resultado del scrub tras la recuperación.

Preguntas frecuentes

1) ¿ZFS garantiza cero pérdida de datos ante fallo de energía?

ZFS garantiza la consistencia en disco de sus estructuras y protege la integridad de datos con checksums.
No garantiza que las escrituras async sobrevivan, y no puede obligar a hardware deshonesto a persistir datos que afirmó haber escrito.

2) Si mi pool se importa limpiamente tras un corte de energía, ¿estoy a salvo?

Estás más seguro que muchos sistemas de archivos, pero «se importa limpiamente» no es lo mismo que «las escrituras sync fueron durables».
Aún necesitas marcadores a nivel de aplicación y un scrub para validar integridad y límites.

3) ¿Es necesario un SLOG para seguridad ante pérdida de energía?

No. Un SLOG sirve principalmente para rendimiento de escrituras síncronas. La seguridad proviene de semánticas sync correctas y dispositivos honestos.
Un mal SLOG puede reducir activamente la seguridad al concentrar escrituras sync en un dispositivo que miente bajo pérdida de energía.

4) ¿Debo poner sync=always en todas partes?

Para probar durabilidad y exponer mentiras de hardware: sí, en los datasets bajo prueba. En producción: solo si tu presupuesto de latencia lo permite.
De lo contrario, mantén sync=standard y asegúrate de que tus aplicaciones soliciten fsync cuando sea necesario.

5) ¿Cómo sé si mi SSD tiene protección ante pérdida de energía?

Las especificaciones del proveedor ayudan, pero la respuesta fiable es testear más usar dispositivos empresariales conocidos por PLP.
Si no puedes verificar PLP, no pongas ese dispositivo en rol SLOG para cargas críticas de durabilidad.

6) ¿Desenchufar el cable es la mejor prueba?

Es la más literal, pero no siempre la más reproducible. Un PDU conmutado o un corte por relé es mejor para timing consistente.
Usa el método que te dé resultados reproducibles y logs limpios.

7) ¿Cuál es la diferencia entre una prueba de crash y una prueba de pérdida de energía?

Una prueba de crash (kernel panic, reboot) detiene el SO pero a menudo deja la alimentación de los dispositivos intacta, por lo que las cachés pueden vaciarse.
Una prueba de pérdida de energía quita la energía para que las cachés volátiles no tengan una salida ordenada. Son verdades distintas.

8) ¿Puede un UPS reemplazar las pruebas de pérdida de energía?

No. Un UPS reduce la frecuencia y gana tiempo, pero no arregla bugs de firmware, mentiras de flush o eventos parciales de energía.
Además: las baterías envejecen y las ventanas de mantenimiento tienen su manera de «descubrirlo».

9) ¿Los layouts RAIDZ se comportan distinto ante cortes comparados con espejos?

La consistencia CoW se mantiene, pero operativamente los espejos suelen recuperarse más rápido y entregar mejor IOPS, lo que puede reducir
el tiempo de recuperación y el impacto del scrub. RAIDZ puede ser perfectamente seguro; también puede ser más lento bajo estrés.

10) Si veo errores de checksum tras un corte, ¿mis datos están permanentemente corrompidos?

No necesariamente. Con redundancia, ZFS a menudo puede reparar. Pero errores de checksum tras una prueba controlada son una alarma muy sonora.
Trátalo como una señal de que tu cadena de durabilidad está comprometida y arregla la causa raíz antes de confiar en el sistema.

Conclusión: pasos prácticos siguientes

Las pruebas de pérdida de energía no se tratan de valentía. Se trata de no delegar tu confianza en suposiciones.
ZFS te da primitivos excelentes—consistencia CoW, checksums, scrubs y visibilidad clara del estado del pool.
Tu trabajo es asegurarte de que la capa de hardware no sabotee esas garantías.

Pasos siguientes que realmente hacen la diferencia:

  • Levanta un laboratorio que coincida con la clase de almacenamiento y la topología de producción.
  • Ejecuta un ciclo de prueba scriptado con sync=always en el dataset objetivo y una carga real que haga fsync.
  • Corta la energía de forma reproducible, importa primero readonly y luego valida con diffs de snapshot y un scrub.
  • Si usas SLOG, trátalo como un componente de durabilidad: PLP-capable, monitorizado y probado.
  • Convierte los resultados en un runbook: procedimiento de importación, comprobaciones de logs, validación de integridad y criterios de «detener la línea».

El mejor resultado es aburrido: tu prueba se vuelve rutina, las gráficas lucen normales y nadie cuenta una historia sobre ti en un postmortem.
Ese es el tipo de fama que quieres.

← Anterior
Desastres con metal líquido: la mejora que acaba en factura de reparación
Siguiente →
Intel XeSS: cómo Intel entró en la lucha mediante software

Deja un comentario