ZFS tiene un pequeño regulador llamado sync que parece inocuo hasta que te arruina la semana —o te la salva. Si lo giras en una dirección, tu gráfico de latencia se calma, tus benchmarks se ven heroicos y tu host de VM de repente “se siente rápido”. Si lo giras en la otra, obtienes el tipo de garantías que a los auditores les encanta y con las que los operadores duermen tranquilos. La trampa es que ambos resultados pueden ser verdaderos al mismo tiempo, dependiendo de lo que entiendas por “escrito en disco”.
Esto no es una lección moral sobre “nunca deshabilitar la seguridad”. Es una guía de campo para quienes gestionan producción: qué hace realmente sync, por qué puede estrangular un sistema, cómo ayudan los dispositivos SLOG (y cómo no), y cómo elegir ajustes que coincidan con las promesas de tu carga de trabajo. El objetivo es simple: ser rápido sin convertir accidentalmente tu almacenamiento en una sugerencia educada.
Qué significa realmente “sync” en ZFS (y qué no)
En ZFS, la propiedad de dataset sync controla cómo ZFS trata las solicitudes de escritura síncronas. Esa redacción importa. ZFS no decide ser síncrono al azar; es el llamador quien lo solicita.
Una escritura síncrona es aquella en la que la aplicación (o el protocolo) dice: “No informes éxito hasta que estos datos estén en almacenamiento estable.” Almacenamiento estable es aquel que sobrevivirá a un fallo y pérdida de energía súbita. No “está en RAM”, no “el controlador dice que está en caché”, no “la caché de páginas de Linux se siente optimista hoy”. Estable.
ZFS implementa esta garantía comprometiendo la intención de escritura en el ZIL (ZFS Intent Log). Si tienes un dispositivo de log separado (un SLOG), ZFS puede colocar esos datos del ZIL en un dispositivo de baja latencia para acelerar las escrituras síncronas. Más tarde, ZFS incorpora esos cambios en la pool principal como parte de los commits normales de grupo de transacciones (TXG).
Dos implicaciones inmediatas:
syncno hace que tu sistema sea “seguro” por sí mismo. Define lo que ZFS hará cuando el llamador solicite semántica síncrona. Si el llamador nunca lo pide (o está mal configurado), aún puedes perder datos en una pérdida de energía.syncpuede absolutamente hacerte más rápido. Pero la aceleración a menudo proviene de eliminar garantías de durabilidad. Por eso este ajuste es famoso: es uno de los pocos interruptores donde rendimiento y seguridad están directamente acoplados.
Aquí va el primer chiste, porque lo necesitaremos más adelante: Desactivar sync es como quitar el detector de humo porque pita cuando quemas tostadas —pacífico hasta que deja de serlo.
Datos interesantes y contexto histórico
Un poco de contexto hace que el comportamiento parezca menos magia y más ingeniería:
- ZFS nació en Sun Microsystems a principios de los 2000, diseñado para integridad de extremo a extremo y flujos de trabajo administrativos sensatos a escala —cuando “usar RAID y esperar” todavía era un plan popular.
- El ZIL no es una caché de escritura para todo. Existe específicamente para satisfacer la semántica síncrona; la mayoría de las escrituras asíncronas nunca lo tocan.
- Un SLOG no es “una caché SSD”. Es un dispositivo dedicado para almacenar rápidamente el ZIL. No acelera lecturas y no acelera automáticamente todas las escrituras.
- Muchos arrays de almacenamiento empresariales vendían “caché de escritura respaldada por NVRAM”. Como ingrediente mágico que aceleraba escrituras síncronas. En el mundo ZFS, un SLOG protegido contra pérdida de energía cumple un papel similar, pero solo para el ZIL.
- NFS tiene reputación de “lentitud misteriosa”. En gran parte porque tiende a solicitar semánticas síncronas para muchas operaciones. Si el almacenamiento no puede comprometer sync rápidamente, el protocolo de red parece culpable.
- Las bases de datos suelen usar
fsync()como su línea en la arena. PostgreSQL, MySQL/InnoDB y otras dependen de llamadas explícitas de flush para mantener la durabilidad de transacciones. - Las pilas de virtualización amplifican el dolor. Una VM que hace escrituras síncronas se convierte en un host haciendo escrituras síncronas, multiplicado por cada invitado. Un inquilino ruidoso y sensible a la durabilidad puede dominar la latencia.
- Los errores de “orden de escritura” solían ser comunes en sistemas de ficheros y controladoras. El diseño de ZFS (copy-on-write + checksums) no elimina la necesidad de sync, pero hace que la corrupción sea más fácil de detectar y más difícil de crear de forma silenciosa.
Los tres modos: standard, always, disabled
La propiedad sync es por dataset (sistema de ficheros o zvol). Tiene tres valores relevantes:
1) sync=standard (el valor por defecto)
Esto significa: respetar la petición del llamador. Si la aplicación emite escrituras síncronas o llama a fsync()/fdatasync(), ZFS compromete la intención en el ZIL y solo entonces informa éxito.
Operativamente: este es el modo de “hacer lo que la app pidió”. Si el rendimiento es malo aquí, es una señal real: tu carga de trabajo está pidiendo durabilidad y tu ruta de almacenamiento no puede entregarla rápidamente.
2) sync=always
Esto fuerza que todas las escrituras sean tratadas como síncronas, incluso si el llamador no lo pidió.
Cuándo usarlo: cuando no confías en la carga de trabajo o el middleware para solicitar semántica sync correctamente, pero aún necesitas comportamiento durable. A veces se usa en exportaciones NFS para cargas que son notoriamente mentirosas sobre sus necesidades de durabilidad, o en ciertas imágenes de VM donde quieres garantizar la seguridad “a nivel de host” independientemente de la configuración del invitado.
Compensación: si no tienes un SLOG rápido y seguro, puedes convertir una pool decente en un museo de latencias.
3) sync=disabled
Esto indica a ZFS que trate las solicitudes síncronas como asíncronas. Aceptará escrituras sync antes de que realmente estén en almacenamiento estable.
Cuándo usarlo: para datos que puedes permitirte perder en un fallo (espacio temporal, cachés, intermediarios analíticos transitorios), o en arquitecturas muy específicas donde la durabilidad se gestiona en otro lugar (por ejemplo, la app tiene su propio log de commits replicado y aceptas explícitamente la pérdida local).
Riesgo: cualquier aplicación que crea que obtuvo un commit durable puede estar equivocada. Eso incluye bases de datos. Incluye sistemas de ficheros de VM. Incluye clientes NFS que realizan escrituras seguras.
Segundo chiste, y luego volvemos a lo serio: Poner sync=disabled en un volumen de base de datos es como poner “probablemente” en medio de tu libro de contabilidad—los auditores no lo encuentran encantador.
Quién solicita escrituras síncronas: apps, bases de datos, NFS, hipervisores
La mayor parte del drama de rendimiento alrededor de sync proviene de no entender quién solicita la semántica síncrona y por qué.
Bases de datos
Las bases de datos suelen convertir “transacción comprometida” en un fsync() sobre un write-ahead log (WAL) o redo log. El log es algo secuencial, pero el requisito es estricto: cuando la base de datos dice commit, el log debe sobrevivir a un fallo. Si ZFS tarda 5 ms en satisfacer eso, la latencia de commit de la base de datos es al menos 5 ms, incluso si todo lo demás es rápido.
Algunas bases de datos pueden relajar esto (por ejemplo, modos de “async commit”), pero eso es una decisión a nivel de aplicación. El almacenamiento no debería cambiar silenciosamente el significado de “commit” sin que lo sepas.
NFS
Los clientes NFS a menudo solicitan escrituras estables, y los servidores deben respetarlas. En servidores NFS respaldados por ZFS, esto significa que la ruta ZIL/SLOG se convierte en el camino caliente. Puedes tener una pool rapidísima para throughput asíncrono y aún así padecer una latencia terrible en NFS si los commits síncronos son lentos.
Virtualización (zvols, imágenes de VM)
Los hipervisores y los sistemas de ficheros invitados pueden generar una cantidad sorprendente de operaciones síncronas —actualizaciones de metadatos, commits de journal, barreras, flushes. Un único ajuste “seguro” en un invitado puede traducirse en flushes constantes en el host, y esos flushes se mapean directamente a la ruta ZIL.
Por eso verás la queja clásica: “Mi pool SSD es rápida pero mi host de VM se siente lento”. A menudo la pool está bien en escrituras masivas, pero la latencia de escritura síncrona es pobre.
La ruta de escritura síncrona en ZFS: TXGs, ZIL, SLOG y qué llega realmente al almacenamiento estable
ZFS escribe datos en grupos de transacciones (TXGs). Los cambios se acumulan en memoria y periódicamente se comprometen a disco en lotes. Ese batching es la razón por la que ZFS puede ser eficiente: convierte muchas escrituras aleatorias pequeñas en IO más ordenado.
Las solicitudes síncronas complican esto. La aplicación no puede esperar al siguiente commit de TXG (que podría tardar segundos). Así que ZFS usa el ZIL: un log de intención que registra suficiente información para reproducir la operación tras un fallo. El ZIL se escribe rápido, luego la escritura síncrona puede ser reconocida. Más tarde, cuando el TXG commit se ejecuta, los datos reales aterrizan en sus estructuras finales en disco y las entradas del ZIL quedan obsoletas.
Verdad operativa clave: el ZIL solo se lee durante la recuperación tras un fallo. En operación normal, se escribe, no se lee. Un dispositivo SLOG no está ahí para mejorar lecturas en estado estable; está ahí para aceptar escrituras pequeñas, sensibles a la latencia, rápida y seguramente.
Otra verdad: si no tienes un SLOG separado, los bloques del ZIL viven en la pool principal. Eso puede estar bien en pools muy rápidas y de baja latencia —especialmente all-flash con protección contra pérdida de energía. En pools más lentas (discos giratorios, o SSDs con mala latencia bajo escrituras síncronas), puede ser brutal.
Realidades del SLOG: lo que acelera y lo que no puede
La gente compra un SLOG por la misma razón por la que compra mejor café: quiere que las mañanas duelan menos. Pero un SLOG no es un dispositivo milagroso. Acelera una cosa: la latencia de los reconocimientos de escrituras síncronas.
Lo que ayuda un SLOG
- Cargas NFS intensivas en sync que están limitadas por la latencia de commit.
- Bases de datos que están acotadas por la latencia de commit (y donde la BD insiste en commits durables).
- Clusters de VM donde los flushes son frecuentes y bloqueantes.
Lo que no ayuda un SLOG
- Latencia de lectura o IOPS de lectura (eso es territorio de ARC/L2ARC, y aun eso tiene matices).
- Throughput de escrituras asíncronas masivas (eso recae principalmente en los vdevs principales y el comportamiento de TXG).
- Cargas que emiten pocas escrituras síncronas; no lo notarás.
Qué hace a un buen SLOG
Dos propiedades: baja latencia bajo escrituras síncronas y protección contra pérdida de energía. Quieres que el dispositivo reconozca escrituras solo cuando los datos estén realmente seguros. Los SSDs de consumo pueden ser rápidos pero mentir sobre la durabilidad de flushes. Los SSDs empresariales (o dispositivos diseñados para logging de escritura) suelen rendir mejor aquí porque tienen capacitores y firmware diseñados para esta tarea.
El tamaño no es lo principal. El SLOG solo necesita almacenar una pequeña ventana de transacciones síncronas pendientes —típicamente segundos, no todo el dataset. Latencia, no capacidad, es lo que estás comprando.
Replica del SLOG
Si un dispositivo SLOG falla, la pool puede continuar (ZFS puede retroceder), pero corres el riesgo de perder las últimas transacciones síncronas reconocidas si el dispositivo de log muere de forma inapropiada. En la práctica, muchos equipos espejan el SLOG por una paranoia que en realidad está justificada —especialmente en almacenamiento compartido para VMs o bases de datos.
Tres mini-historias del mundo corporativo (relatos de guerra realistas)
Mini-historia #1: Un incidente causado por una suposición incorrecta
El equipo de almacenamiento heredó un cluster NFS respaldado por ZFS que alimentaba una granja de compilaciones y un puñado de servicios internos “pequeños”. Apareció un servicio nuevo: un sistema de colas con estado que escribía mensajes diminutos constantemente y dependía de commits síncronos para su corrección. Todos asumieron que sería “como las otras apps”, porque vivía en el mismo clúster de Kubernetes y usaba la misma clase NFS.
No lo era. El servicio de colas forzaba escrituras estables, y la latencia pasó de “bien” a “¿qué está pasando?” de la noche a la mañana. Los jobs de build empezaron a agotar tiempos en lugares que no tenían sentido. El equipo de red fue llamado porque los gráficos de latencia de NFS parecían pérdida de paquetes. El SRE de guardia reinició demonios, luego nodos, luego cuestionó la realidad.
Tras unas horas de whack-a-mole, alguien ejecutó zpool iostat -v 1 y notó un dispositivo pequeño (el único SLOG) atascado en altas operaciones de escritura con latencia fea, mientras la pool principal tenía margen. El SLOG era un viejo SSD SATA de consumo —rápido en benchmarks, terrible en escrituras síncronas sostenidas y probablemente no respetando las semánticas de flush de forma fiable. Se había convertido en el cuello de botella y la fuente de la latencia de cola.
La solución fue mundana: reemplazar el SLOG por un dispositivo adecuado de baja latencia y protegido contra pérdida de energía y espejarlo. El rendimiento se estabilizó inmediatamente. El postmortem no fue sobre culpas; fue sobre suposiciones. El entorno cambió de “artefactos de build mayoritariamente asíncronos” a “carga de trabajo que exige sync”, y los ajustes de almacenamiento no evolucionaron con ello.
Mini-historia #2: Una optimización que salió mal
Un equipo de plataforma de virtualización tenía una pool ZFS alojando discos de VM (zvols). Un clúster nuevo entró en producción y, bajo carga, rindió peor que el antiguo —aunque el hardware era más nuevo. Alguien encontró un post que sugería sync=disabled para “ganancias de rendimiento masivas” en almacenamiento de VM. Lo probaron en un host de staging con IO sintético y obtuvieron números preciosos.
Así que lo desplegaron gradualmente. La ganancia de rendimiento fue real: la latencia de commit se desplomó, el IO wait bajó, los inquilinos dejaron de quejarse. Se sentía como trabajo heroico —hasta el primer evento real de corte de energía. No fue un apagón catastrófico, solo un corte en un rack durante mantenimiento. Los hosts se reiniciaron, el almacenamiento se importó correctamente y la mayoría de las VMs arrancaron bien.
Pero algunas no. Los sistemas de ficheros quedaron corruptos de maneras que el journaling no arregló. Una VM de base de datos arrancó pero le faltaban los últimos minutos de transacciones comprometidas —transacciones que la app había reconocido hacia servicios upstream. La opción “rápida” había cambiado silenciosamente el significado de “commit” dentro de esos invitados. Eso provocó corrupción lógica: no bloques rotos, sino verdad de negocio rota.
El rollback fue sencillo. La limpieza no lo fue. Tuvieron que reconciliar pedidos perdidos y reprocesar eventos desde logs upstream. En el informe final, la lección no fue “nunca afines ZFS”. Fue: si deshabilitas sync en almacenamiento de VM, estás haciendo una promesa de durabilidad en nombre de cada invitado, y más vale que tu arquitectura la tolere. Si no, tu benchmark es solo un truco de confianza.
Mini-historia #3: Una práctica aburrida pero correcta que salvó el día
Un equipo de servicios financieros operaba un par de servidores ZFS exportando NFS a un clúster de aplicaciones. Tenían una costumbre que parecía tediosa: antes de cada pico trimestral de tráfico, ejecutaban un “simulacro de durabilidad”. Era simple: verificar propiedades sync de datasets, comprobar la salud del SLOG, verificar que los flushes se comportaban como se esperaba y ejecutar una simulación controlada de pérdida de energía en un laboratorio con la misma clase de hardware.
Los ingenieros se quejaban de que era culto al cargo. Nada fallaba nunca en el simulacro. Ese era el punto. Era el equivalente en almacenamiento a revisar el paracaídas estando todavía en tierra.
Entonces tuvieron un incidente real: un bug de firmware hizo que uno de los dispositivos de log empezara a reportar salud mientras silenciosamente timoutaba bajo ciertos depths de cola. ZFS no lo marcó inmediatamente como faulty, pero la latencia se disparó cuando la carga entró en una fase intensa en sync. Porque el equipo tenía números base de latencia de simulacros anteriores, detectaron la desviación rápido y no perdieron una noche culpando a NFS, la red o la aplicación.
Reemplazaron el par de SLOG durante una ventana de mantenimiento y el clúster volvió a la normalidad. Sin pérdida de datos, sin misterio. Ingeniería aburrida, que es lo que quieres cuando hay dinero en juego.
Tareas prácticas: comandos, qué observar y cómo interpretarlos
Los comandos abajo asumen un entorno OpenZFS típico en Linux. Ajusta nombres de pool/dataset para que coincidan con tu sistema. Cada tarea incluye qué significa la salida en la práctica.
Task 1: Encuentra los ajustes sync de tus datasets (y la herencia)
cr0x@server:~$ zfs get -r -o name,property,value,source sync tank
NAME PROPERTY VALUE SOURCE
tank sync standard default
tank/vm sync disabled local
tank/vm/critical sync standard inherited from tank
tank/nfs sync standard local
Interpretación: No mires solo la raíz del pool. Un único dataset “útil” con sync=disabled puede esconderse en tu jerarquía de almacenamiento para VMs. La columna source es tu detector de verdad: local vs inherited vs default.
Task 2: Comprueba si tienes un SLOG (y qué es)
cr0x@server:~$ zpool status -v tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:18:42 with 0 errors on Mon Dec 16 03:10:05 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
logs
mirror-1 ONLINE 0 0 0
nvme2n1 ONLINE 0 0 0
nvme3n1 ONLINE 0 0 0
errors: No known data errors
Interpretación: La sección logs es tu SLOG. Si falta, tu ZIL vive en los vdevs principales. Si es un solo dispositivo (no espejado), decide si toleras ese perfil de riesgo.
Task 3: Observa la latencia por vdev bajo carga
cr0x@server:~$ zpool iostat -v tank 1
capacity operations bandwidth
pool alloc free read write read write
-------------------------- ----- ----- ----- ----- ----- -----
tank 1.20T 2.40T 110 980 8.5M 72.1M
mirror-0 1.20T 2.40T 110 220 8.5M 15.4M
nvme0n1 - - 60 120 4.2M 7.8M
nvme1n1 - - 50 100 4.3M 7.6M
logs - - - -
mirror-1 - - 0 760 0K 56.7M
nvme2n1 - - 0 380 0K 28.4M
nvme3n1 - - 0 380 0K 28.3M
-------------------------- ----- ----- ----- ----- ----- -----
Interpretación: Si los dispositivos de log llevan la mayor parte de las operaciones de escritura mientras los vdevs principales están calmados, tu carga es intensiva en sync. Si el rendimiento es malo, el SLOG es el primer sospechoso.
Task 4: Confirma que ZFS ve el ashift correcto (alineación del tamaño de sector)
cr0x@server:~$ zdb -C tank | grep -E "ashift|vdev_tree" -n | head
52: vdev_tree:
83: ashift: 12
121: ashift: 12
Interpretación: ashift=12 significa sectores de 4K. Una desalineación (ashift demasiado pequeño) puede crear amplificación de escritura y latencia fea, incluyendo para tráfico sync.
Task 5: Comprueba la salud del pool ZFS y contadores de errores
cr0x@server:~$ zpool status tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:18:42 with 0 errors on Mon Dec 16 03:10:05 2025
config:
NAME STATE READ WRITE CKSUM
tank ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
nvme0n1 ONLINE 0 0 0
nvme1n1 ONLINE 0 0 0
errors: No known data errors
Interpretación: Depurar rendimiento sync en un pool con errores latentes es como ajustar un motor con una bomba de aceite rota. Arregla la integridad primero.
Task 6: Identificar llamadores intensivos en sync observando actividad de fsync (Linux)
cr0x@server:~$ sudo perf trace -e fsync,fdatasync,openat -a --duration 10
0.000 ( 0.008 ms): postgres/1931 fdatasync(fd: 7) = 0
0.012 ( 0.006 ms): postgres/1931 fdatasync(fd: 7) = 0
0.030 ( 0.010 ms): qemu-kvm/2210 fsync(fd: 31) = 0
0.044 ( 0.009 ms): qemu-kvm/2210 fsync(fd: 31) = 0
Interpretación: Buscas frecuencia. Si ves miles de llamadas sync por segundo, tu presupuesto de latencia se está gastando en durabilidad.
Task 7: Medir la latencia de escrituras sync con fio (directo, parecido a sync)
cr0x@server:~$ fio --name=syncwrite --filename=/tank/test/syncwrite.bin \
--rw=write --bs=4k --iodepth=1 --numjobs=1 --direct=1 \
--fsync=1 --size=1G --runtime=30 --time_based=1
syncwrite: (g=0): rw=write, bs=4K-4K, ioengine=psync, iodepth=1
...
write: IOPS=6200, BW=24.2MiB/s (25.4MB/s)(726MiB/30001msec)
clat (usec): min=90, max=9200, avg=160.4, stdev=210.7
Interpretación: --fsync=1 fuerza un flush en cada escritura, aproximando el peor comportamiento de commit. La latencia media es agradable; el max y la cola son lo que sienten tus usuarios.
Task 8: Comparar comportamiento con sync=disabled en un dataset desechable
cr0x@server:~$ sudo zfs create tank/test_nodur
cr0x@server:~$ sudo zfs set sync=disabled tank/test_nodur
cr0x@server:~$ fio --name=syncwrite --filename=/tank/test_nodur/syncwrite.bin \
--rw=write --bs=4k --iodepth=1 --numjobs=1 --direct=1 \
--fsync=1 --size=1G --runtime=15 --time_based=1
...
write: IOPS=42000, BW=164MiB/s (172MB/s)(2462MiB/15001msec)
clat (usec): min=18, max=480, avg=22.7, stdev=7.1
Interpretación: Este delta demuestra exactamente lo que estás sacrificando: reconocimiento durable. Trata este resultado como herramienta diagnóstica, no como “solución”. Si la única forma de ser rápido es mentir, la solución real es mejorar la ruta sync (frecuentemente SLOG).
Task 9: Inspeccionar si los datasets usan zvols (común en almacenamiento VM)
cr0x@server:~$ zfs list -t volume -o name,volsize,volblocksize,sync,logbias
NAME VOLSIZE VOLBLOCKSIZE SYNC LOGBIAS
tank/vm-001 120G 16K standard latency
tank/vm-002 200G 16K disabled latency
Interpretación: Los zvols a menudo soportan patrones IO de VM. Observa cualquier sync=disabled sorprendente. También fíjate en volblocksize —influye en la amplificación de IO y latencia.
Task 10: Comprobar logbias (preferencia latencia vs throughput)
cr0x@server:~$ zfs get -r logbias tank/vm
NAME PROPERTY VALUE SOURCE
tank/vm logbias latency default
Interpretación: logbias=latency fomenta el uso del dispositivo de log para escrituras sync. throughput puede reducir el uso del log en algunos casos. Esto no sustituye un sync correcto, pero puede influir en el comportamiento para ciertas cargas.
Task 11: Confirmar compresión y recordsize (pueden cambiar la historia sync indirectamente)
cr0x@server:~$ zfs get compression,recordsize tank/nfs
NAME PROPERTY VALUE SOURCE
tank/nfs compression lz4 local
tank/nfs recordsize 128K default
Interpretación: La compresión puede reducir IO físico (a menudo bueno), pero aumenta trabajo CPU. Si tu problema de “sync lento” es realmente saturación CPU durante commits TXG, perseguir otra cosa te hará perder tiempo a menos que midas.
Task 12: Comprobar presión CPU en tiempo real y IO wait durante tormentas sync
cr0x@server:~$ vmstat 1 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 0 712344 89244 3821000 0 0 8 420 980 1900 12 6 78 4 0
5 3 0 701112 89244 3818200 0 0 0 8200 1200 2400 10 7 55 28 0
3 2 0 700980 89244 3818500 0 0 0 7900 1180 2300 11 7 56 26 0
Interpretación: Un aumento de wa (IO wait) durante periodos intensos en sync sugiere que la ruta de almacenamiento está bloqueando al CPU. Si wa es bajo pero la latencia es alta, podrías estar enfrentando colas, comportamiento de flush de dispositivos o un dispositivo de log saturado.
Task 13: Detectar sistemas de ficheros en red que fuerzan semántica sync (ángulo servidor NFS)
cr0x@server:~$ sudo nfsstat -s
Server rpc stats:
calls badcalls badfmt badauth badclnt
18233990 0 0 0 0
Server nfs v4:
null compound
0 11239821
Server nfs v3:
null getattr setattr lookup access
0 226001 8402 110240 90412
commit write create mkdir remove
340882 901220 4800 220 1900
Interpretación: Alta actividad NFS commit es una pista: los clientes exigen semánticas de almacenamiento estable. Si los commits son frecuentes y lentos, tu ruta ZIL/SLOG importa más que tu throughput masivo.
Task 14: Verificar que los dispositivos de log realmente están haciendo trabajo (o no)
cr0x@server:~$ iostat -x 1 5 | egrep 'nvme2n1|nvme3n1|nvme0n1'
nvme2n1 0.00 740.00 0.00 56000.00 0.00 74.20 0.02 0.35 3.10 0.20 74.9
nvme3n1 0.00 735.00 0.00 55800.00 0.00 73.80 0.02 0.34 3.00 0.19 75.1
nvme0n1 55.00 120.00 8200.00 15400.00 3.40 15.30 0.10 0.80 2.10 0.40 25.0
Interpretación: Si los dispositivos de log muestran altas tasas de escritura y alta utilización, están en el camino caliente. Si muestran actividad casi nula bajo una carga intensiva en sync, o bien la carga no es realmente sync, o el dataset no está en standard/always, o el sistema está configurado diferente a lo que crees.
Guía rápida de diagnóstico (qué comprobar primero, segundo, tercero)
Cuando “ZFS está lento” hace sonar tu pager, no tienes tiempo para filosofía. Necesitas una secuencia de triage que encuentre el cuello de botella rápido.
Primero: Determina si el dolor está relacionado con sync
- Comprueba las propiedades
syncde los datasets en la ruta caliente (zfs get -r syncen los datasets/zvols relevantes). - Observa
zpool iostat -v 1y busca dominancia de escritura en dispositivos de log (o vdevs principales luchando con escrituras pequeñas). - En Linux, muestrea la frecuencia de
fsync/fdatasyncconperf trace(o logs/ métricas a nivel de aplicación).
Decisión: Si ves llamadas sync frecuentes y alta actividad/latencia en el log, es un cuello de botella en la ruta sync. Si no, no pierdas tiempo culpando a sync.
Segundo: Localiza el punto de estrangulamiento (SLOG vs vdevs principales vs CPU)
- Si hay un SLOG: inspecciona su clase de dispositivo, salud y utilización. Usa
iostat -xyzpool iostat -vpara ver si está saturado. - Si no hay SLOG: comprueba la latencia de los vdevs principales bajo carga intensiva en sync. Discos giratorios haciendo escrituras sync pueden parecer “congelaciones aleatorias” para aplicaciones.
- Comprueba saturación CPU y IO wait (
vmstat,top). Un sistema ocupado puede hacer que los commits sync parezcan almacenamiento cuando en realidad es planificación y contención.
Tercero: Valida las expectativas de durabilidad antes de “arreglar” rendimiento
- Identifica la clase de carga: base de datos, discos VM, directorios home NFS, cache de builds, scratch, datos efímeros replicados.
- Pregunta: ¿cuál es la ventana aceptable de pérdida de datos ante una pérdida de energía súbita? “Ninguna” es una respuesta válida.
- Solo entonces considera cambios como añadir un SLOG, espejarlo, ajustar datasets o (poco frecuente) deshabilitar sync para datos realmente desechables.
Errores comunes (con síntomas específicos y soluciones)
Error 1: Deshabilitar sync en almacenamiento de VM o base de datos “porque es lento”
Síntomas: Los benchmarks y latencias mejoran dramáticamente; después, tras un fallo o evento de energía, ves corrupción de sistemas de ficheros, transacciones BD comprometidas faltantes o estado de aplicación inconsistente.
Solución: Restaurar sync=standard (o always si procede). Invierte en un SLOG apropiado y/o reduce la presión de sync en la capa de aplicación mediante ajustes soportados (con aceptación explícita del riesgo).
Error 2: Comprar un SLOG rápido pero no seguro contra pérdida de energía
Síntomas: Gran rendimiento; luego, problemas inexplicables de integridad tras pérdida de energía abrupta; o descubres que el dispositivo ignora flushes.
Solución: Usa dispositivos con protección contra pérdida de energía diseñados para escrituras sostenidas de baja latencia. Espeja el SLOG cuando la integridad de la carga importe.
Error 3: Esperar que el SLOG acelere todo
Síntomas: Añades un SLOG y no ves mejora; o solo una mejora pequeña; los usuarios aún se quejan de latencias de lectura.
Solución: Confirma que la carga emite escrituras sync. Si es de lectura, enfócate en dimensionar ARC, número de vdevs, recordsize y el rendimiento del dispositivo subyacente —no en SLOG.
Error 4: Afinar sin medir la latencia cola
Síntomas: La latencia media parece bien; los usuarios se quejan de bloqueos; pausas de VM; picos en commits de BD.
Solución: Mide y grafica percentiles (p95/p99). Los cuellos de botella sync suelen aparecer como latencia de cola por colas y tormentas de flush.
Error 5: Mezclar datos “críticos” y “desechables” bajo la misma política de dataset
Síntomas: Alguien pone sync=disabled para un directorio de caché y lo aplica accidentalmente a un dataset padre usado por datos reales; o la herencia cambia tras refactorizaciones.
Solución: Usa datasets separados con propiedades explícitas. Verifica con zfs get -r -o name,property,value,source e incorpora comprobaciones en el provisioning.
Error 6: Ignorar que NFS puede forzar comportamiento sync
Síntomas: Clientes NFS muestran alta latencia; CPU/red del servidor parecen bien; el throughput de almacenamiento no está al máximo; sin embargo las operaciones bloquean.
Solución: Inspecciona patrones commit/write de NFS y asegúrate de que la ruta sync del servidor sea rápida y segura (SLOG + dispositivos apropiados). No “arregles” deshabilitando sync salvo que los datos sean realmente descartables.
Listas de verificación / plan paso a paso
Checklist A: Decidir el modo sync correcto por dataset
- Clasifica los datos: estado crítico, datos de usuario, base de datos, imágenes de VM, cache, scratch, efímeros replicados.
- Define la pérdida aceptable ante un fallo: ninguna, segundos, minutos, “no importa”. Escríbelo.
- Configura
sync=standardpara la mayoría de los datos reales. - Considera
sync=alwayssolo cuando necesites imponer durabilidad independientemente del comportamiento del llamador. - Usa
sync=disabledsolo para datasets explícitamente desechables (y mantenlos aislados).
Checklist B: Añadir un SLOG de forma segura (cuando esté justificado)
- Demuestra que estás limitado por sync: mide la tasa de
fsyncy la utilización ZIL/SLOG. - Elige dispositivos con protección contra pérdida de energía y latencia predecible bajo escrituras sostenidas.
- Espeja el SLOG para cargas importantes.
- Añádelo y valida con pruebas de carga reales, no solo throughput sintético.
Paso a paso: Implementar un dataset dedicado “sync seguro y rápido”
Este es un patrón común para exportaciones NFS o volúmenes de base de datos donde quieres durabilidad con rendimiento razonable.
cr0x@server:~$ sudo zfs create tank/prod_safe
cr0x@server:~$ sudo zfs set sync=standard tank/prod_safe
cr0x@server:~$ sudo zfs set logbias=latency tank/prod_safe
cr0x@server:~$ sudo zfs set atime=off tank/prod_safe
cr0x@server:~$ sudo zfs set compression=lz4 tank/prod_safe
cr0x@server:~$ zfs get -o name,property,value,source sync,logbias,atime,compression tank/prod_safe
NAME PROPERTY VALUE SOURCE
tank/prod_safe sync standard local
tank/prod_safe logbias latency local
tank/prod_safe atime off local
tank/prod_safe compression lz4 local
Interpretación: Esto no “garantiza rapidez”, pero alinea el comportamiento de ZFS con una estrategia de sync de baja latencia manteniendo la durabilidad.
Paso a paso: Crear un dataset explícitamente desechable (y etiquétalo como radiactivo)
cr0x@server:~$ sudo zfs create tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set sync=disabled tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set compression=off tank/scratch_ephemeral
cr0x@server:~$ sudo zfs set atime=off tank/scratch_ephemeral
cr0x@server:~$ zfs get -o name,property,value,source sync,compression tank/scratch_ephemeral
NAME PROPERTY VALUE SOURCE
tank/scratch_ephemeral sync disabled local
tank/scratch_ephemeral compression off local
Interpretación: Haz obvio el radio de acción. Manténlo fuera de rutas de herencia usadas por datos reales.
Preguntas frecuentes
1) ¿Significa sync=disabled “puedo perder los últimos segundos”?
Puede ser peor. Puedes perder datos que la aplicación creía comprometidos de forma segura. Eso puede causar corrupción lógica: una base de datos o servicio puede reconocer una transacción y luego olvidarla tras un fallo. “Unos segundos” no es una cota fiable a menos que toda la pila esté diseñada con ese modo de fallo en mente.
2) Si tengo un SAI/UPS, ¿puedo desactivar sync de forma segura?
Un UPS reduce el riesgo pero no lo elimina. Ocurren kernel panics, resets de controladora, bugs de firmware, cortes accidentales y fallos de doble alimentación. Además, un UPS no ayuda si un dispositivo miente sobre la finalización de flushes. Si necesitas garantías de durabilidad, trata el UPS como defensa en profundidad, no como sustituto.
3) ¿Necesito un SLOG en una pool all-NVMe?
No siempre. Algunas pools NVMe tienen latencia suficientemente baja para que el ZIL en-pool sea aceptable. El factor decisivo es la latencia de escrituras sync bajo tu carga y el comportamiento de flush de los dispositivos. Mide antes de comprar hardware.
4) ¿Debe ser grande el SLOG?
Normalmente no. El SLOG sostiene un log a corto plazo de operaciones sync hasta que los TXGs commiten. La consistencia de latencia y la seguridad ante pérdida de energía importan mucho más que la capacidad. Sobredimensionarlo es común y en su mayoría inofensivo, pero rara vez es el cuello de botella o la ventaja.
5) ¿Cuál es la diferencia entre ZIL y SLOG otra vez?
El ZIL es un mecanismo: el intent log usado para satisfacer semánticas sync. El SLOG es un dispositivo: un lugar dedicado para almacenar registros ZIL, idealmente más rápido y más seguro que la pool principal para ese patrón de escritura específico.
6) ¿Por qué NFS es lento en mi servidor ZFS aunque las escrituras locales son rápidas?
Los clientes NFS suelen solicitar escrituras estables. Las pruebas locales a menudo usan IO bufferizado/asíncrono que no fuerza flushes. Si tu ruta ZIL/SLOG es lenta, la latencia NFS se verá terrible mientras el throughput masivo parece estar bien.
7) ¿Es sync=always más seguro que sync=standard?
Puede ser, en el sentido de que fuerza durabilidad incluso si la aplicación no la solicita. Pero también puede causar penalizaciones de rendimiento grandes. Úsalo cuando tengas una razón específica para desconfiar de los llamadores —y cuando tu ruta sync (SLOG o pool principal) pueda asumirlo.
8) ¿Puedo “arreglar” la latencia sync cambiando recordsize o la compresión?
A veces de forma indirecta. La latencia sync suele estar relacionada con comportamiento de flush/commit y latencia de dispositivos. Pero si los commits TXG están causando retropresión, la CPU y la amplificación de escritura pueden importar. No adivines: mide latencia de llamadas sync, latencia de dispositivo y comportamiento TXG juntos.
9) Si espejo mi SLOG, ¿eso duplica la latencia?
Puede incrementarla algo, porque las escrituras deben ser comprometidas en ambos dispositivos. Pero con dispositivos de baja latencia adecuados, un SLOG espejado suele ser todavía drásticamente más rápido que loguear en vdevs principales más lentos —y mejora la resiliencia frente a fallo del dispositivo de log.
10) ¿Cuál es la regla práctica más amigable para operadores?
Si la carga abriría un bug al perder una escritura “comprometida”, no uses sync=disabled. En su lugar, haz que sync sea rápido de la forma honesta: buenos dispositivos, buen SLOG (si hace falta) y diseño de datasets consciente de la carga de trabajo.
Conclusión
El sync de ZFS es una de esas opciones que parece un truco porque puede serlo. También puede ser una trampa. La propiedad no trata de “hacer ZFS más rápido”. Trata de si ZFS respetará el contrato de durabilidad del llamador —o lo reescribirá en silencio.
La mentalidad de producción es tratar sync como una decisión de política, no como un truco de afinado. Empieza identificando quién está pidiendo semánticas síncronas y por qué. Mide la ruta ZIL/SLOG, no solo el throughput masivo. Si necesitas rendimiento y veracidad en el reconocimiento, invierte en una ruta de escrituras sync adecuada y mantén los ajustes alineados con la promesa de negocio que realizan tus sistemas.