No notas el “almacenamiento” cuando funciona. Lo notas cuando la cola de compilación se detiene, tu VM arranca como si los bytes se los llevara una cucharilla de café,
y tu base de datos empieza a registrar “fsync taking too long” mientras todos culpan a la red porque eso es un chivo expiatorio socialmente aceptable.
ZFS sobre NFS puede sentirse sorprendentemente cercano al disco local—hasta que no. La brecha casi siempre son ajustes, supuestos desajustados y un par de
valores por defecto pequeños pero letales. Vamos a arreglar eso.
El modelo mental: por qué “NFS se siente lento” suele ser una mentira
“NFS es lento” no es un diagnóstico. Es un estado emocional. En producción, la lentitud proviene de uno de cuatro lugares:
latencia, serialización, semánticas síncronas o fragmentación/desalineación con la carga de trabajo. ZFS y NFS tienen opiniones fuertes
sobre cómo debe ocurrir el IO. Cuando sus opiniones coinciden, obtienes algo que se siente local. Cuando no, obtienes una denegación de servicio distribuida
construida a partir de valores por defecto pequeños y bienintencionados.
Tu trabajo es alinear la tubería:
- Forma del IO de la aplicación: aleatorio vs secuencial, pequeño vs grande, síncrono vs asíncrono, intensivo en metadata vs streaming.
- Comportamiento NFS: cacheo de atributos, read-ahead, delegación/bloqueo, número de RPCs paralelos, semántica de montaje.
- Comportamiento ZFS: recordsize, compresión, primarycache, dimensionamiento de ARC, special vdev, política sync, ZIL/SLOG.
- Realidad de hardware y red: piso de latencia, velocidad de enlace, profundidad de cola, moderación de interrupciones, offloads de NIC.
El modo de fallo más común es asumir que el almacenamiento es “suficientemente rápido” porque rinde bien con benchmarks localmente en el servidor.
NFS cambia el patrón de IO. ZFS reacciona. La latencia se amplifica por los viajes de ida y vuelta y las semánticas síncronas. Un pool que hace 2 GB/s de lecturas secuenciales
podría aún sentirse terrible para una carga que hace escrituras síncronas de 4 KB sobre NFS.
Un punto más importante: “sentirse como disco local” no significa “mismo throughput.” Significa “misma latencia de cola bajo carga normal.”
La latencia de cola es lo que hace que los usuarios abran tickets, o peor, creen soluciones alternativas.
Idea parafraseada (atribución): John Allspaw ha sostenido que la fiabilidad trata de reducir la sorpresa, no solo de prevenir fallos.
El ajuste de NFS es un proyecto de reducción de sorpresas.
Hechos e historia que siguen importando en producción
Unos cuantos datos concretos de contexto hacen que las elecciones de ajuste de hoy sean menos misteriosas. Esto no es trivia; explican por qué los valores por defecto son como son,
y por qué tu carga de trabajo aún puede caerse por un precipicio.
- NFS nació asumiendo redes poco fiables. Los diseños tempranos se basaban en la estatelessness (especialmente NFSv3), lo cual afecta cómo los clientes recuperan y cachean.
- NFSv4 introdujo estado. El bloqueo y las delegaciones cambiaron la coordinación cliente/servidor y pueden mejorar el rendimiento—hasta que chocan con comportamientos de cliente extraños o patrones de failover.
- ZFS se construyó alrededor de copy-on-write. Excelente para snapshots e integridad; también implica que las pequeñas escrituras aleatorias pueden convertirse en patrones de IO más grandes y complejos.
- El ZIL existe incluso sin un SLOG dedicado. Aún hay quienes piensan “sin SLOG no hay ZIL.” El ZIL es una estructura de registro; SLOG es solo un dispositivo más rápido para ella.
- Las escrituras síncronas son una promesa semántica, no una preferencia de rendimiento. Las bases de datos y los hipervisores suelen forzar sync por buenas razones.
- Recordsize no es “tamaño de bloque”. Es el tamaño máximo lógico de bloque para archivos, afectando cómo ZFS empaqueta datos y cuánto lee/escribe para una petición dada.
- El cacheo de atributos en NFS es un truco de rendimiento con consecuencias. Puede hacer que cargas intensivas en metadata vuelen—o introducir confusión tipo “¿por qué no veo el archivo?” en aplicaciones distribuidas.
- Los checksums cambiaron el juego. El checksumming y scrub de ZFS son la razón por la que las historias de “corrupción silenciosa” no son solo leyenda urbana en almacenamiento empresarial.
- 10GbE hizo que el throughput sea fácil, la latencia sigue siendo difícil. Muchos equipos “suben el tubo” y luego descubren que el cuello de botella es el RTT síncrono y el tiempo de flush del almacenamiento.
Ajustes de cliente y servidor NFS que mueven la aguja
Elige la versión del protocolo a propósito
NFSv4.x suele ser la elección por defecto correcta en 2025: mejor modelo de seguridad, operaciones compuestas, características con estado que pueden reducir el tráfico.
Pero NFSv3 aún tiene su lugar, especialmente en entornos donde quieres un comportamiento más simple, o tratas con ciertos hipervisores
y stacks legacy que son “especiales” en la forma que arruina fines de semana.
La clave es la consistencia. Versiones mixtas entre clientes pueden crear diferencias de comportamiento no obvias (bloqueo, cacheo, recuperación), y terminas depurando
“rendimiento” cuando en realidad depuras semánticas.
rsize/wsize: deja de ser tímido
Las redes y kernels modernos manejan bien tamaños de IO grandes. Usa 1M donde sea soportado. Si tu entorno no puede, lo sabrás rápidamente en la negociación.
Valores pequeños de rsize/wsize producen más RPCs, más overhead y más posibilidades de chocar con muros de latencia.
Pero no lo imites sin entenderlo: si estás en un enlace WAN de alta latencia, tamaños grandes pueden mejorar throughput pero empeorar la latencia de cola interactiva en algunos patrones.
Mide con tu carga, no con una prueba sintética de lectura secuencial.
nconnect y paralelismo: el mejor amigo del throughput
Los clientes Linux soportan nconnect= para abrir múltiples conexiones TCP al servidor por un mismo montaje. Esto puede incrementar el throughput dramáticamente
al repartir la carga entre colas de CPU y evitar que un solo flujo sea el punto de estrangulamiento. No es gratis; más conexiones significan más estado y a veces
más contención de locks en el servidor.
Montajes hard vs soft: sé valiente, no imprudente
Usa montajes hard para cualquier cosa que importe. Los montajes soft devuelven errores por timeout, que muchas aplicaciones tratan como corrupción o “borrar y reintentar.”
Así conviertes un fallo transitorio en pérdida de datos.
Para directorios de usuarios interactivos, “soft” puede sentirse más agradable cuando el servidor está caído, pero es una trampa. Si quieres capacidad de respuesta, ajusta timeouts y
retransmits. No cambies corrección por conveniencia.
actimeo y cacheo de atributos: elige tu veneno explícitamente
Cargas intensivas en metadata (sistemas de compilación, gestores de paquetes) pueden beneficiarse del cacheo de atributos. Pero aplicaciones distribuidas que esperan visibilidad casi instantánea
de cambios pueden confundirse si los clientes cachean atributos demasiado tiempo.
El enfoque limpio: establece actimeo en algo razonable (como 1–5 segundos) en lugar de desactivar el cacheo por completo.
“actimeo=0” es un suicidio de rendimiento para la mayoría de cargas.
Hilos del servidor y comportamiento RPC
En servidores NFS Linux, el conteo de hilos de nfsd importa bajo concurrencia. Demasiados pocos hilos y las peticiones hacen cola; demasiados y quemas CPU en cambios de contexto
y contención de locks. Quieres “suficientes para mantener la tubería llena,” no “tantos como puedas meter en RAM.”
Ajustes de dataset y pool de ZFS que cambian resultados
recordsize: alínialo con tu carga, no con tus sentimientos
Si sirves imágenes de VM o bases de datos por NFS, la ganancia más común es fijar recordsize en algo como 16K o 32K (a veces 8K),
porque esas cargas hacen muchas IOs aleatorias pequeñas. El 128K por defecto es genial para streaming y backups, no para invitados con muchas escrituras aleatorias.
Para directorios de uso general, 128K está bien. Para archivos multimedia, considera tamaños mayores si tu plataforma lo soporta.
La idea es evitar la amplificación read-modify-write y mantener útil al ARC.
compresión: actívala salvo que tengas una razón
compression=lz4 es una de las pocas comidas casi gratis en almacenamiento. A menudo mejora el throughput y reduce IO. En CPUs modernas, el coste es modesto.
No “salvas rendimiento” desactivando compresión; a menudo solo fuerzas más bytes sobre disco y red.
atime: desactívalo para la mayoría de exportaciones NFS
Las actualizaciones de tiempo de acceso generan escrituras extra y agitan metadata. A menos que tengas un requisito de cumplimiento o aplicación, usa atime=off.
Para sistemas de archivos compartidos que sirven muchas lecturas, es una reducción fácil de latencia.
xattr y comportamiento de ACL: elige un modo que coincida con tus clientes
Clientes Linux, clientes Windows (vía gateways SMB) y hipervisores pueden tener expectativas distintas sobre ACLs y atributos extendidos.
Mala alineación se manifiesta como tormentas de metadata y rarezas de permisos. Decide el caso de uso principal y ajusta para él.
special vdev: la metadata merece mejor que “los discos que quedan”
Si tu carga es intensiva en metadata (millones de archivos pequeños, builds, árboles de código), un special vdev puede ser transformador.
Pon metadata (y opcionalmente bloques pequeños) en SSDs rápidos. Los aciertos en ARC son geniales, pero los fallos en ARC siguen ocurriendo, y los fallos de metadata son muerte por mil seeks.
primarycache y secondarycache: sé intencional
ARC es memoria; L2ARC es cache en SSD. Para exportaciones NFS que sirven grandes lecturas de streaming, el cache puede expulsar metadata útil.
Para imágenes de VM, cachear datos puede ayudar, pero valida primero el dimensionamiento de memoria. Un patrón común:
primarycache=metadata para ciertos datasets, manteniendo el ARC enfocado en lo que más ayuda.
ashift: no lo ajustas después
ashift se establece al crear el vdev y afecta la alineación de sectores. Si te equivocas, pagas para siempre en amplificación de escritura.
Si estás en discos con sector 4K o SSDs (lo estás), ashift=12 es la elección segura habitual. No dejes que la autodetección adivine mal.
Escrituras síncronas, SLOG y por qué “sync=disabled” limita tu carrera
Los clientes NFS a menudo emiten escrituras como síncronas dependiendo de opciones de montaje y comportamiento de la aplicación. Las bases de datos llaman a fsync porque quieren que sus datos
sobrevivan a una pérdida de energía. Los hipervisores a menudo usan semánticas sync para discos de VM porque “perdí un filesystem de VM” es una reunión cara.
En ZFS, las escrituras síncronas se reconocen solo cuando están comprometidas de forma segura. Eso significa que el camino ZIL importa.
Sin un SLOG dedicado, el ZIL vive en tu pool principal, y la latencia de escritura sync se convierte en “qué tan rápido puede el pool confirmar escrituras pequeñas de forma segura.”
En pools HDD, eso puede ser brutal. En pools SSD, puede estar bien. En pools mixtos, depende del paso consistente más lento.
Un dispositivo SLOG dedicado puede reducir drásticamente la latencia sync. Pero solo si es el dispositivo adecuado: baja latencia, protección contra pérdida de energía, rendimiento consistente,
y conectado de forma fiable. Un NVMe consumidor barato sin PLP es un generador de incidentes disfrazado.
Broma #1: Un SSD de consumo como SLOG es como usar un paraguas de papel en un huracán—técnicamente un paraguas, emocionalmente un error.
No desactives sync para “arreglar rendimiento”
sync=disabled hace que los benchmarks se vean increíbles. También convierte “escritura reconocida” en “quizá escrita eventualmente,” que no es lo que muchas aplicaciones esperan.
Si el servidor falla, puedes perder datos que el cliente creía durables. Eso no es ajuste; es un truco de magia con trampilla.
Entiende los modos sync: standard, always, disabled
- sync=standard: respeta las peticiones de la aplicación (por defecto, normalmente correcto).
- sync=always: trata todas las escrituras como sync. Útil para ciertos casos de cumplimiento; a menudo castigador.
- sync=disabled: miente a los clientes. Solo para casos especiales donde has aceptado explícitamente el riesgo y lo has documentado como adulto.
Logbias e intención de carga
logbias=latency le dice a ZFS que prefiera comportamiento de logging de baja latencia (a menudo apropiado para cargas heavy-sync). logbias=throughput puede ayudar para streaming.
Este es un ajuste para alinear la intención, no una palanca mágica de rendimiento. Pruébalo por dataset.
Ruta de red: ajustes aburridos que te compran milisegundos
NFS es sensible a la latencia porque cada RPC es un viaje de ida y vuelta, y las escrituras síncronas son una cadena de reconocimientos.
No necesitas una red fancy. Necesitas una predecible.
Jumbo frames: no son obligatorios, pero no los hagas a medias
Si habilitas MTU 9000, debe ser end-to-end: NICs, switches, VLANs, bonds y el servidor de almacenamiento. Una configuración jumbo parcial es peor que ninguna porque
obtendrás fragmentación o agujeros negros. Si no controlas todo el camino, sáltatelo y céntrate en evitar pérdidas.
Offloads de NIC y CPU
Los offloads pueden ayudar, pero también introducir picos de latencia extraños dependiendo de drivers y firmware. El enfoque correcto es empírico:
mide la carga de softirq de CPU, pérdidas y latencia, y decide. No desactives funciones porque un post de 2013 lo dijo.
Congestión y bufferbloat
En LANs rápidas, aún puedes tener micro-bursts y colas. Revisa buffers de switch, cola en host y retransmisiones TCP.
Si tu NFS “se siente lento” solo bajo carga, podrías estar viendo acumulación de colas más que límites de throughput bruto.
Tareas prácticas: comandos, salidas y qué decides después
Estas son tareas de campo que puedes ejecutar durante una queja de rendimiento sin convertir el incidente en un proyecto de arqueología.
Cada tarea incluye: comando, qué significa la salida y la decisión que tomas a partir de ella.
Tarea 1: Confirma las opciones de montaje NFS (cliente)
cr0x@server:~$ nfsstat -m
/home from nas01:/tank/home
Flags: rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none
Qué significa: Estás en NFSv4.2 con rsize/wsize de 1M, montaje hard, TCP. Esa es una línea base saludable.
Decisión: Si ves rsize/wsize pequeños (como 64K) o vers=3 inesperadamente, arregla montajes primero. Si es soft, cámbialo a menos que sean datos prescindibles.
Tarea 2: Revisa rápidamente versión NFS negociada y transporte (cliente)
cr0x@server:~$ cat /proc/mounts | grep nfs
nas01:/tank/home /home nfs4 rw,relatime,vers=4.2,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=10.10.10.21,local_lock=none 0 0
Qué significa: Confirma lo que el kernel piensa, no lo que tu fstab deseaba.
Decisión: Si tu fstab dice nconnect=8 y no aparece aquí, no lo estás usando realmente. Arregla la automatización de montajes.
Tarea 3: Mide la latencia al servidor NFS (cliente)
cr0x@server:~$ ping -c 5 nas01
PING nas01 (10.10.10.10) 56(84) bytes of data.
64 bytes from 10.10.10.10: icmp_seq=1 ttl=64 time=0.312 ms
64 bytes from 10.10.10.10: icmp_seq=2 ttl=64 time=0.287 ms
64 bytes from 10.10.10.10: icmp_seq=3 ttl=64 time=0.301 ms
64 bytes from 10.10.10.10: icmp_seq=4 ttl=64 time=0.295 ms
64 bytes from 10.10.10.10: icmp_seq=5 ttl=64 time=0.289 ms
--- nas01 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4090ms
rtt min/avg/max/mdev = 0.287/0.296/0.312/0.009 ms
Qué significa: RTT submilisegundo en LAN. Bien. Si esto está en 2–5 ms, las cargas sync se sentirán “pegajosas”.
Decisión: Si el RTT es alto o con jitter, deja de ajustar ZFS. Arregla la ruta de red, problemas de NIC o enrutamiento primero.
Tarea 4: Revisa retransmisiones TCP y pérdidas (cliente)
cr0x@server:~$ netstat -s | egrep -i 'retrans|segments retransm|lost|timeouts' | head
12 segments retransmitted
0 retransmit timeouts
0 connections reset due to unexpected data
Qué significa: Bajas retransmisiones. Si esto sube durante quejas, estás perdiendo paquetes o haciendo colas muy mal.
Decisión: Retransmisiones en aumento bajo carga = revisa estadísticas de NIC, puertos del switch, mismatch de MTU o bufferbloat.
Tarea 5: Confirma que el servidor NFS realmente exporta lo que crees (servidor)
cr0x@server:~$ exportfs -v
/tank/home 10.10.10.0/24(rw,async,wdelay,hide,no_subtree_check,sec=sys,secure,root_squash,no_all_squash)
Qué significa: La exportación es async a nivel NFS (esto trata del comportamiento de respuesta del servidor, no de las semánticas sync de ZFS). Root squashing activado.
Decisión: Si sirves bases de datos/VMs, piensa cuidadosamente sobre async. Muchas organizaciones mantienen export async pero confían en ZFS sync para durabilidad; otras requieren semántica de export sync. No adivines—ajústalo según tu modelo de riesgo.
Tarea 6: Revisa el conteo de hilos nfsd (servidor Linux)
cr0x@server:~$ cat /proc/fs/nfsd/threads
32
Qué significa: 32 hilos nfsd. Si tienes cientos de clientes haciendo operaciones de metadata, pocos hilos harán cola.
Decisión: Si la CPU está baja y los clientes hacen cola, incrementa hilos moderadamente (por ejemplo, 64). Si la CPU está alta y la latencia crece, aumentar hilos puede empeorar las cosas.
Tarea 7: Observa actividad RPC NFS (servidor)
cr0x@server:~$ nfsstat -s
Server rpc stats:
calls badcalls badclnt badauth xdrcall
482913 0 0 0 0
Server nfs v4:
null compound read write getattr
0 412001 32941 21887 100221
Qué significa: Alto compound y getattr sugiere tráfico intensivo en metadata. Los conteos read/write muestran la mezcla de IO.
Decisión: Si getattr domina y la latencia duele, considera special vdev para ZFS, enfoque de metadata en ARC y estrategia de cacheo de atributos en clientes.
Tarea 8: Revisa salud del pool ZFS e indicadores de IO lento (servidor)
cr0x@server:~$ zpool status -v
pool: tank
state: ONLINE
scan: scrub repaired 0B in 02:11:43 with 0 errors on Sun Dec 22 01:10: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
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
errors: No known data errors
Qué significa: Pool sano, scrub limpio. No prueba de rendimiento, pero elimina “vdev degradado” de la lista de sospechosos.
Decisión: Si ves un disco degradado o resilver, detente. Ajustar rendimiento durante un resilver es como afinar un coche durante un incendio en la rueda.
Tarea 9: Ver latencia ZFS en tiempo real y comportamiento sync (servidor)
cr0x@server:~$ zpool iostat -v tank 1 5
capacity operations bandwidth
pool alloc free read write read write
---------- ----- ----- ----- ----- ----- -----
tank 3.12T 8.54T 220 1450 48.1M 31.2M
raidz2-0 3.12T 8.54T 220 1450 48.1M 31.2M
sda - - 35 240 8.2M 5.3M
sdb - - 36 241 8.1M 5.2M
sdc - - 37 239 8.0M 5.3M
sdd - - 37 242 8.0M 5.2M
sde - - 38 243 8.0M 5.1M
sdf - - 37 245 7.8M 5.1M
Qué significa: IOPS de escritura altas, ancho de banda moderado—clásico workload de escrituras pequeñas. RAIDZ2 en HDD haciendo IO pesado sync se sentirá lento.
Decisión: Si esto es VM/bases de datos sobre NFS, considera SLOG y recordsize más pequeño. Si es churn de metadata, considera special vdev y atime off.
Tarea 10: Inspecciona propiedades clave del dataset (servidor)
cr0x@server:~$ zfs get -o name,property,value -s local,default recordsize,compression,atime,sync,logbias,primarycache tank/home
NAME PROPERTY VALUE
tank/home recordsize 128K
tank/home compression lz4
tank/home atime off
tank/home sync standard
tank/home logbias latency
tank/home primarycache all
Qué significa: Valores por defecto sensatos para uso general, pero recordsize podría estar mal para imágenes de VM o bases de datos.
Decisión: Si este dataset sirve discos de VM, fija recordsize más pequeño (16K–32K) y considera primarycache=metadata según RAM y patrón de acceso.
Tarea 11: Revisa presión de ARC y ratio de aciertos (servidor)
cr0x@server:~$ arcstat 1 3
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
12:01:11 780 90 11 22 2 68 9 0 0 42G 48G
12:01:12 802 95 12 24 2 71 9 0 0 42G 48G
12:01:13 799 88 11 21 2 67 8 0 0 42G 48G
Qué significa: ~11–12% de miss. No es terrible. Si miss% sube durante la carga, los discos serán azotados y la latencia NFS subirá.
Decisión: Si ARC está limitado demasiado o la memoria escasea, ajusta el tamaño de ARC (con cuidado) o enfócate en cachear metadata vía propiedades de dataset.
Tarea 12: Verifica presencia y rol del SLOG (servidor)
cr0x@server:~$ 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
sde ONLINE 0 0 0
sdf ONLINE 0 0 0
logs
nvme0n1p1 ONLINE 0 0 0
Qué significa: Existe dispositivo de log dedicado. Bien. Ahora asegúrate de que sea la clase correcta de dispositivo (latencia, PLP).
Decisión: Si no hay SLOG y tienes cargas sync intensivas en HDDs, añade un SLOG en espejo con dispositivos de grado enterprise.
Tarea 13: Detecta “dolor por escrituras sync” desde el lado cliente (cliente)
cr0x@server:~$ dd if=/dev/zero of=/home/testfile bs=4k count=4096 conv=fdatasync status=progress
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s
4096+0 records in
4096+0 records out
16777216 bytes (17 MB, 16 MiB) copied, 2.10 s, 8.0 MB/s
Qué significa: Escrituras 4K con flush sync son lentas (8 MB/s). Esto es el dolor que sienten usuarios en bases de datos y journaling de VM.
Decisión: Si esto es “malo,” no persigas rsize/wsize. Persigue la calidad del SLOG, latencia del pool y semánticas sync.
Tarea 14: Compara rendimiento de streaming asíncrono (cliente)
cr0x@server:~$ dd if=/dev/zero of=/home/testfile2 bs=1M count=4096 status=progress
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s
4096+0 records in
4096+0 records out
4294967296 bytes (4.3 GB, 4.0 GiB) copied, 9.12 s, 471 MB/s
Qué significa: Las escrituras de streaming grandes se ven muy bien. Este contraste es clásico: el throughput está bien, la latencia sync no.
Decisión: Optimiza para la carga que realmente ejecutas. Si tu app hace sync 4K, enfócate en ZIL/SLOG y latencia, no en throughput.
Tarea 15: Revisa sospechas de amplificación de escritura por dataset (servidor)
cr0x@server:~$ zfs get -o name,property,value copies,dedup,checksum tank/home
NAME PROPERTY VALUE
tank/home copies 1
tank/home dedup off
tank/home checksum on
Qué significa: No hay dedup (bueno para la mayoría), copia única, checksumming activado. Dedup en un dataset NFS ocupado es una historia común de “¿por qué todo está lento?”
Decisión: Si dedup está activado por accidente, planifica una migración fuera de ese dataset. Apagarlo no deshace la deduplicación de bloques existentes.
Tarea 16: Detecta errores a nivel NIC y mismatch de MTU (servidor)
cr0x@server:~$ ip -s link show dev eno1
2: eno1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000
link/ether 3c:fd:fe:aa:bb:cc brd ff:ff:ff:ff:ff:ff
RX: bytes packets errors dropped missed mcast
918G 612M 0 12 0 1200
TX: bytes packets errors dropped carrier collsns
877G 590M 0 3 0 0
Qué significa: Algunas pérdidas. No necesariamente fatal, pero si las pérdidas suben durante picos, la latencia NFS y las retransmisiones seguirán.
Decisión: Si MTU es 9000 aquí pero 1500 en algún otro punto, arregla la red. Si las pérdidas persisten, revisa buffers de anillo, afinidad de IRQ y congestión en el switch.
Guion de diagnóstico rápido
Cuando alguien dice “NFS está lento,” necesitas un plan que encuentre el cuello de botella en minutos, no en un hilo de correo.
Aquí está el orden que minimiza tiempo perdido.
Primero: decide si es dolor por latencia o por throughput
- Dolor por latencia: IO pequeño, heavy-sync, operaciones de metadata. Síntomas: git status lento, instalaciones de paquetes lentas, bases de datos quejándose de fsync, pausas en VMs.
- Dolor por throughput: transferencias grandes lentas. Síntomas: backups arrastrando, copias de archivos grandes por debajo de la velocidad del enlace.
Ejecuta el par rápido: un dd sync-flush (Tarea 13) y un dd secuencial grande (Tarea 14). Si lo secuencial está bien pero lo sync es terrible, ya lo dejaste acotado.
Segundo: revisa la red por traición obvia
- Ping RTT y jitter (Tarea 3).
- Retransmisiones (Tarea 4).
- Caídas/errores de interfaz (Tarea 16).
Si ves retransmisiones incrementando durante el incidente, detente y arregla la ruta de red. El ajuste de almacenamiento no superará la pérdida de paquetes.
Tercero: valida semánticas de montaje y versión de protocolo
- Confirma opciones de montaje y rsize/wsize negociados, versión, proto (Tareas 1–2).
- Revisa si
nconnectestá realmente en efecto. - Busca
actimeo=0o timeouts extraños.
Cuarto: identifica si el servidor está CPU-bound, thread-bound o IO-bound
- Hilos del servidor NFS (Tarea 6).
- Mezcla de operaciones NFS (Tarea 7): metadata vs datos.
- iostat del pool ZFS (Tarea 9): perfil de IOPS y ancho de banda.
- Comportamiento ARC (Tarea 11): ¿estás fallando cache y yendo a disco?
Quinto: confirma el camino sync (SLOG/ZIL) y propiedades del dataset
- Presencia de SLOG (Tarea 12).
- Dataset sync/logbias/recordsize (Tarea 10).
- Sorpresas de dedup/copies (Tarea 15).
Si es heavy-sync y no tienes un SLOG apropiado, ya tienes la respuesta. Si sí lo tienes, sospecha de la calidad o saturación del dispositivo SLOG,
o de que en realidad no lo estás aprovechando por la configuración del dataset.
Tres microhistorias corporativas desde las trincheras
Incidente: el supuesto equivocado (“NFS async significa suficientemente seguro”)
Una empresa mediana ejecutaba sus artefactos de CI y una pequeña instancia Postgres en una exportación NFS respaldada por ZFS. El equipo de almacenamiento había puesto la exportación NFS en async
porque “mejoraba el rendimiento,” y asumieron que ZFS cubriría la durabilidad igualmente. El equipo de aplicaciones asumió “NFS es disco compartido, por lo tanto durable.”
Entonces vino un evento de energía. No dramático—solo una breve caída y un reinicio desordenado. La instancia Postgres reinició y empezó a quejarse inmediatamente de páginas corruptas.
El sistema de CI también mostró chunks de artefactos faltantes que habían sido “subidos exitosamente” minutos antes. El canal de incidentes se llenó con los clásicos:
“¿Podría ser DNS?” y “Pensé que ZFS prevenía corrupción.”
El problema raíz no fue corrupción ZFS. Fue semántica. El servidor NFS había respondido a escrituras antes de que fueran durables en almacenamiento estable.
ZFS tenía integridad, pero integridad de lo que realmente se había comprometido. Algunas escrituras reconocidas nunca llegaron. Eso no es un problema de checksum; es un problema de promesa.
La solución no fue un simple toggle. Separaron cargas: artefactos de CI se quedaron en export async (riesgo aceptable, datos recreables),
las bases de datos se movieron a una exportación y política de dataset que respetara durabilidad síncrona, con un SLOG empresarial en espejo.
También documentaron la política en el catálogo de servicios para que “async” dejara de ser una trampa invisible.
Optimización que salió mal: la apuesta del recordsize
Otra organización servía imágenes de VM por NFS desde un pool ZFS reluciente. Alguien notó el recordsize=128K por defecto y decidió que “bloques más grandes significan más rápido.”
Pusieron recordsize en 1M en el dataset que alojaba discos de VM. Las pruebas iniciales se vieron geniales: copiar grandes ISOs fue más rápido, y un benchmark secuencial sintético
hizo un gráfico que merecía premios.
Dos semanas después, empezaron las quejas de latencia aleatoria: tiempos de arranque de VM erráticos, sesiones interactivas entrecortadas y logs del hipervisor mostrando timeouts de IO ocasionales.
El servidor de almacenamiento no se veía “ocupado” en términos de ancho de banda, pero sí ocupado en la peor forma: amplificación read-modify-write e ineficiencia de cache.
Pequeñas escrituras de los invitados forzaban al almacenamiento a tocar records enormes, y ARC empezó a cachear bloques de datos grandes en lugar de metadata y regiones calientes que importaban.
La resolución tardó más de lo que debía porque todos miraban throughput. El throughput estaba bien. La latencia tail no.
Eventualmente alguien comparó tamaños de IO del hipervisor con recordsize de ZFS y se dieron cuenta de que habían ajustado para la carga equivocada.
El plan de recuperación fue aburrido: nuevo dataset con recordsize sensato (16K–32K), storage vMotion/migración de discos de VM, y dejar el recordsize de 1M para archivos de backup.
Lección aprendida: no ajustes un filesystem para un benchmark que no ejecutas en producción.
Práctica correcta y aburrida que salvó el día: datasets separados, defaults sensatos, intención documentada
Una gran empresa tenía una “plataforma NFS” interna usada por dev, build, analytics y un puñado de servicios stateful. Hicieron algo profundamente poco sexy:
estandarizaron plantillas de dataset. Home dirs recibieron una plantilla; caches de build otra; imágenes de VM otra. Cada plantilla tenía recordsize, atime, compresión
y política de cache alineadas al caso de uso.
Cuando un incidente de rendimiento golpeó durante una gran semana de release, el on-call no tuvo que adivinar para qué era “este share.” El nombre del dataset codificaba la intención, y las
propiedades coincidían. Ejecutaron zfs get y descartaron inmediatamente los errores clásicos: no había dedup sorpresa, no había sync=always accidental,
no había churn de atime en shares de solo lectura.
El problema resultó ser congestión de red en un switch ToR. Porque la configuración de almacenamiento era predecible, no perdieron horas cambiando ajustes de ZFS
y reiniciando clientes. Arreglaron la cola y el problema desapareció.
La victoria no fue un ajuste ingenioso. Fue eliminar ambigüedad, que es la optimización de rendimiento más fiable que conozco.
Errores comunes: síntoma → causa raíz → solución
1) “La copia de archivo grande es rápida, pero las bases de datos son lentas”
Síntoma: dd secuencial se ve genial, pero cualquier cosa que haga fsync va lento; invitados VM se entrecortan.
Causa raíz: Cuello de botella en latencia de escrituras sync (sin SLOG, SLOG débil, flush lento del pool).
Solución: Añade un SLOG en espejo apropiado con PLP; mantén sync=standard. Verifica con tests sync-flush y observa latencia bajo carga.
2) “Todo se volvió más lento después de poner actimeo=0”
Síntoma: Compilaciones y listados de archivos se vuelven lentos; CPU del servidor sube; operaciones getattr se disparan.
Causa raíz: Cache de atributos deshabilitada, causando revalidación constante de metadata.
Solución: Usa un actimeo=1 modesto o tuning de acregmin/acregmax en lugar de cero; agrega special vdev para metadata si es necesario.
3) “NFS cuelga para siempre cuando el servidor está abajo”
Síntoma: Procesos atascados en estado D; esperas de IO inmanejables.
Causa raíz: Montaje hard haciendo lo que prometió, más una aplicación que no tolera IO bloqueante.
Solución: Mantén montajes hard para corrección, pero ajusta timeo/retrans sensiblemente y diseña apps con timeouts; para montajes no críticos, considera rutas separadas o caches locales.
4) “El IO aleatorio es terrible en un pool RAIDZ”
Síntoma: Carga alta de IOPS de escritura arroja latencia horrible; iostat muestra muchas escrituras pequeñas en vdevs HDD.
Causa raíz: RAIDZ + escrituras pequeñas aleatorias + semánticas sync = amplificación de escritura y tormentas de seeks.
Solución: Usa mirrors para pools con muchas escrituras aleatorias, o asegura que la carga esté cacheada/aggregateada; añade SLOG para sync, ajusta recordsize y considera special vdev para metadata/bloques pequeños.
5) “Aumentamos hilos nfsd y empeoró”
Síntoma: CPU sube, cambios de contexto aumentan, latencia crece.
Causa raíz: Demasiados hilos en el servidor causando contención y overhead del scheduler.
Solución: Reduce hilos al punto óptimo medido; enfócate en afinidad de CPU, interrupciones de red y latencia del almacenamiento subyacente.
6) “Tras habilitar jumbo frames, algunos clientes van lentos aleatoriamente”
Síntoma: Ciertas subredes u hosts ven timeouts, retransmisiones; otros bien.
Causa raíz: Mismatch de MTU en algún punto del camino causando fragmentación o pérdidas.
Solución: Asegura consistencia MTU end-to-end o revierte a 1500; valida con pings DF y chequeos de configuración de switches.
7) “La tasa de aciertos ARC está bien pero aún estamos lentos”
Síntoma: miss% de ARC se ve OK, pero clientes se quejan; el pool muestra presión de escrituras sync.
Causa raíz: El cache no ayuda la latencia de commit sync; el cuello de botella es tiempo de flush/commit.
Solución: Invierte en SLOG y dispositivos de baja latencia; reduce IO sync donde sea correcto (configuraciones de app), no donde sea peligroso (sync=disabled).
8) “Habilitamos dedup y ahora el servidor NFS está poseído”
Síntoma: Picos de latencia, presión de memoria, rendimiento impredecible.
Causa raíz: Dedup requiere estructuras metadata grandes y calientes; si no está dimensionado correctamente, thrash y castiga cada IO.
Solución: No uses dedup para NFS general. Migra datos fuera del dataset con dedup; mantén la compresión en su lugar.
Broma #2: Dedup es el equivalente en almacenamiento a adoptar un mapache—a veces es lindo, pero absolutamente se meterá en todo.
Listas de verificación / plan paso a paso
Plan A: hacer que un share ZFS+NFS existente se sienta local para usuarios generales
- Fija la línea base del montaje cliente. Confirma
vers,proto=tcp,hard, y rsize/wsize negociados (Tareas 1–2). - Establece opciones de montaje sensatas. Punto de partida típico: NFSv4.2,
rsize/wsize=1M,hard,timeoajustado, y consideranconnect=4o8para clientes ocupados. - Desactiva atime en el dataset.
zfs set atime=offpara shares de usuarios salvo que se requiera. - Habilita compresión lz4.
zfs set compression=lz4. - Vigila comportamiento de metadata. Si
getattrdomina (Tarea 7), considera cache de atributos moderada y special vdev para metadata. - Valida sanidad de la red. RTT, retransmisiones, pérdidas (Tareas 3–4, 16).
- Vuelve a probar con flujos reales. Operaciones de git, builds, exploración de archivos, no solo un gran
dd.
Plan B: servir imágenes de VM por NFS sin arrepentimientos
- Crea un dataset dedicado. No reutilices el dataset de “home dirs” y esperes lo mejor.
- Fija recordsize para coincidir con IO. Empieza en 16K o 32K para discos de VM. Prueba ambos.
- Mantén sync honesto. Usa
sync=standard. Añade un SLOG en espejo apropiado si estás en HDD o si la latencia sync es alta. - Considera la estrategia de cache. A menudo
primarycache=metadataayuda si el dataset es grande y el ARC se vería contaminado por datos de invitados. - Mide latencia sync. Usa tests sync-flush (Tarea 13) y observa iostat del pool bajo carga (Tarea 9).
- Valida comportamiento de failover. La recuperación de clientes NFS y expectativas del hipervisor pueden crear problemas de rendimiento que parecen “almacenamiento”.
Plan C: builds intensivos en metadata y árboles de código
- Prioriza metadata. Considera un special vdev para metadata/bloques pequeños.
- Usa compresión y atime=off. Reduce el churn de IO.
- Ajusta cacheo de atributos. No pongas
actimeo=0a menos que disfrutes el dolor auto-infligido. - Vigila CPU del servidor y hilos nfsd. Incrementa hilos solo cuando veas colas, no como rito.
- Asegura espacio de respiración para ARC. Cachear metadata es tu mejor amigo aquí.
Preguntas frecuentes
1) ¿Debo usar NFSv3 o NFSv4.2?
Por defecto, usa NFSv4.2 en Linux moderno salvo que tengas una razón de compatibilidad. NFSv3 puede ser más simple y a veces más fácil de depurar, pero las características de v4.x
suelen reducir el ruido y mejorar la seguridad.
2) ¿Qué rsize/wsize debo usar?
Empieza con 1M donde sea soportado. Si la negociación cae, lo verás en nfsstat -m. Si tu carga es sensible a latencia y de IO pequeño,
rsize/wsize no te salvarán de la latencia sync—SLOG y diseño del pool lo harán.
3) ¿nconnect es siempre bueno?
A menudo es bueno para throughput y paralelismo, especialmente en enlaces rápidos y servidores multicore. Pero incrementa estado de conexión y puede exponer contención de locks en el servidor.
Prueba 4 u 8, mide y no asumas que más es mejor.
4) ¿Necesito un SLOG?
Si tienes cargas heavy-sync (bases de datos, imágenes de VM, cualquier cosa que haga fsync frecuentemente) y tu pool no es ya de baja latencia, sí. Para pools all-flash con
latencia excelente, un SLOG puede no aportar mucho. Mide con escrituras sync-flush.
5) ¿Puedo simplemente poner sync=disabled para arreglar rendimiento?
Puedes, y se verá genial—hasta que te caigas y pierdas escrituras reconocidas. Para datos descartables, quizá. Para cualquier cosa que importe, no lo hagas.
Arregla la ruta real de latencia en su lugar.
6) ¿Qué recordsize ZFS debo usar para shares NFS?
Para shares de archivos generales: 128K está bien. Para imágenes de VM y bases de datos: empieza en 16K o 32K. Para archivos secuenciales grandes: más grande puede ayudar.
El valor correcto depende de la forma de IO, no de la velocidad del enlace.
7) ¿La compresión ayuda o perjudica el rendimiento NFS?
A menudo ayuda. Menos datos sobre disco y red, a veces mejor utilización de cache. lz4 es la elección habitual. Si la CPU está totalmente ocupada y el IO es bajo,
entonces considera probar, pero no desactives compresión por superstición.
8) ¿Por qué mi share NFS se siente lento solo en horas pico?
Congestión y colas. Revisa retransmisiones, utilización de puerto del switch, pérdidas de interfaz y carga de softirq en el servidor. El almacenamiento puede estar bien; la red puede estar
acumulando colas que inflan la latencia tail.
9) ¿Debo usar un special vdev?
Si tu carga es intensiva en metadata o tienes millones de archivos pequeños, un special vdev en SSDs rápidos puede ser una mejora radical.
Pero trátalo como un vdev crítico: ponlo en espejo y móntoréalo, porque perderlo puede implicar perder el pool según la configuración.
10) ¿Cómo sé si el cuello de botella es el servidor NFS o el pool ZFS?
Mira nfsstat -s del lado servidor para la mezcla de operaciones y volumen, luego correlaciónalo con zpool iostat. Si las ops NFS suben pero el pool está inactivo,
sospecha CPU/threading/red. Si IOPS y latencia del pool suben, sospecha diseño del almacenamiento (camino sync, layout de vdevs, recordsize, misses de cache).
Conclusión: pasos prácticos siguientes
Si quieres que ZFS sobre NFS se sienta como disco local, optimiza para la latencia tail y las semánticas, no para gráficos bonitos de throughput.
Empieza con lo básico: confirma montajes, confirma salud de la red, observa la forma de IO, luego alinea propiedades de datasets ZFS a la carga.
- Ejecuta las dos pruebas rápidas en cliente: sync-flush y throughput secuencial (Tareas 13 y 14). Decide si peleas contra latencia o ancho de banda.
- Verifica opciones NFS negociadas y corrige desajustes (Tareas 1–2). No depures lo que no configuraste realmente.
- Revisa RTT de red y retransmisiones (Tareas 3–4). Si se pierden paquetes, el ajuste de almacenamiento es una negación elaborada.
- En el servidor, correlaciona mezcla de ops NFS con comportamiento del pool ZFS (Tareas 7–9). Identifica si es metadata, sync o IO bruto.
- Aplica cambios ZFS dirigidos: recordsize por carga, compresión activada, atime off, y un SLOG adecuado donde sync importe (Tareas 10–12).
Luego anota lo que elegiste y por qué. Tú del futuro estará cansado, on-call y alérgico a perillas misteriosas.