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)
- 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”.
- 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.
- 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.
- 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”.
- 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.
- 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.
- 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.
- 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
awaiten vdevs, caminosyncde ZFS bloqueado, SLOG ausente/lento, pool casi lleno o fragmentado.
Tercero: valida comportamiento sync (este suele ser el villano)
- Revisa la propiedad
syncdel 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 dexattry 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:
- ¿El cliente está esperando al servidor (latencia), o no está enviando (throttling del cliente)?
- ¿El servidor espera a vaciados de disco (ruta sync) o a la CPU (signing/encryption) o a la red?
- ¿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=alwayspara shares con cumplimiento estricto. Espera menor throughput; diseña almacenamiento en consecuencia. - Desactivar sync:
sync=disabledes 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=1Msi 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
- Confirma salud del pool:
zpool status -v. Si está degradado o con errores, detente y arregla discos. - Revisa llenado del pool:
zfs list. Si >85% usado, planifica recuperación/expansión de espacio. - Identifica dataset y propiedades:
zfs get recordsize,atime,sync,compression. - Inspecciona configuración del share Samba:
testparm -svbuscandostrict sync, ajustesaio, módulos VFS. - Mide latencia sync: prueba servidor-side
dd ... conv=fdatasync. Si es lenta, es tu principal sospechosa. - Comprueba presencia/rendimiento de SLOG:
zpool statuspara logs y asegurarse de que la clase de dispositivo sea apropiada. - Observa latencia de disco bajo carga:
iostat -xyzpool iostatmientras reproduces. - Verifica salud de red:
ip -s link, retransmisiones (netstat -s) y velocidad de enlace (ethtool). - Aplica un cambio a la vez: por ejemplo, desactiva
strict syncen un share de prueba o añade SLOG; luego repite la misma transferencia y compara. - 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 dezfs get,ip -s linky 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.
- Elige una prueba reproducible (un archivo grande y una carpeta de “muchos archivos pequeños”) y mantenla constante.
- Ejecuta la guía rápida de diagnóstico y captura salidas:
zpool iostat,iostat -x,ip -s link,netstat -s,smbstatus. - Prueba o elimina la latencia sync con la prueba servidor-side
dd ... conv=fdatasyncen el dataset. - Separa datasets por carga si no lo has hecho. Ajusta
atime=offy unrecordsizesensato por categoría. - 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í.
- 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.