ZFS SMB: Solucionar de verdad “Copia lenta en Windows”

¿Te fue útil?

Windows Explorer muestra “Copiando… 112 MB/s” durante tres segundos, luego cae a 0 B/s y se queda allí como si estuviera reflexionando sobre su vida. Los usuarios culpan “la red”. La red culpa “el almacenamiento”. El almacenamiento culpa “Windows”. Cada uno tiene una parte de error distinta.

Si ejecutas SMB respaldado por ZFS (normalmente Samba en Linux, a veces en un appliance de almacenamiento), puedes hacer que las copias desde Windows sean consistentemente rápidas. Pero no lo consigues girando perillas al azar. Lo haces demostrando de dónde viene la latencia y luego arreglando la parte específica que está fallando.

Qué significa realmente “copia lenta” (y qué no es)

“La copia en Windows es lenta” no es un problema único. Es un síntoma visible por el usuario de una canalización que incluye: comportamiento del cliente Windows, semántica del protocolo SMB, detalles de implementación de Samba, grupos de transacciones y rutas de escritura de ZFS, y latencia del medio físico. Tu tarea es encontrar la etapa que convierte ancho de banda en espera.

Los tres patrones de copia que debes separar

  • Copias grandes y secuenciales (p. ej., ISO, VHDX): deberían correr cerca de la velocidad del enlace hasta que el servidor no pueda comprometer escrituras lo suficientemente rápido.
  • Muchos archivos pequeños (p. ej., árboles de código): dominados por metadata (create, setattr, close, rename), no por el throughput.
  • Cargas mixtas (carpetas personales + VMs + escáneres): “lento” suele ser bloqueo por cabeza de línea: un patrón malo arruina la cola para todos.

Lo que normalmente no es

Rara vez es “SMB es lento”. SMB3 puede ser muy rápido. Rara vez es “ZFS es lento”. ZFS puede saturar redes serias. Suele ser picos de latencia por escrituras síncronas, I/O aleatorio pequeño, amplificación de metadata o alineación de caché deficiente, visibles por un cliente que reporta velocidad en ráfagas optimistas.

Un cambio de encuadre más: Windows Explorer no es una herramienta de benchmark; es un visualizador de ansiedad. Ese gráfico es más anillo de humor que osciloscopio.

Hechos interesantes y contexto histórico (para entender el comportamiento)

  1. SMB1 vs SMB2/3 lo cambió todo. SMB2 (era Vista/2008) redujo la verbosidad, aumentó lecturas/escrituras y añadió pipelining. Muchas historias de “SMB es lento” en realidad son “estás atascado en SMB1”.
  2. Samba empezó como un proyecto reimplementado. Creció desde “hacer que UNIX hable con Windows” hasta un servidor SMB de nivel empresarial. Algunas configuraciones por defecto son conservadoras porque Samba debe sobrevivir clientes raros.
  3. Las escrituras de ZFS se agrupan. ZFS compromete datos en grupos de transacciones (TXGs). Eso hace que el throughput sea excelente, pero también crea un comportamiento de “pulso” visible si la fase de commit se atrasa.
  4. Las escrituras síncronas son una promesa, no una sensación. Cuando un cliente SMB solicita durabilidad, ZFS debe comprometer de forma segura. Si tu pool no puede hacer fsync de baja latencia, obtendrás el clásico gráfico “rápido y luego cero”.
  5. Los manejadores durables y los leases de SMB cambiaron el comportamiento de close/open. Windows moderno cachea agresivamente. Eso es bueno, hasta que una aplicación fuerza semánticas de durabilidad y convierte el caching en dolor síncrono.
  6. Recordsize importa más para compartidos que la gente admite. El recordsize de ZFS modela la amplificación de I/O. Un recordsize incorrecto no solo desperdicia espacio: fuerza IOPS extra bajo accesos aleatorios pequeños.
  7. La compresión suele ayudar en SMB, incluso con CPUs rápidas. Muchos archivos de oficina se comprimen bien, reduciendo carga de disco y red. La ganancia suele ser en latencia, no en ancho de banda puro.
  8. El signing de SMB se volvió más común por seguridad. Activar signing puede costar CPU. La configuración “segura” a veces se convierte en “seguramente lenta” cuando el servidor tiene CPU débil o está limitado por un solo hilo.

Guía rápida de diagnóstico

Este es el orden que encuentra el cuello de botella rápido, sin caer en la trampa de “afinar todo”.

Primero: clasifica la carga

  • ¿Un archivo grande? ¿Muchos archivos pequeños? ¿Escrituras de aplicación con requisitos de durabilidad?
  • ¿La velocidad cae a intervalos fijos (cada pocos segundos)? Eso huele a latencia de commit de TXG.
  • ¿Ocurre solo en ciertos shares? Eso huele a propiedades del dataset o a opciones del share SMB.

Segundo: decide si es red, CPU o latencia de almacenamiento

  • Red: errores de interfaz, retransmisiones, MTU incorrecto, hashing LACP malo, clientes Wi‑Fi fingiendo ser servidores.
  • CPU: un núcleo saturado en smbd, sobrecarga por signing/encryption, interrupciones, saturación de softirq.
  • Latencia de almacenamiento: alto await en vdevs, camino sync de ZFS bloqueado, SLOG ausente/lento, pool casi lleno o fragmentado.

Tercero: valida comportamiento sync (este suele ser el villano)

  • Revisa la propiedad sync del dataset y las configuraciones de Samba que fuerzan sync (p. ej., strict sync).
  • Mide la latencia de fsync desde el host SMB, no desde tu portátil.
  • Si necesitas semánticas sync, asegúrate de un SLOG apropiado (protegido contra pérdida de energía) o acepta los límites de rendimiento de tus vdevs principales.

Cuarto: aisla el caso de “muchos archivos pequeños”

  • La metadata es la carga. Revisa atime, comportamiento de xattr y rendimiento de bloques pequeños.
  • Verifica que el layout del pool coincida con las expectativas de IOPS de metadata (tradeoffs espejos vs RAIDZ).

Quinto: ajusta solo lo que las mediciones implican

Si no puedes mostrar un antes/después en latencia de I/O, utilización de CPU o retransmisiones, no estás afinando: estás adornando.

Deja de adivinar: mide a dónde va el tiempo

Las copias SMB son una negociación entre un cliente que hace buffering y un servidor que compromete. Explorer reporta “velocidad” basado en qué tan rápido los datos son aceptados en buffers, no en qué tan rápido son escritos de forma duradera. Mientras tanto, ZFS puede aceptar datos rápidamente en ARC y buffers sucios, luego pausar mientras compromete TXGs. Esa pausa es donde el gráfico llega a cero.

Tu plan de medición debe responder tres preguntas:

  1. ¿El cliente está esperando al servidor (latencia), o no está enviando (throttling del cliente)?
  2. ¿El servidor espera a vaciados de disco (ruta sync) o a la CPU (signing/encryption) o a la red?
  3. ¿ZFS amplifica la carga (mismatch de recordsize, fragmentación, presión de metadata)?

Ingeniería de confiabilidad tiene una regla simple aplicable aquí: mide el sistema que tienes, no el sistema que quisieras tener.

Idea parafraseada (Gene Kim): “Mejorar el flujo significa encontrar y eliminar la restricción.” Ese es todo el juego.

Realidades de ZFS que afectan a SMB

TXGs y el patrón “rápido y luego cero”

ZFS acumula datos sucios en memoria y periódicamente los compromete a disco como un grupo de transacción. Si la fase de commit toma demasiado tiempo, el sistema restringe a los escritores. Desde la vista del cliente: ráfaga rápida, luego stall. Repetir. Eso no es “jitter de red”. Es la durabilidad del almacenamiento poniéndose al día.

Escrituras síncronas: el impuesto de durabilidad

Cuando la carga emite escrituras síncronas (o cuando el servidor las trata así), ZFS debe asegurar que los datos estén en almacenamiento estable antes de reconocerlos. En pools sin un dispositivo de intent log rápido, las escrituras síncronas impactan tus vdevs principales. Si éstos son RAIDZ con HDDs, puedes predecir el resultado: dolor con marca temporal.

Recordsize, ashift y amplificación de I/O

El recordsize de ZFS controla el tamaño máximo de bloque para datos de archivo. Los compartidos SMB suelen almacenar archivos de tamaños mixtos; un recordsize demasiado grande no siempre dañará lecturas secuenciales, pero puede perjudicar escrituras aleatorias y sobreescrituras parciales. Uno demasiado pequeño puede aumentar la sobrecarga de metadata y reducir la eficiencia de compresión.

La metadata no es “gratis”

Las copias de archivos pequeños estresan la metadata: entradas de directorio, ACLs, xattrs, marcas de tiempo. ZFS puede manejar esto bien, pero solo si el layout del pool y la caché son sensatos. Si construiste un RAIDZ ancho para capacidad y luego lo usaste como un share SMB intensivo en metadata, básicamente compraste un autobús y lo inscribiste en una carrera de motocicletas.

Llenado del pool y fragmentación

A medida que los pools se llenan, la asignación se vuelve más difícil, la fragmentación sube y la latencia aumenta. Los usuarios SMB experimentan esto como “estaba bien el mes pasado”. ZFS no olvida repentinamente cómo escribir; se queda sin lugares fáciles para poner bloques.

Realidades de SMB que afectan a ZFS

Semántica de copia en Windows: buffering, close y durabilidad

Windows puede hacer buffering de escrituras y solo forzar durabilidad al cerrar el archivo, dependiendo de flags de aplicación y configuración del servidor. Algunas apps (y algunas herramientas de seguridad) solicitan write-through. Eso convierte tu carga de “mayormente async” a “intensamente sync” al instante.

Signing y encriptación: la seguridad tiene coste en CPU

El signing de SMB suele ser exigido por políticas. La encriptación puede estar habilitada para ciertos shares. Ambos consumen CPU. Si tu servidor SMB tiene una CPU modesta con NIC rápida, puedes alcanzar un techo donde la red está inactiva y un núcleo está sudando por la criptografía.

SMB3 Multichannel: genial cuando funciona, irrelevante cuando no

Multichannel puede usar múltiples NICs y colas RSS. Cuando está mal configurado, obtienes exactamente un flujo TCP atascado en una cola. Entonces alguien dice “pero tenemos doble 10GbE” como si el servidor estuviera obligado a ocuparse.

Opportunistic locks, leases y antivirus

El caching del cliente (oplocks/leases) reduce la verbosidad. Pero los escáneres de seguridad de endpoints adoran abrir archivos, forzar actualizaciones de atributos y, en general, romper el comportamiento de caching. Esto puede convertir una copia de “muchos archivos pequeños” en un festival de llamadas al sistema.

Broma #1: El troubleshooting de SMB es como la política de oficina: todos insisten en que son el cuello de botella y, de alguna manera, todos tienen razón.

Tareas prácticas: comandos, salidas, decisiones

A continuación hay tareas reales que puedes ejecutar en el servidor SMB/ZFS. Cada una incluye qué significa la salida y qué decisión debes tomar después. Están sesgadas hacia Linux + Samba + OpenZFS, porque ahí viven la mayoría de los tickets “la copia en Windows es lenta”.

Tarea 1: Confirma la salud del pool (porque el rendimiento suele ser síntoma de un disco moribundo)

cr0x@server:~$ sudo zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 04:12:19 with 0 errors on Tue Dec 10 03:20:01 2025
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          mirror-0                  ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_A   ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_B   ONLINE       0     0     0

errors: No known data errors

Significado: “ONLINE” y scrub limpio significa que no estás luchando contra reintentos silenciosos o carga de resilver. Si ves DEGRADED, resilvering o errores de checksum, detén el tuning y arregla el hardware primero.

Decisión: Si algún vdev muestra errores o actividad de resilver, programa remediación y vuelve a probar el rendimiento después de la estabilización.

Tarea 2: Revisa el llenado del pool (los pools casi llenos se vuelven lentos de forma predecible)

cr0x@server:~$ zfs list -o name,used,avail,refer,mountpoint tank
NAME   USED  AVAIL  REFER  MOUNTPOINT
tank   38.2T 2.1T   96K    /tank

Significado: ~95% usado (38.2T usados, 2.1T disponibles) es zona de peligro para muchas cargas. La asignación se vuelve restringida; la fragmentación sube.

Decisión: Si estás por encima de ~80–85% usado y el rendimiento importa, planifica recuperar/expandir espacio. Ningún ajuste de Samba vencerá a la física.

Tarea 3: Identifica qué dataset respalda el share SMB y muestra sus propiedades clave

cr0x@server:~$ sudo zfs get -H -o property,value recordsize,compression,atime,sync,xattr,acltype,primarycache,logbias tank/shares/engineering
recordsize	1M
compression	lz4
atime	on
sync	standard
xattr	sa
acltype	posixacl
primarycache	all
logbias	latency

Significado: Tienes recordsize 1M (bueno para archivos grandes secuenciales, riesgoso para sobreescrituras parciales), atime activado (escrituras de metadata extra), sync standard (sync respetado), xattr en SA (suele ser bueno), logbias latency (prefiere SLOG si está presente).

Decisión: Si el share es de “muchos archivos pequeños”, considera recordsize=128K y atime=off. Si son imágenes de VM, trátalo diferente (y probablemente no vía SMB).

Tarea 4: Mide latencia de I/O del pool durante una copia (la verdad está en iostat)

cr0x@server:~$ sudo zpool iostat -v tank 1 5
                              capacity     operations     bandwidth
pool                        alloc   free   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----
tank                        38.2T  2.1T     12   2400   3.1M   210M
  mirror-0                  38.2T  2.1T     12   2400   3.1M   210M
    ata-SAMSUNG_SSD_1TB_A      -      -      6   1250   1.6M   108M
    ata-SAMSUNG_SSD_1TB_B      -      -      6   1150   1.5M   102M
--------------------------  -----  -----  -----  -----  -----  -----

Significado: Operaciones de escritura altas (2400/s) con ancho de banda moderado sugiere escrituras pequeñas o comportamiento intensivo en sync. Si el ancho de banda es bajo pero las ops son altas, estás limitado por IOPS o por flushes.

Decisión: Si las escrituras son pequeñas y frecuentes, investiga semánticas sync, carga de metadata y mismatch de recordsize. Si las ops son bajas y el ancho de banda es bajo, sospecha red o throttling SMB.

Tarea 5: Observa latencia por vdev con iostat (await es la alarma)

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

Device            r/s     w/s   rkB/s   wkB/s  avgrq-sz avgqu-sz   await  r_await  w_await  svctm  %util
nvme0n1           2.0   950.0    64.0 118000.0   248.0     3.20    3.4     1.2      3.4    0.6   58.0
nvme1n1           1.0   910.0    32.0 112000.0   246.0     3.05    3.3     1.1      3.3    0.6   55.0

Significado: ~3.3ms de await en escritura está bien para NVMe. Si ves decenas/centenas de ms durante copias, el almacenamiento está limitando tu throughput.

Decisión: Await alto + CPU baja + red limpia = problema en la ruta de almacenamiento (escrituras sync, pool lleno, vdevs lentos o problemas con SLOG).

Tarea 6: Comprueba si tienes un SLOG (y si está haciendo algo)

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

        NAME                         STATE     READ WRITE CKSUM
        tank                         ONLINE       0     0     0
          mirror-0                   ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_A    ONLINE       0     0     0
            ata-SAMSUNG_SSD_1TB_B    ONLINE       0     0     0
        logs
          nvme-SLOG_INTEL_OPTANE     ONLINE       0     0     0

Significado: Hay un dispositivo de log separado. Bien. Pero la existencia no es rendimiento; debe ser rápido y protegido contra pérdida de energía.

Decisión: Si existen cargas sync y no hay SLOG, decide si necesitas semánticas sync. Si las necesitas, añade un SLOG adecuado. Si no, no lo falsifiques con sync=disabled a menos que estés cómodo perdiendo datos reconocidos en un corte de energía.

Tarea 7: Observa throttling de TXG y comportamiento de datos sucios

cr0x@server:~$ sudo arcstat 1 3
    time  read  miss  miss%  dmis  dm%  pmis  pm%  mmis  mm%  arcsz     c  avail
12:10:01   320    12      4     1    0    11    3     0    0   84.2G  96.0G  21.4G
12:10:02   410    16      3     2    0    14    3     0    0   84.2G  96.0G  21.4G
12:10:03   390    10      2     1    0     9    2     0    0   84.2G  96.0G  21.4G

Significado: ARC no está fallando gravemente; el caching no es tu restricción actual. Si ARC es pequeño respecto a la memoria, o los misses se disparan, podrías estar limitado por memoria o mal configurado.

Decisión: Si los misses de ARC son altos durante lecturas, ajusta tamaño de memoria/ARC o el working set (o acepta que la carga no cachea bien).

Tarea 8: Confirma versión de Samba y si se negoció SMB3

cr0x@server:~$ smbd -V
Version 4.19.5-Debian

cr0x@server:~$ sudo smbstatus -b | sed -n '1,60p'
Samba version 4.19.5-Debian
PID     Username     Group        Machine                                   Protocol Version  Encryption           Signing
-------------------------------------------------------------------------------------------------------------------------
23144   user1        domain users  10.10.20.55 (ipv4:10.10.20.55:53122)     SMB3_11           -                    partial

Significado: Se negoció SMB3_11, bien. El signing está “partial” (depende de configuración y cliente). Si ves SMB1, tienes problemas mayores que tuning.

Decisión: Si aparece SMB1, desactívalo y arregla la compatibilidad del cliente intencionalmente. No mantengas SMB1 “por ese escáner legado”. Reemplaza el escáner o aíslelo.

Tarea 9: Revisa la configuración del share Samba en busca de killers de sync (strict sync, sync always)

cr0x@server:~$ sudo testparm -sv | sed -n '/^\[engineering\]/,/^\[/{p}'
[engineering]
	path = /tank/shares/engineering
	read only = No
	vfs objects = acl_xattr
	strict sync = Yes
	sync always = No

Significado: strict sync = Yes fuerza a Samba a vaciar más operaciones. Esta es una clásica configuración “la activamos por seguridad” que puede hundir el throughput.

Decisión: Si no tienes una necesidad de cumplimiento para semánticas estrictas, pon strict sync = No y valida la corrección de las aplicaciones. Si la necesitas, invierte en SLOG y almacenamiento de baja latencia.

Tarea 10: Verifica si signing/encryption están activados y si la CPU es el limitante

cr0x@server:~$ sudo smbstatus -b | awk 'NR==1 || NR==2 || $0 ~ /SMB3/'
Samba version 4.19.5-Debian
PID     Username     Group        Machine                                   Protocol Version  Encryption           Signing
23144   user1        domain users  10.10.20.55 (ipv4:10.10.20.55:53122)     SMB3_11           AES-128-GCM          mandatory

cr0x@server:~$ top -b -n 1 | sed -n '1,20p'
top - 12:12:41 up 34 days,  3:01,  2 users,  load average: 9.12, 8.40, 7.95
Tasks: 291 total,   2 running, 289 sleeping,   0 stopped,   0 zombie
%Cpu(s): 12.1 us,  2.0 sy,  0.0 ni, 78.0 id,  0.0 wa,  0.0 hi,  7.9 si,  0.0 st
MiB Mem :  256000.0 total,  21000.0 free,  95000.0 used, 140000.0 buff/cache

Significado: La encriptación está activada. La CPU está mayormente inactiva aquí, por lo que la encriptación probablemente no es el cuello de botella en este momento. Si ves un núcleo pegado y softirq alto, vuelve a revisar.

Decisión: Si encryption/signing es obligatorio y la CPU está caliente, actualiza CPU, usa sistemas con AES-NI, asegúrate de RSS y multiqueue, o limita la encriptación a shares sensibles.

Tarea 11: Verifica enlace NIC, duplex y contadores de errores (chequeos baratos, consecuencias caras)

cr0x@server:~$ ip -s link show dev bond0
2: bond0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 9c:dc:71:aa:bb:cc brd ff:ff:ff:ff:ff:ff
    RX:  bytes packets errors dropped  missed   mcast
    1223344556677 1023344556      0       0       0  120034
    TX:  bytes packets errors dropped carrier collsns
    1334455667788 1124455667      0       0       0       0

cr0x@server:~$ ethtool bond0 | sed -n '1,25p'
Settings for bond0:
	Supported ports: [ ]
	Supported link modes:   Not reported
	Speed: 20000Mb/s
	Duplex: Full
	Auto-negotiation: off

Significado: Sin errores, full duplex, velocidad esperada. Si ves errores o drops, arregla la red antes de tocar ZFS.

Decisión: Si existen errores: revisa cableado, puertos del switch, consistencia de MTU y opciones de offload. Afinar sobre pérdida de paquetes es teatro de rendimiento.

Tarea 12: Revisa retransmisiones TCP y presión de sockets (SMB sobre una red enferma es mentira)

cr0x@server:~$ ss -s
Total: 884
TCP:   211 (estab 104, closed 72, orphaned 0, timewait 72)

Transport Total     IP        IPv6
RAW	  0         0         0
UDP	  11        8         3
TCP	  139       113       26
INET	  150       121       29
FRAG	  0         0         0

cr0x@server:~$ netstat -s | sed -n '1,80p'
Tcp:
    154239 active connection openings
    149802 passive connection openings
    1124 failed connection attempts
    1821 connection resets received
    0 connections established
    224159 segments received
    231008 segments sent out
    214 segments retransmitted

Significado: Existen retransmisiones pero no son locas. Si las retransmisiones saltan durante copias, verás stalls no relacionados con almacenamiento. SMB es sensible a picos de latencia.

Decisión: Retransmisiones altas: inspecciona buffers del switch, mismatch de MTU, driver/firmware de NIC o un path de firewall sobrecargado.

Tarea 13: Identifica si la carga es sync-heavy (prueba de fsync del servidor)

cr0x@server:~$ sync; sudo bash -c 'time dd if=/dev/zero of=/tank/shares/engineering/.fsync-test bs=1M count=256 conv=fdatasync status=none'
real	0m1.92s
user	0m0.00s
sys	0m0.28s

cr0x@server:~$ sudo rm -f /tank/shares/engineering/.fsync-test

Significado: Esto mide “escribir y luego forzar durabilidad”. Si esto es lento (p. ej., 10–60s), tu pool no puede comprometer escrituras sync lo suficientemente rápido para cargas SMB que las requieran.

Decisión: fsync lento: añade/valida SLOG, reduce flushes forzados en Samba si es aceptable, o rediseña almacenamiento para escrituras de baja latencia.

Tarea 14: Confirma que el dataset no está forzando sync accidentalmente (o lo contrario)

cr0x@server:~$ sudo zfs get -H -o name,property,value sync tank/shares/engineering tank/shares/finance
tank/shares/engineering	sync	standard
tank/shares/finance	sync	always

Significado: El share finance está forzado a sync=always. Eso puede ser intencional (apps que necesitan durabilidad) o una mala configuración que lo hace lento.

Decisión: Si sync=always existe, confirma con los dueños de la app por qué. Si nadie lo justifica, vuelve a standard y prueba.

Tarea 15: Revisa compresión y ratio real (porque “activamos compresión” no es igual a “está funcionando”)

cr0x@server:~$ zfs get -H -o name,property,value compression,compressratio tank/shares/engineering
tank/shares/engineering	compression	lz4
tank/shares/engineering	compressratio	1.62x

Significado: 1.62x significa que estás ahorrando I/O y espacio. Si el ratio está ~1.00x, la compresión no ayuda mucho pero normalmente LZ4 no perjudica.

Decisión: Mantén LZ4 casi siempre. Solo desactívalo si mides saturación de CPU y datos casi incomprimibles.

Tarea 16: Busca fragmentación patológica (especialmente si el pool es antiguo y casi lleno)

cr0x@server:~$ sudo zdb -bbbs tank | sed -n '1,40p'
Block Size Histogram:
 512: 0
 1K : 0
 2K : 1048576
 4K : 2097152
 8K : 1048576
 16K: 524288
 32K: 262144
 64K: 131072
 128K: 65536
 256K: 32768
 512K: 16384
 1M : 8192

Significado: Esto es una vista aproximada; en la práctica correlacionarás fragmentación con comportamiento de asignación y latencia. Una alta diversidad de bloques pequeños en un dataset pensado para escrituras grandes secuenciales puede ser una pista.

Decisión: Si la fragmentación y el llenado son altos, planifica migración de datos o expansión del pool. ZFS es excelente, pero no se desfragmenta por desearlo.

Tres microhistorias del mundo corporativo

Microhistoria 1: El incidente causado por una suposición equivocada

Tuvieron un servidor de archivos ZFS nuevo y dos uplinks 10GbE. El despliegue se veía bien la primera semana, sobre todo porque la prueba fue “copiar un ISO de 20GB una vez” y todos se fueron a casa contentos.

Luego llegó el cierre de trimestre. Finanzas volcó miles de PDFs y hojas de cálculo pequeñas en un share desde una app Windows que insistía en write-through. Los usuarios reportaron copias “que se detenían cada pocos segundos”. El equipo de red no vio saturación, así que se declararon victoriosos y culparon a Windows. El equipo de almacenamiento vio mucha RAM libre y asumió que ARC lo suavizaría. No lo hizo.

La suposición equivocada fue sutil: “Si el pool puede hacer 1GB/s en escrituras secuenciales, puede hacer copias de archivos de oficina”. Son deportes distintos. El ancho de banda secuencial es una vuelta de victoria; la metadata sincrónica es el circuito de obstáculos.

Una vez que alguien ejecutó un simple dd ... conv=fdatasync en el dataset, quedó obvio. La latencia de commit sync era el cuello de botella. El pool era RAIDZ en HDDs. Perfecto para capacidad, terrible para durabilidad de baja latencia.

La solución también fue sutil: no desactivaron sync. Agregaron un SLOG apropiado protegido contra pérdida de energía y quitaron strict sync de los shares que no lo requerían. Finanzas mantuvo sus semánticas; engineering recuperó su velocidad. Los tickets del helpdesk se detuvieron, que es el único KPI que importa cuando estás de guardia.

Microhistoria 2: La optimización que salió mal

Otra empresa tenía copias lentas de directorios personales. Alguien leyó en un foro y decidió que “recordsize más grande = más rápido”. Así que pusieron recordsize=1M en todos los datasets SMB, incluidos directorios personales y árboles de proyectos compartidos.

Las copias de archivos grandes mejoraron ligeramente. Luego las quejas se volvieron raras: guardar documentos pequeños se sentía lento, el acceso a PST de Outlook se volvió inestable y algunas apps empezaron a “no responder” al guardar. El servidor SMB no estaba caído; simplemente hacía trabajo extra.

¿Por qué? Las sobreescrituras parciales en registros grandes pueden crear amplificación de escritura. Un pequeño cambio en un archivo puede desencadenar un read-modify-write de un bloque grande, especialmente cuando la carga es aleatoria y la app hace muchas actualizaciones pequeñas. ZFS es copy-on-write, así que ya hace contabilidad cuidadosa; añadir amplificación es como pedirle que haga malabarismos en una caminadora.

La “optimización” que salió mal también incrementó la agitación de metadata porque los perfiles de usuario generan montones de archivos diminutos y actualizaciones de atributos. Un recordsize mayor no ayudó el camino de metadata en absoluto. Solo empeoró el camino de datos.

El rollback fue disciplinado: separaron datasets por carga. Directorios personales fueron a recordsize 128K, atime off. Los archivos de medios/proyectos grandes se quedaron en 1M. El rendimiento se estabilizó. La lección perduró: afinar no es un buffet donde pones todo lo que parece apetitoso.

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

Un equipo con un cluster ZFS + Samba tenía un hábito poco glamuroso: reportes de scrub semanales y snapshots de rendimiento mensuales. No dashboards para pared ejecutiva. Solo un archivo de texto con zpool status, zpool iostat bajo carga y contadores básicos de errores NIC.

Un martes, los usuarios reportaron que las copias se habían vuelto “espigadas”. El ingeniero de guardia no adivinó. Sacó la línea base y la comparó con los números actuales. El gran cambio: la latencia de escritura en una pata del mirror había subido, y aparecían errores corregibles—lo suficiente para disparar reintentos, no para fallar el disco.

Porque tenían datos de referencia, no pasaron media jornada discutiendo sobre flags de Samba. Reemplazaron el disco durante una ventana de mantenimiento, resilverearon y los stalls de copia desaparecieron.

No pasó nada heroico. Ningún tunable mágico. Solo notar que una “regresión de rendimiento” a menudo es “hardware envejeciendo lentamente”. Esto es lo que la competencia aburrida parece en producción.

Decisiones de ajuste que realmente impactan

1) Decide explícitamente tu postura sobre sync (no dejes que te suceda)

Las cargas SMB pueden ser intensivas en sync, especialmente con ciertas aplicaciones y políticas. Tienes tres opciones:

  • Respetar sync y pagarlo: mantener sync=standard, evitar configuraciones de Samba que forcen flushes extra, y desplegar un SLOG real si se necesita.
  • Forzar siempre sync: sync=always para shares con cumplimiento estricto. Espera menor throughput; diseña almacenamiento en consecuencia.
  • Desactivar sync: sync=disabled es una decisión de negocio para arriesgar perder escrituras reconocidas en corte de energía o crash. Puede ser válido en shares temporales, pero no lo disimules como “rendimiento gratis”. Es un contrato de durabilidad distinto.

2) Separa datasets por carga (un share, un comportamiento)

Un dataset para todo es la forma más rápida de que nada funcione bien. Separa:

  • Directorios personales (intensivo en metadata, archivos pequeños)
  • Árboles de proyecto de engineering (muchos archivos pequeños, mayormente lectura)
  • Archivos de medios (grandes y secuenciales)
  • Zonas de caída de aplicaciones (pueden requerir durabilidad estricta)

Luego ajusta propiedades por dataset: recordsize, atime, sync, compresión, comportamiento de ACL.

3) Acierta el recordsize lo suficiente

  • Compartidos SMB generales: empieza con recordsize=128K.
  • Archivos grandes: considera recordsize=1M si la mayoría de archivos son grandes y secuenciales.
  • Bases de datos/VMs sobre SMB: evítalo si puedes; si debes, usa configuraciones especializadas y prueba a fondo. Servir archivos SMB y datastores de VM no es un matrimonio casual.

4) Apaga atime para shares SMB (salvo que tengas una razón real)

atime=on añade escrituras de metadata en lecturas. La mayoría de organizaciones no usa la hora de acceso para nada significativo, y Windows ciertamente no necesita que tu servidor ZFS escriba metadata extra cada vez que alguien abre un archivo.

5) Mantén LZ4 activado por defecto

LZ4 es uno de los pocos “por defecto” que defenderé en producción. A menudo mejora el throughput efectivo y reduce I/O. No lo sobrepienses hasta que tengas evidencia de saturación de CPU.

6) Usa un SLOG real cuando lo necesites (y no escatimes)

Un dispositivo SLOG no es “cualquier SSD”. Necesita baja latencia bajo carga de escrituras sync y protección contra pérdida de energía. Si no, construiste un generador de latencia caro.

7) Samba: evita “strict sync” salvo que lo justifiques

strict sync puede destruir el throughput para cargas que generan muchos puntos de fsync (incluyendo algunos comportamientos de Windows al cerrar archivos). Si necesitas semánticas estrictas, haz que el almacenamiento sea capaz. Si no, no lo pagues.

8) Signing/encryption SMB: limita su alcance

Los equipos de seguridad gustan de políticas globales. Los sistemas de producción gustan de presupuestos. Si signing/encryption debe ser obligatorio, asegura que el host SMB tenga margen de CPU y aceleración criptográfica moderna. Si solo ciertos shares contienen datos sensibles, delimita políticas por share o por segmento de tráfico.

Broma #2: Nada hace un servidor de archivos más rápido que una reunión de políticas que termina con “no cambiamos nada”.

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

1) Síntoma: La copia empieza rápida, luego cae a 0 B/s repetidamente

Causa raíz: Stalls de commit TXG por escrituras síncronas o latencia de flush lenta (sin SLOG, vdevs lentos, pool muy lleno).

Solución: Mide fsync (dd ... conv=fdatasync), verifica configuraciones sync de Samba, añade un SLOG apropiado o rediseña el pool para latencia, recupera espacio.

2) Síntoma: Archivos grandes copian bien; muchos archivos pequeños van lentos

Causa raíz: Carga limitada por metadata (ACLs, xattrs, timestamps) además de I/O aleatorio pequeño.

Solución: atime=off, asegúrate de propiedades adecuadas del dataset, considera espejos para pools intensivos en metadata, verifica que los módulos VFS de Samba no añadan sobrecarga, acepta que esto es IOPS no bandwidth.

3) Síntoma: Velocidad tope ~110 MB/s en “10GbE”

Causa raíz: Cliente/servidor negociado a 1GbE, hashing LACP malo, o flujo TCP único sin multichannel.

Solución: Revisa velocidad de enlace con ethtool, valida configuración del switch, prueba SMB multichannel y verifica que el cliente no esté en un segmento 1GbE.

4) Síntoma: Rendimiento peor tras activar signing o encriptación SMB

Causa raíz: Cuello de botella de CPU en crypto/signing, puntos calientes single-thread, colas RSS insuficientes.

Solución: Mide CPU por núcleo durante la transferencia, habilita multiqueue/RSS, actualiza CPU, delimita signing/encryption o usa hardware con aceleración.

5) Síntoma: Copias se cuelgan intermitentemente por “exactamente unos segundos”

Causa raíz: Retransmisiones de red, bufferbloat o congestión del switch; a veces la temporización de TXG alinea con las pausas percibidas.

Solución: Revisa retransmisiones (netstat -s), drops de interfaz y contadores del switch. Si está limpio, vuelve a la latencia de almacenamiento y sync.

6) Síntoma: Un share es lento; otro en el mismo servidor va bien

Causa raíz: Mismatch en propiedades del dataset (sync=always, recordsize raro, atime on), diferencias en config Samba (strict sync, módulos VFS) o cuotas/reservas afectando asignación.

Solución: Compara salidas de zfs get y bloques de testparm -sv para ambos shares. Normaliza intencionalmente.

7) Síntoma: “Windows dice que tomará 2 horas” pero el servidor parece inactivo

Causa raíz: Escaneo en el cliente (antivirus, indexación), sobrecarga de archivos pequeños o el cliente esperando por operaciones metadata por archivo.

Solución: Reproduce con un cliente limpio, prueba con opciones de robocopy y confirma métricas del servidor durante la operación. No ajustes servidores para compensar endpoints problemáticos.

Listas de verificación / plan paso a paso

Paso a paso: arreglar copias SMB “rápido y luego cero” en ZFS

  1. Confirma salud del pool: zpool status -v. Si está degradado o con errores, detente y arregla discos.
  2. Revisa llenado del pool: zfs list. Si >85% usado, planifica recuperación/expansión de espacio.
  3. Identifica dataset y propiedades: zfs get recordsize,atime,sync,compression.
  4. Inspecciona configuración del share Samba: testparm -sv buscando strict sync, ajustes aio, módulos VFS.
  5. Mide latencia sync: prueba servidor-side dd ... conv=fdatasync. Si es lenta, es tu principal sospechosa.
  6. Comprueba presencia/rendimiento de SLOG: zpool status para logs y asegurarse de que la clase de dispositivo sea apropiada.
  7. Observa latencia de disco bajo carga: iostat -x y zpool iostat mientras reproduces.
  8. Verifica salud de red: ip -s link, retransmisiones (netstat -s) y velocidad de enlace (ethtool).
  9. Aplica un cambio a la vez: por ejemplo, desactiva strict sync en un share de prueba o añade SLOG; luego repite la misma transferencia y compara.
  10. Anota el resultado: captura latencia, throughput y si los stalls desaparecieron. La memoria falla; los tickets no.

Checklist base (lo aburrido que agradecerás)

  • Scrub semanal programado; reportes de scrub revisados.
  • Snapshot mensual de: zpool status, propiedades clave de zfs get, ip -s link y una prueba repetible de throughput + fsync.
  • Layout de datasets documentado por categoría de carga.
  • Política explícita sobre sync: qué shares requieren garantías de durabilidad.
  • Control de cambios para la configuración de Samba; no “fixes de una línea” en producción a las 2am.

Preguntas frecuentes

1) ¿Por qué Explorer muestra velocidad alta y luego 0 B/s?

Explorer reporta basado en buffering y aceptación a corto plazo. ZFS y Samba pueden aceptar datos rápido y luego hacer una pausa mientras comprometen escrituras sync o TXGs. Mide latencia del servidor.

2) ¿Es robocopy más rápido que Explorer?

A veces. La ventaja mayor es que robocopy es más predecible y scriptable, y expone reintentos y comportamiento por archivo. No arreglará la latencia sync del servidor.

3) ¿Debo poner sync=disabled para hacerlo rápido?

Sólo si aceptas perder escrituras reconocidas en corte de energía o crash. Para shares temporales puede ser aceptable. Para datos de negocio es una degradación de durabilidad, no un truco de tuning.

4) ¿Necesito un SLOG para SMB?

Si tu carga genera muchas escrituras sync (o las configuraciones de Samba fuerzan flushing estricto), un buen SLOG puede ser transformador. Si la carga es mayormente async, un SLOG no ayudará mucho.

5) ¿Qué recordsize debo usar para shares SMB?

Empieza en 128K para shares de propósito general. Usa 1M para archivos grandes secuenciales. Evita cambios globales; separa datasets por carga.

6) ¿Activar LZ4 ralentiza?

Normalmente no, y con frecuencia acelera al reducir I/O. Si la CPU ya está saturada (encryption/signing, carga intensa), mide antes de decidir.

7) ¿RAIDZ es malo para SMB?

No “malo”, pero RAIDZ es menos amigable con escrituras aleatorias pequeñas y cargas intensivas en metadata que los espejos. Si tu caso SMB son muchos archivos pequeños y comportamiento sync, los mirrors suelen ganar en latencia.

8) ¿Por qué un share SMB es lento y otros están bien?

Propiedades diferentes de dataset o opciones de share Samba. Busca sync=always, atime=on, recordsize extraño o strict sync activado en un solo share.

9) ¿SMB Multichannel lo arregla todo?

No. Puede aumentar throughput y resiliencia, pero no arreglará latencia de almacenamiento o stalls por sync. Además requiere NIC, driver y soporte del cliente correctos.

10) ¿Cómo sé si estoy limitado por CPU?

Durante la transferencia, uno o más núcleos estarán consistentemente altos, a menudo en smbd o en networking/crypto del kernel. Mientras tanto, discos y NICs no estarán saturados. Ese es tu indicio.

Próximos pasos que puedes ejecutar esta semana

Haz estos en orden. Cada paso aclara una decisión, y ninguno requiere fe.

  1. Elige una prueba reproducible (un archivo grande y una carpeta de “muchos archivos pequeños”) y mantenla constante.
  2. Ejecuta la guía rápida de diagnóstico y captura salidas: zpool iostat, iostat -x, ip -s link, netstat -s, smbstatus.
  3. Prueba o elimina la latencia sync con la prueba servidor-side dd ... conv=fdatasync en el dataset.
  4. Separa datasets por carga si no lo has hecho. Ajusta atime=off y un recordsize sensato por categoría.
  5. Arregla el verdadero cuello de botella: añade un SLOG apropiado para shares sync-heavy, recupera espacio si el pool está demasiado lleno, o atiende problemas de CPU/red si la evidencia apunta ahí.
  6. Escribe un runbook de una página con tus comandos base y salidas “normales”. El tú del futuro le comprará café al tú del pasado.

El objetivo no es un gráfico perfecto. El objetivo es rendimiento predecible bajo el contrato de durabilidad que realmente quieres ofrecer. Una vez que eliges ese contrato a propósito, ZFS y SMB dejan de ser misteriosos y pasan a ser… simplemente exigentes.

← Anterior
Docker: Copias de seguridad que nunca probaste — Cómo ejecutar correctamente un simulacro de restauración
Siguiente →
MySQL vs PostgreSQL: cargas JSON — atajo rápido o dolor a largo plazo

Deja un comentario