Ajuste de expanders SAS para ZFS: evitar saturación y cuellos de botella en los enlaces

¿Te fue útil?

Construiste un pool ZFS perfectamente razonable. Luego lo colocaste detrás de un expander SAS porque “es solo cableado, ¿no?”. Ahora los scrubs tardan una eternidad, los resilver avanzan a paso de tortuga y tu gráfica de latencia parece un sismógrafo durante un apocalipsis menor.

En este punto la gente culpa a ZFS. No lo hagas. La mayoría de las veces es la topología y las matemáticas del enlace: oversubscription, puertos estrechos, colas, arbitraje del expander o una HBA que está silenciosamente limitada por PCIe. La buena noticia: puedes diagnosticar esto rápido y arreglarlo sin convertir tu estante de almacenamiento en arte moderno.

Un modelo mental que no te fallará

Un expander SAS es un conmutador de paquetes para tramas SAS. Eso es todo. No es un multiplicador mágico de ancho de banda. Te da fan-out (muchos discos) detrás de menos enlaces ascendentes (hacia tu HBA), y programa el acceso en esos enlaces. Si la demanda agregada aguas abajo excede la capacidad upstream, no obtienes más rendimiento: obtienes contención, colas y latencia.

Cuando ZFS hace lecturas secuenciales grandes, puede que te salves con un expander sobresuscrito porque los discos son lentos y predecibles. Cuando ZFS realiza scrubs, resilvers, recorridos de metadatos y muchas E/S pequeñas concurrentes, los expanders se estresan de una forma que parece “picos de latencia aleatorios” en la capa de la aplicación.

Tres capas que pueden provocar un cuello de botella (y a menudo lo hacen)

  • Medio: comportamiento de HDD/SSD, SATA vs SAS, NCQ/TCQ, peculiaridades de firmware.
  • Transporte: enlaces SAS, puertos wide, arbitraje del expander, SATA tunneling (STP), zoning.
  • Host: profundidad de cola de la HBA, ajustes del driver, carriles PCIe, manejo de interrupciones, sobrecarga de CPU, planificación de ZFS.

La tarea es identificar qué capa te está limitando ahora mismo. No en teoría. No en la hoja de especificaciones. En tu rack a las 3 a.m. mientras el temporizador del resilver se ríe de ti.

Broma #1: Un expander SAS es como una oficina abierta: todos pueden colaborar, pero de algún modo nadie hace trabajo en las horas punta.

Hechos e historia: por qué se comportan así los expanders

Algo de contexto ayuda porque SAS tiene una larga historia de decisiones de diseño. Aquí puntos concretos que aparecen en sistemas reales:

  1. Los expanders SAS descienden de ideas de conmutación Fibre Channel, pero con direccionamiento más simple y un modelo de arbitraje distinto. La intuición de “es un switch” es correcta, pero los detalles de implementación difieren.
  2. SAS-1 (3 Gb/s), SAS-2 (6 Gb/s), SAS-3 (12 Gb/s) son tasas por lane; los puertos wide agrupan lanes (x2, x4, etc.). Tu “estante 12G” puede seguir siendo efectivamente “6G-ish” si negocia a menor velocidad.
  3. Los discos SATA detrás de expanders SAS usan STP (SATA Tunneling Protocol), que puede comportarse muy diferente bajo carga que SAS nativo. Algunos expanders manejan mal la contención STP.
  4. Los primeros expanders SAS-2 tenían extrañas peculiaridades de firmware: resets de enlace ante errores, mala equidad y extrañas interacciones con firmwares de HBA específicos. Mejoró, pero “actualiza firmware” sigue siendo un consejo útil.
  5. El porteo wide existe porque los lanes individuales no son suficientes. Un solo lane 12G es fantástico hasta que pones 24 discos detrás y empiezas un scrub.
  6. El zoning en expanders SAS es real, y una configuración errónea puede forzar tráfico por un camino estrecho o impedir que multipath funcione aunque esté cableado físicamente.
  7. El ajuste de profundidad de cola ha sido deporte desde los días de SCSI. Muy bajo desperdicia hardware; muy alto causa colapso de latencia. Linux moderno facilita el ajuste—y también facilita hacerlo mal.
  8. PCIe se volvió el limitador silencioso a medida que SAS se aceleró. Una HBA “12G” en carriles PCIe insuficientes puede ser el cuello de botella mucho antes que la tela SAS.

Una cita de ingeniería para llevar en el bolsillo cuando te tiente optimizar sin medir: “Si no lo puedes medir, no lo puedes mejorar.” — Peter Drucker. (Comúnmente atribuida; tómala como una idea parafraseada si eres quisquilloso.)

Matemáticas de topología y oversubscription (donde están los cadáveres)

Hablemos del fallo más común: tienes muchos discos y no suficiente ancho de banda upstream.

Conoce tus lanes, y deja de adivinar

El ancho de banda SAS es por lane, por dirección, aproximadamente:

  • 6G SAS: ~600 MB/s por lane después de codificación/sobrecarga (estimado).
  • 12G SAS: ~1200 MB/s por lane después de sobrecarga (estimado).

Los puertos wide combinan lanes. Un puerto x4 12G es aproximadamente “hasta ~4.8 GB/s por dirección” en el caso ideal. Los casos ideales son raros en producción, pero las matemáticas aún te dicen si estás soñando.

La oversubscription no es automáticamente mala

La oversubscription es normal porque los discos no siempre funcionan a tasa de línea. Con HDDs, cada unidad puede entregar ~200–280 MB/s secuencial, y mucho menos con E/S aleatoria. Puedes sobresuscribir y seguir bien si:

  • las cargas son intermitentes y no se sincronizan en muchos spindles,
  • hay suficiente caché (ARC/L2ARC) para absorber lecturas,
  • no ejecutas scrubs/resilvers en horas pico o los limitas sensiblemente.

Pero las operaciones de mantenimiento de ZFS son la carga sincronizada. Un scrub toca todo. Un resilver toca mucho y lo hace mientras el pool ya está degradado. Si tu uplink del expander es estrecho, estas operaciones se convierten en un atasco de tráfico a cámara lenta.

Topologías comunes y sus trampas

  • Un puerto HBA → un uplink del expander → muchos discos: lo más simple, y lo más fácil de saturar.
  • Dos puertos HBA → uplinks duales al mismo expander: puede ayudar, pero solo si wide porting o multipath están realmente negociados y el expander está configurado para ello.
  • Expanders duales (rutas redundantes) en un estante: bueno para disponibilidad; el rendimiento depende de cómo se balancea el tráfico y si el OS ve rutas distintas.
  • Expanders en cadena (daisy-chained): funciona, pero es fácil crear un “embudo” donde todo transita por un enlace. Los picos de latencia se vuelven tu personalidad.

Patrones de E/S de ZFS que estresan a los expanders

ZFS no es “una tarjeta RAID.” Es un sistema de almacenamiento que planifica E/S según transaction groups, disposición de vdev y políticas de colas. Esto importa porque los expanders son sensibles a la concurrencia y a la equidad.

Scrub/resilver: alto fan-out, sostenido, sensible a la equidad

Durante un scrub, ZFS lee todo el pool para verificar checksums. Es decir: muchos discos, muchas lecturas concurrentes y presión sostenida durante horas o días. Un uplink sobresuscrito se vuelve un punto de estrangulamiento compartido, y los expanders pueden introducir latencia adicional cuando los ciclos de arbitraje se saturan.

E/S aleatoria de bloques pequeños: metadatos y cargas sincronas

Aun si tu aplicación hace “escrituras secuenciales grandes”, los metadatos de ZFS, los indirect blocks y el comportamiento de asignación introducen E/S más pequeñas. Los expanders no odian la E/S pequeña; odian muchas órdenes pendientes compitiendo por un uplink restringido, especialmente con SATA detrás de STP.

Special vdevs y SLOG pueden ayudar, pero también enmascarar problemas de transporte

Un special vdev puede reducir E/S de metadatos en vdevs HDD. Un SLOG puede transformar la latencia de escrituras síncronas. Ninguno aumentará el ancho de banda del uplink del expander. Pueden reducir la demanda—y eso es excelente—pero no confundas “síntomas mejorados” con “tela reparada”.

Broma #2: Las estimaciones de tiempo de resilver son como los pronósticos meteorológicos: técnicamente derivadas, emocionalmente inexactas.

Guía rápida de diagnóstico

Estás de guardia. La latencia es alta. Un scrub está en curso. Alguien dice “el estante está lento”. Aquí tienes una secuencia rápida que encuentra el cuello de botella más veces de las que fallarás.

Primero: demuestra si el cuello de botella está en la tela SAS o en los discos

  1. Revisa la latencia por vdev en ZFS (¿todos los vdevs están lentos por igual, o sólo uno?): usa zpool iostat -v.
  2. Revisa tiempo de servicio por disco y colas: usa iostat -x y mira proxies tipo await/svctm (r_await/w_await), utilización y profundidad de cola.
  3. Revisa la negociación de enlace y la topología: usa systool/lsscsi/sas2ircu/storcli (según tu HBA) para confirmar 12G/6G y número de lanes.

Segundo: comprueba si estás saturando un uplink

  1. Mide el throughput agregado durante scrub/resilver y compáralo con lo teórico del uplink: ¿se estabiliza sospechosamente?
  2. Busca problemas de equidad: algunos discos muestran profundidades de cola enormes mientras otros están inactivos; eso es clásico arbitraje de expander o problema de pathing.
  3. Busca resets/reintentos: los errores de enlace causan retransmisiones y paradas que imitan “almacenamiento lento”.

Tercero: elimina cuellos de botella del lado del host

  1. Revisa ancho/velocidad PCIe para la HBA.
  2. Revisa presión de softirq/interrupciones en CPU si estás haciendo IOPS muy altos (los SSDs detrás de expanders pueden hacer eso).
  3. Revisa ajustes de profundidad de cola para dispositivos SCSI y el módulo/driver de la HBA.

Si solo haces tres cosas: zpool iostat -v, iostat -x y “¿a qué velocidad/anchura negoció la HBA?”, atraparás la mayoría de las fallas del mundo real.

Tareas prácticas: comandos, salidas y qué decidir

Estos no son snapshots bonitos de benchmark. Son los tipos de comandos que ejecutas cuando alguien espera en Slack una respuesta. Cada tarea incluye qué significa la salida y qué decisión tomar a continuación.

Task 1: Identificar latencia a nivel de pool y si está localizada

cr0x@server:~$ zpool iostat -v tank 5 3
                               capacity     operations     bandwidth
pool                         alloc   free   read  write   read  write
---------------------------  -----  -----  -----  -----  -----  -----
tank                         120T   80.0T  1.20K   220   1.10G  180M
  raidz2-0                    60T   40.0T    620   120   560M   95M
    sda                           -      -    78    15   70M   12M
    sdb                           -      -    77    14   70M   12M
    sdc                           -      -    76    15   69M   12M
  raidz2-1                    60T   40.0T    580   100   540M   85M
    sdd                           -      -    74    13   68M   11M
    sde                           -      -    12     2   10M  1.5M
    sdf                           -      -    73    13   67M   11M
---------------------------  -----  -----  -----  -----  -----  -----

Qué significa: Un disco (sde) rinde dramáticamente peor mientras los demás son estables. Eso no es una historia simple de saturación de uplink; huele a disco defectuoso, path defectuoso o enlace negociando a menor velocidad.

Decisión: Investiga sde: comprueba velocidad negociada, contadores de errores, cableado y SMART. No ajustes ZFS hasta saber si un disco/path está fallando.

Task 2: Revisar estado del scrub y si está siendo limitado

cr0x@server:~$ zpool status -v tank
  pool: tank
 state: ONLINE
  scan: scrub in progress since Thu Dec 26 01:12:03 2025
        14.2T scanned at 1.05G/s, 9.8T issued at 720M/s, 200K repaired
        18.4% done, 0 days 10:22:11 to go
config:

        NAME                        STATE     READ WRITE CKSUM
        tank                        ONLINE       0     0     0
          raidz2-0                  ONLINE       0     0     0
          raidz2-1                  ONLINE       0     0     0

errors: No known data errors

Qué significa: La diferencia entre “scanned at” y “issued at” sugiere que el scrub está limitado por la emisión real de I/O a los dispositivos (o algún throttling), no solo por recorrer metadatos.

Decisión: Si el impacto en latencia es inaceptable, considera limitar temporalmente vía tunables del módulo ZFS (depende de la plataforma) o programar scrubs fuera de pico. Si la tasa “issued at” está muy por debajo de lo que los discos pueden hacer, sospecha uplink del expander o limitaciones de colas.

Task 3: Ver tiempos de espera y utilización por disco

cr0x@server:~$ iostat -x -d 5 2
Linux 6.6.0 (server)   12/26/2025  _x86_64_  (32 CPU)

Device            r/s     w/s   rMB/s   wMB/s  r_await  w_await  aqu-sz  %util
sda              78.2    14.9    70.5    12.1    9.2     12.3     1.2   88.0
sdb              77.9    14.7    70.3    12.0    9.4     12.1     1.2   87.5
sdc              76.8    15.1    69.5    12.2    9.6     12.0     1.3   89.1
sdd              74.0    13.4    68.1    11.0    9.1     11.8     1.1   86.2
sde              11.7     2.0    10.2     1.6   55.0     61.2     3.8   42.0
sdf              73.2    13.1    67.4    10.8    9.0     11.6     1.1   85.9

Qué significa: sde tiene await alto y mayor cola promedio pero bajo throughput y baja utilización. Eso es clásico “esperando algo que no es el plato”: reintentos, resets de enlace, problemas de path o rarezas del expander.

Decisión: Revisa los logs del kernel por errores de enlace y consulta la tasa SAS negociada para ese target. No aumentes las profundidades de cola para “arreglar” esto; empeorará la latencia de cola.

Task 4: Encontrar hosts SAS y el/los expander(s) visibles para Linux

cr0x@server:~$ lsscsi -g
[0:0:0:0]    disk    ATA      ST12000NM000J  SN02  /dev/sda  /dev/sg0
[0:0:1:0]    disk    ATA      ST12000NM000J  SN02  /dev/sdb  /dev/sg1
[0:0:2:0]    disk    ATA      ST12000NM000J  SN02  /dev/sdc  /dev/sg2
[0:0:3:0]    disk    ATA      ST12000NM000J  SN02  /dev/sdd  /dev/sg3
[0:0:4:0]    disk    ATA      ST12000NM000J  SN02  /dev/sde  /dev/sg4
[0:0:5:0]    disk    ATA      ST12000NM000J  SN02  /dev/sdf  /dev/sg5
[1:0:0:0]    enclosu HGST     H4060-J        4R06  -         /dev/sg10

Qué significa: Tienes al menos dos hosts SCSI ([0:...] y [1:...]), y un dispositivo de enclosure. Esa entrada de enclosure suele indicar SES (enclosure services), común en estantes con expanders.

Decisión: Mapea discos a la topología de expander/phy usando herramientas HBA (LSI/Broadcom) o atributos de sysfs. Quieres saber: ¿están los “discos lentos” agrupados detrás de un puerto de expander?

Task 5: Revisar logs del kernel por resets de enlace SAS, timeouts y errores de transporte

cr0x@server:~$ dmesg -T | egrep -i 'sas|mpt3sas|scsi|reset|timeout|link'
[Thu Dec 26 02:01:14 2025] mpt3sas_cm0: log_info(0x31120400): originator(PL), code(0x12), sub_code(0x0400)
[Thu Dec 26 02:01:15 2025] sd 0:0:4:0: [sde] tag#1826 FAILED Result: hostbyte=DID_SOFT_ERROR driverbyte=DRIVER_OK
[Thu Dec 26 02:01:15 2025] sd 0:0:4:0: [sde] tag#1826 Sense Key : Aborted Command [current]
[Thu Dec 26 02:01:15 2025] mpt3sas_cm0: sas_device(0x00000008), phy(6) link reset
[Thu Dec 26 02:01:17 2025] sd 0:0:4:0: [sde] Synchronizing SCSI cache

Qué significa: Errores suaves y resets de enlace en una phy particular indican fuertemente un problema de capa física (cable, conector, slot del backplane, phy del expander), o negociación marginal a alta velocidad.

Decisión: Antes de tocar tunables de ZFS, arregla la fiabilidad del transporte: vuelve a conectar/reemplaza el cable, mueve el disco a otra bahía, comprueba compatibilidad de firmware expander/HBA. Afinar el rendimiento con un enlace inestable es pulir una lente agrietada.

Task 6: Verificar velocidad/anchura PCIe para la HBA

cr0x@server:~$ lspci -nn | egrep -i 'sas|scsi'
3b:00.0 Serial Attached SCSI controller [0107]: Broadcom / LSI SAS3008 PCI-Express Fusion-MPT SAS-3 [1000:0097] (rev 02)

cr0x@server:~$ sudo lspci -s 3b:00.0 -vv | egrep -i 'LnkCap|LnkSta'
LnkCap: Port #0, Speed 8GT/s, Width x8, ASPM not supported
LnkSta: Speed 8GT/s, Width x4

Qué significa: La tarjeta puede hacer PCIe Gen3 x8, pero actualmente funciona a x4. Esa es una limitación engañosa de rendimiento y puede producir saturación “misteriosa” incluso con un uplink SAS correctamente ancho.

Decisión: Mueve la HBA a un slot que proporcione todos los lanes, ajusta la bifurcación BIOS, o quita el dispositivo conflictivo que está robando lanes. No discutas con la física.

Task 7: Inspeccionar profundidad de cola SCSI por dispositivo

cr0x@server:~$ for d in sda sdb sdc sdd sde sdf; do echo -n "$d "; cat /sys/block/$d/device/queue_depth; done
sda 32
sdb 32
sdc 32
sdd 32
sde 32
sdf 32

Qué significa: Profundidad de cola 32 es común para discos SATA detrás de SAS. No es inherentemente malo.

Decisión: Si estás saturando un uplink, aumentar la profundidad de cola puede empeorar la latencia porque incrementa el trabajo pendiente compitiendo por el mismo enlace estrecho. Si estás subutilizando SSDs rápidos y la latencia es estable, aumentarla puede ayudar. Decide en base a saturación/latencia observada, no sensaciones.

Task 8: Comprobar el scheduler de la capa de bloques (ayuda a diagnosticar amplificación de latencia)

cr0x@server:~$ cat /sys/block/sda/queue/scheduler
[mq-deadline] none kyber bfq

Qué significa: mq-deadline está activo. Eso suele ser sensato para HDDs en servidores.

Decisión: Si ves latencia patológica en la cola bajo cargas mixtas detrás de un expander, mq-deadline suele ser un mejor punto de partida que none para HDD. No hagas “none everywhere” por imitación.

Task 9: Comprobar velocidad negociada a nivel de dispositivo (SAS/SATA)

cr0x@server:~$ sudo smartctl -a /dev/sde | egrep -i 'SATA Version|SAS Version|Negotiated|Transport protocol'
SATA Version is:  SATA 3.3, 6.0 Gb/s (current: 3.0 Gb/s)

Qué significa: El disco soporta 6.0 Gb/s pero actualmente está a 3.0 Gb/s. Eso es una pista clara de un enlace marginal.

Decisión: Trata “negociado a menor velocidad” como un problema de hardware/cableado/backplane primero. Arregla eso y vuelve a probar. Si sigue ocurriendo, esa bahía o phy del expander es sospechosa.

Task 10: Mapear discos a ranuras del enclosure (para mover lo correcto)

cr0x@server:~$ sudo sg_map -x
/dev/sg0  0 0 0 0  /dev/sda
/dev/sg1  0 0 1 0  /dev/sdb
/dev/sg2  0 0 2 0  /dev/sdc
/dev/sg3  0 0 3 0  /dev/sdd
/dev/sg4  0 0 4 0  /dev/sde
/dev/sg5  0 0 5 0  /dev/sdf
/dev/sg10 1 0 0 0

Qué significa: Ahora puedes correlacionar direcciones SCSI con discos. Si tienes herramientas SES, a menudo puedes encender LEDs o consultar el mapeo de bahías.

Decisión: Si solo una phy/bahía es problemática, mueve el disco a otra bahía para ver si el problema sigue al disco (problema de disco) o se queda con la bahía (backplane/path del expander).

Task 11: Observar la latencia de ZFS bajo carga con visibilidad por vdev

cr0x@server:~$ zpool iostat -v -l tank 5 2
                              capacity     operations     bandwidth    total_wait     disk_wait
pool                        alloc   free   read  write   read  write   read  write   read  write
--------------------------  -----  -----  -----  -----  -----  -----  ----- -----  -----  -----
tank                        120T   80.0T  1.15K   240   1.05G  190M   12ms   8ms    9ms   6ms
  raidz2-0                   60T   40.0T    600   120   530M   95M    11ms   7ms    8ms   5ms
  raidz2-1                   60T   40.0T    550   120   520M   95M    13ms   9ms   10ms   7ms
--------------------------  -----  -----  -----  -----  -----  -----  ----- -----  -----  -----

Qué significa: total_wait incluye tiempo en colas de ZFS; disk_wait está más cerca del tiempo de servicio del dispositivo. Cuando total_wait se dispara mientras disk_wait se mantiene moderado, estás limitado por capas por encima de los discos (colas en ZFS, HBA o la tela).

Decisión: Si ambos waits son altos, los discos o el transporte hacia ellos son lentos. Si solo total está alto, revisa profundidad de cola, throttles de scrub/resilver y contención del host.

Task 12: Comprobar tunables actuales de ZFS que afectan scrub/resilver (Linux OpenZFS)

cr0x@server:~$ sudo sysctl -a 2>/dev/null | egrep 'zfs\.(vdev|scan)' | head -n 12
zfs.vdev.max_active=1000
zfs.vdev.scrub_max_active=64
zfs.vdev.resilver_max_active=64
zfs.vdev.async_read_max_active=64
zfs.vdev.async_write_max_active=64
zfs.vdev.sync_read_max_active=10
zfs.vdev.sync_write_max_active=10
zfs.scan.issue_strategy=0

Qué significa: Estos controlan cuántas I/O concurrentes ZFS lanzará a los vdevs para distintas clases de trabajo. Alta concurrencia puede saturar un uplink de expander e inflar la latencia para “trabajo real”. Baja concurrencia puede hacer que el mantenimiento dure una eternidad.

Decisión: Si ves saturación del expander durante scrub/resilver, reduce primero la concurrencia de scrub/resilver (y observa el impacto). Si estás subutilizando la tela y los discos, sube con precaución. Hazlo midiendo y no cambies diez perillas a la vez.

Task 13: Confirmar que multipath está realmente en efecto (si lo esperas)

cr0x@server:~$ multipath -ll
mpatha (3600508b1001c3d6d5f3c1b2a00000001) dm-2 LIO-ORG ,disk
size=10T features='1 queue_if_no_path' hwhandler='0' wp=rw
|-+- policy='service-time 0' prio=50 status=active
| `- 3:0:0:0 sda 8:0  active ready running
`-+- policy='service-time 0' prio=10 status=enabled
  `- 4:0:0:0 sda 8:0  active ready running

Qué significa: Tienes múltiples paths. Genial—siempre que sean uplinks independientes y no dos paths que convergen en el mismo uplink estrecho del expander.

Decisión: Valida el cableado físico y el ruteo del expander. Multipath no es garantía de rendimiento; es una herramienta de corrección/disponibilidad que también puede ayudar al throughput si la topología lo soporta.

Task 14: Medir throughput agregado durante scrub/resilver para detectar plateaus de uplink

cr0x@server:~$ zpool iostat tank 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
tank        120T   80.0T  1.10K   210   1.15G  160M
tank        120T   80.0T  1.12K   215   1.16G  162M
tank        120T   80.0T  1.11K   212   1.15G  161M
tank        120T   80.0T  1.11K   211   1.15G  160M
tank        120T   80.0T  1.10K   209   1.14G  159M

Qué significa: Un plateau estable (aquí ~1.15 GB/s de lecturas) no es automáticamente malo. Se vuelve sospechoso cuando tu uplink teórico está cerca de ese valor y tienes muchos spindles que colectivamente podrían excederlo durante un scrub.

Decisión: Compara el plateau con la capacidad del uplink (lanes × tasa negociada). Si estás cerca, estás limitado por el uplink. Remedios: añadir lanes (puertos más anchos), añadir otro uplink o repartir estantes entre HBAs.

Task 15: Comprobar versión de firmware/driver de la HBA (porque la compatibilidad es una característica de rendimiento)

cr0x@server:~$ modinfo mpt3sas | egrep -i 'version|firmware'
version:        46.100.00.00
firmware:       16.00.12.00

Qué significa: Al menos puedes identificar qué estás ejecutando. Mismas de firmware entre expander y HBA pueden manifestarse como resets, downshifts de enlace o mala equidad bajo carga.

Decisión: Si persigues resets intermitentes o negociaciones a menor velocidad, alinea el firmware de la HBA con un conjunto conocido bueno para tu estante/generación de expander. Haz cambios en ventanas de mantenimiento y valida con stress + scrub.

Palancas de ajuste que realmente importan

1) Arregla primero la capa física y de enlace

Si tienes resets de enlace, velocidades negociadas a la baja o errores CRC, para. Reemplaza cables, vuelve a asentar conectores, intercambia bahías y actualiza firmware. Ajustar por encima de esa capa es como poner a punto un auto de carreras con tres tuercas faltantes.

2) Prefiere puertos wide y ancho de banda real en uplinks

Si tu expander tiene múltiples puertos externos, quieres o bien:

  • Wide porting: múltiples lanes agregadas entre HBA y expander, o
  • Múltiples uplinks independientes divididos entre estantes/vdevs para que un uplink no se convierta en embudo.

En la práctica: cablea el estante tal como el proveedor espera para “alto ancho de banda”, no como si usaras la menor cantidad de cables posible. Los cables son baratos. El tiempo on-call no lo es.

3) Concurrencia de scrub/resilver: ajústala al tamaño de tu tela, no a tu ego

En OpenZFS (Linux), los knobs zfs.vdev.scrub_max_active y zfs.vdev.resilver_max_active son los primeros a tocar cuando las operaciones de mantenimiento matan la latencia.

Guía que funciona sorprendentemente bien detrás de expanders sobresuscritos:

  • Comienza con 16–32 scrub/resilver max_active por clase de vdev si tienes HDDs detrás de un expander.
  • Si la latencia es estable y no saturas uplinks, sube gradualmente.
  • Si ves picos de latencia en la cola, baja y vuelve a medir.

Estos valores no son sagrados. Lo sagrado es cambiar una cosa a la vez y colectar datos antes/después.

4) Profundidad de cola: no “arregles” límites de ancho de banda con más colas

La profundidad de cola es un multiplicador de contención. Si tu uplink ya está saturado, aumentar la profundidad de cola incrementa la cantidad de trabajo esperando su turno, lo que aumenta latencia, que hace infelices a las aplicaciones, que te hace infeliz.

¿Cuándo aumentarla?

  • SSDs detrás de una tela SAS propiamente ancha donde la HBA no es el limitador.
  • Cargas orientadas a throughput que toleran mayor latencia (backups, replicación masiva).

5) Divide pools/vdevs entre telas cuando puedas

El rendimiento de ZFS vive y muere por el paralelismo de vdev. Si tienes dos HBAs o dos estantes, no pongas todos los vdevs detrás de un uplink de expander porque es “ordenado”. Distribuye vdevs para que ningún enlace sea el cuello de botella compartido del pool. Eso es diseño, no ajuste.

6) Valida colocación PCIe y NUMA

Si tu HBA está en un slot que negocia a x4 en lugar de x8, o está conectada al “otro socket” con penalidad NUMA, puedes perder mucho tiempo culpando al expander. Confirma ancho/velocidad del enlace PCIe y mantén la localidad de interrupciones/CPU razonable en sistemas de IOPS altos.

7) Ten cuidado con políticas de “optimizar velocidad de rebuild”

Los resilvers rápidos son geniales hasta que dejan famélica la I/O de producción. En estantes sobresuscritos, concurrencia agresiva de resilver puede saturar uplinks y degradar todos los datasets, incluso aquellos en vdevs “saludables”. Tu objetivo es servicio predecible, no ganar una captura de pantalla de benchmark.

Tres mini-historias corporativas desde el campo

Incidente causado por una suposición errónea: “estante 12G significa 12G en todas partes”

La configuración parecía moderna: HBA SAS3, estante SAS3, “12G” impreso en el frente. El equipo migró un destino de backup ZFS a él, luego lo reutilizó para algo más interactivo porque “tiene muchos discos”. El primer scrub tras el go-live hizo explotar la latencia. Las bases de datos se quejaron. La gente miró las gráficas de ZFS como si fueran a confesar.

La suposición fue sutil: que un estante 12G garantiza 12G por disco y suficiente ancho de uplink para coincidir con el conteo de spindles. En realidad, el estante tenía un expander 12G, pero el cableado upstream era equivalente a un solo lane x1 debido a una mala elección de cable y un puerto que negoció a menor velocidad. El expander servía felizmente 24 discos a través de una pajita.

La señal reveladora fue un plateau sospechoso de throughput: lecturas del scrub ancladas en lo que un solo lane down-negociado podía hacer. El iostat por disco mostró mucha espera y baja utilización. Nada “estaba mal” con los discos. La tela estaba simplemente saturada.

La solución fue aburrida: recablear a un enlace x4 ancho, verificar tasas negociadas y correr el scrub otra vez. El throughput se duplicó, la latencia cayó y el equipo dejó de discutir si ZFS “necesita un controlador RAID”. También anotaron el mapeo de puertos en un runbook, lo cual no debería ser un acto heroico, pero aquí estamos.

Optimización que salió mal: poner cada perilla a 11

Otra compañía tenía un gran objeto store en ZFS con vdevs HDD detrás de expanders. Los scrubs eran lentos y alguien decidió que era inaceptable. Aumentaron agresivamente la concurrencia de ZFS vdev y subieron profundidades de cola de dispositivos porque “más paralelismo equivale a más velocidad”. El siguiente scrub fue más rápido—durante unos quince minutos.

Luego vino lo extraño: la latencia de la API subió, aparecieron timeouts y los nodos más ocupados mostraron gráficas de I/O oscilantes. No era una simple línea de saturación; parecía ráfagas de congestión y recuperación, como olas de tráfico en una autopista. El equipo on-call deshabilitó el scrub para estabilizar producción, lo que es exactamente lo que no quieres hacer por la integridad de datos.

El análisis post-incidente mostró un clásico colapso por colas. Los uplinks del expander estaban sobresuscritos. Al aumentar las órdenes pendientes, incrementaron la cola dentro de la tela y en los discos. El sistema pasó más tiempo manejando y tiempo fuera de comandos y menos tiempo haciendo E/S útil. La latencia cola se disparó; la app lo notó de inmediato.

La solución fue bajar la concurrencia de scrub/resilver para empatarla con el ancho de uplink, mantener profundidades de cola moderadas y programar scrubs con un presupuesto de impacto explícito. El resultado fue un scrub que tomó más tiempo que el intento “rápido”, pero que corrió sin interrumpir producción. Esa es la versión con la que puedes vivir.

Práctica aburrida pero correcta que salvó el día: documentación de topología y scrubs canario

Un equipo empresarial ejecutaba varios pools ZFS en múltiples estantes. No eran del tipo “avanzar rápido y romper almacenamiento”. Cada estante tenía un diagrama de topología: qué puerto HBA, qué puerto expander, qué cable y qué rangos de bahías pertenecían a qué vdevs. Era una hoja de cálculo. No era emocionante. También era precisa.

Durante una ventana de mantenimiento, actualizaron firmware de expander. Después del cambio, un scrub canario en un pool no crítico mostró una pequeña pero consistente caída de throughput y un aumento en disk_wait. No catastrófico, pero medible. Porque tenían baselines “conocidos” de scrubs canario previos, no tuvieron que discutir si esto era variación normal.

Revirtieron firmware en un estante y el rendimiento canario volvió. Eso acotó el problema a una interacción de firmware del expander con su modelo de HBA y mezcla de discos SATA. Probaron otra revisión de firmware y repitieron hasta que coincidió con la baseline.

No pasó nada dramático en producción. Ese es el punto. Prácticas aburridas—documentación de topología, baselines y scrubs canario—transforman “regresiones de rendimiento misteriosas” en cambios controlados con evidencia. No es glamuroso, pero tampoco lo es restaurar desde backups.

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

1) Scrubs/resilvers se estabilizan en un número sospechosamente redondo

Síntomas: Throughput se estanca alrededor de ~550 MB/s, ~1.1 GB/s, ~2.2 GB/s, etc., independientemente de cuántos spindles tengas.

Causa raíz: El uplink es un solo lane (o negoció a menor velocidad), o el wide porting no está realmente activo. A veces la HBA está limitada por PCIe.

Solución: Verifica velocidad SAS negociada y conteo de lanes; recablea para puerto x4 ancho; asegura que la HBA PCIe x8 esté negociada; reparte vdevs entre uplinks/HBAs.

2) Uno o pocos discos muestran await masivo mientras otros están bien

Síntomas: iostat -x muestra un disco con await alto, bajo throughput y %util no demasiado alto; ZFS muestra ese dispositivo hoja rezagado.

Causa raíz: Resets de enlace, velocidad negociada a la baja para ese disco, bahía/backplane marginal o problemas de phy del expander.

Solución: Revisa dmesg; confirma velocidad negociada vía SMART; mueve el disco a otra bahía; reemplaza cable/ruta de backplane; actualiza firmware del expander si es un problema conocido.

3) “Multipath habilitado” pero el rendimiento no cambia

Síntomas: Existen dos paths en el OS, pero el throughput parece como un solo enlace; el failover funciona pero no hay escalado.

Causa raíz: Ambos paths convergen en el mismo uplink del expander, o zoning/ruteo del expander fuerza un solo path activo.

Solución: Valida la topología física; asegura uplinks independientes; revisa zoning y cableado de puertos HBA; prueba desconectando un cable y observando cambios en paths.

4) Picos de latencia durante scrub que desaparecen cuando el scrub para

Síntomas: Las aplicaciones ven timeouts periódicos; métricas de almacenamiento muestran picos correlacionados con ventanas de scrub.

Causa raíz: Concurrencia de scrub demasiado alta para la tela; arbitraje/oversubscription del expander causa colas; a veces cargas síncronas compiten mal.

Solución: Reduce concurrencia de scrub/resilver; programa scrubs fuera de pico; considera special vdev para metadatos; asegura que los uplinks sean suficientemente anchos.

5) “Actualicé a HBA más rápida” pero nada mejoró

Síntomas: Nueva HBA SAS3 instalada; mismo plateau; mismos patrones de latencia.

Causa raíz: La HBA está limitada por carriles PCIe, o el uplink del estante sigue siendo estrecho, o los discos son SATA detrás de STP y dominan el comportamiento.

Solución: Confirma PCIe x8 a la generación esperada; confirma lanes del uplink del expander; considera discos SAS para uso de alta concurrencia; no olvides el cableado.

6) Timeouts de comandos aleatorios bajo carga intensa

Síntomas: Logs del kernel muestran comandos abortados/timeouts; ZFS marca dispositivos como lentos; resilvers reinician.

Causa raíz: Profundidad de cola excesiva + oversubscription + enlaces marginales; firmware del expander; a veces power/temperatura causa inestabilidad PHY.

Solución: Arregla errores de enlace, baja concurrencia/profundidad de cola, actualiza firmware, revisa alimentación/thermals del estante y revalida con pruebas de stress.

Listas de verificación / plan paso a paso

Paso a paso: de “el almacenamiento está lento” a una solución estable

  1. Captura el momento. Guarda zpool status, zpool iostat -v -l y iostat -x durante la ventana del incidente.
  2. Revisa anomalías de dispositivo único. Si un disco está retrasado, trátalo como problema de enlace/dispositivo primero.
  3. Revisa logs por errores de transporte. Cualquier patrón de reset/reintento te lleva a modo de remediación hardware.
  4. Verifica velocidades negociadas. Confirma que los discos no estén en 3G y que los uplinks no sean más estrechos de lo que crees.
  5. Verifica negociación PCIe. Confirma que la HBA esté a la anchura/velocidad esperada.
  6. Calcula capacidad aproximada de uplink. Lanes × tasa; compáralo con el plateau observado bajo scrub.
  7. Decide: añade ancho de banda o reduce demanda. Ancho de banda: recablear puertos wide, añadir uplinks, repartir estantes. Demanda: tunear concurrencia de scrub/resilver, programar mantenimiento.
  8. Cambia una cosa. Aplica un ajuste único (recablear, firmware, concurrencia) y vuelve a medir.
  9. Ejecuta un scrub canario. No todo en producción primero. Valida estabilidad e impacto en latencia.
  10. Documenta topología y baselines. Si omites esto, lo pagarás luego—con intereses.

Lista de verificación: “¿mi uplink del expander es realmente wide?”

  • Los puertos HBA usados son capaces de wide porting y están configurados en consecuencia.
  • Los cables soportan el conteo de lanes que crees (no todos los cables externos son equivalentes).
  • El enlace negoció a la tasa esperada (6G/12G) de extremo a extremo.
  • OS/driver/utilidad HBA reportan múltiples phys en el puerto wide.
  • No hay reglas de zoning/routing que fuerce todo el tráfico por un camino estrecho.

Lista de verificación: ajuste seguro de scrub/resilver en estantes sobresuscritos

  • Comienza conservador con zfs.vdev.scrub_max_active y zfs.vdev.resilver_max_active.
  • Mide impacto en latencia sobre cargas de producción durante una ventana controlada.
  • Aumenta en pasos pequeños; detente cuando la latencia cola empiece a subir.
  • Mantén un plan de rollback (y documenta los valores anteriores).

Preguntas frecuentes

1) ¿Los expanders SAS reducen el rendimiento por defecto?

No. Reducen rendimiento cuando sobresuscribes uplinks, tienes cableado/negociación pobre o alcanzas límites de equidad/colas. Con puertos wide adecuados y concurrencia sensata, los expanders pueden rendir muy bien.

2) ¿Por qué los scrubs dañan más que lecturas normales?

Los scrubs son sincronizados, sostenidos y de amplio fan-out. Mantienen muchos discos ocupados a la vez y exponen cuellos de botella compartidos (uplinks, PCIe, arbitraje) que la E/S normal de la aplicación podría no golpear continuamente.

3) ¿Es mala idea usar SATA detrás de un expander SAS?

Es común y puede estar bien para capas de capacidad. Pero el comportamiento STP más la alta concurrencia pueden producir latencias cola más feas que SAS nativo, especialmente durante scrub/resilver. Si necesitas latencia predecible bajo alta concurrencia, los discos SAS son más fáciles de razonar.

4) ¿Debería aumentar profundidad de cola para acelerar resilvers?

Sólo si has demostrado que no estás limitado por el uplink y la latencia es estable. Si ya estás saturando un uplink del expander, mayor profundidad suele provocar timeouts y latencias cola más altas, haciendo los resilvers menos estables.

5) ¿Cuál es el mejor indicador único de un cuello de botella en uplink del expander?

Un plateau estable de throughput durante scrub/resilver que coincide con la capacidad de un enlace estrecho, más colas/tiempos de espera elevados en muchos discos sin un disco claramente culpable.

6) ¿Cómo sé si el wide porting funciona realmente?

Usa herramientas de la HBA para inspeccionar phys/puertos y tasas negociadas. Indicadores a nivel OS pueden ser engañosos. También compara throughput bajo carga: si añadir un segundo cable no cambia nada, tu “wide port” puede no ser verdadero.

7) ¿Puedo “tunar ZFS” para superar un uplink SAS saturado?

Puedes sintonizar ZFS para ser menos disruptivo (menos concurrencia, mejor planificación), pero no puedes sintonizar para compensar ancho de banda faltante. Estás eligiendo entre “mantenimiento lento” y “todo lento”. Arregla la topología si necesitas ambos rápido y suave.

8) ¿Agregar L2ARC o más RAM ayuda con cuellos de botella de expander?

Puedes reducir E/S de lectura a disco, lo que disminuye demanda en la tela. No ayudará escrituras que deben alcanzar disco, ni solucionará límites de bandwidth en scrub/resilver. Trátalo como mitigación de carga, no reparación de transporte.

9) ¿Qué hay de dividir un pool entre varios expanders?

Repartir vdevs entre uplinks independientes puede ser una gran mejora. El truco es “independiente”: si ambos expanders acaban canalizándose por una sola HBA, solo añadiste complejidad, no ancho de banda.

Próximos pasos prácticos

Si tu pool ZFS está detrás de un expander SAS y luchas contra scrubs lentos, resilvers lentos o picos de latencia, haz esto a continuación:

  1. Prueba velocidades negociadas y anchura PCIe. Arregla cualquier downshift o limitación de lanes antes de ajustar otra cosa.
  2. Mide plateau vs matemáticas de uplink. Si tu throughput se topa cerca de un solo lane o número de puerto estrecho, has encontrado el cuello de botella.
  3. Dimensiona la concurrencia de scrub/resilver. Haz el mantenimiento predecible y no destructivo, aunque sea más lento de lo que quisieras.
  4. Recablea para ancho de banda. Puertos wide y múltiples uplinks ganan a cualquier sysctl ingenioso todos los días de la semana.
  5. Anota la topología. El tú-futuro lo necesitará, y el tú-futuro ya está cansado.

Una vez que la tela sea fiable y las matemáticas del enlace coincidan con tus expectativas, ZFS suele comportarse como un sistema adulto: aburrido, medible y lo suficientemente rápido para mantener a todos fuera de problemas. Ese es el sueño. Apunta a lo aburrido.

← Anterior
Ubuntu 24.04: Los jumbo frames rompen “solo parte” del tráfico — cómo probar y arreglar MTU de forma segura
Siguiente →
Eras del chipset: cuando la placa base decidía la mitad de tu rendimiento

Deja un comentario