Rutas de dispositivo faltantes en ZFS: usar by-id y WWN como un adulto

¿Te fue útil?

Tu pool ZFS está sano durante meses y luego un reinicio lo convierte en una escena del crimen: DEGRADED, un disco “UNAVAIL” y el nombre de dispositivo en zpool status
parece haber sido elegido por un generador de números aleatorios. Probablemente los datos están bien. Lo que falla es la nomenclatura.

Aquí está la brecha entre “funcionó en el laboratorio” y “sobrevive en producción”: rutas de dispositivo persistentes. Si tu pool referencia /dev/sdX,
ya decidiste que tu próxima interrupción será educativa.

Por qué /dev/sdX es una trampa (y por qué sigue ocurriendo)

/dev/sdX no es una identidad. Es una asignación de asiento. Linux distribuye esas letras en el orden de descubrimiento, y el orden de descubrimiento cambia:
firmware nuevo del HBA, entrenamiento de la ranura PCIe diferente, un disco lento que responde más tarde tras un evento de energía, tiempos en multipath, reinicios del chasis, lo que sea.
Tu disco no dejó de ser el mismo disco. El kernel simplemente los conoció en distinto orden.

ZFS está perfectamente contento usando la ruta que le diste. Si creaste el pool como mirror /dev/sda /dev/sdb,
ZFS registrará esas cadenas. Más tarde, si /dev/sda ahora apunta a otro disco, tienes dos problemas:
ZFS no puede encontrar el anterior, y podrías “arreglar” accidentalmente el disco equivocado. El primero causa un pool degradado. El segundo causa una actualización en tu currículum.

La cura es dejar de usar nombres efímeros y empezar a usar identificadores estables: /dev/disk/by-id y, específicamente, IDs basadas en WWN cuando estén disponibles.
Estos están diseñados para sobrevivir reinicios, reenumeraciones y la mayoría de los reordenamientos de hardware.

Broma #1: Usar /dev/sdX en producción es como etiquetar servidores como “el que está cerca de la ventana”. Funciona hasta que alguien mueve el escritorio.

Datos interesantes y un poco de historia

  • Dato 1: ZFS se originó en Sun Microsystems y se diseñó con la idea de que el almacenamiento miente; verifica los datos de extremo a extremo con checksums.
  • Dato 2: Los nombres de dispositivo de Linux como /dev/sda provienen del subsistema SCSI de discos, incluso para discos SATA y USB encaminados a través de capas de emulación SCSI.
  • Dato 3: WWN (World Wide Name) es un concepto de identificador globalmente único del ecosistema Fibre Channel/SAS, que luego se adoptó en SATA mediante estándares y adaptadores.
  • Dato 4: Los enlaces simbólicos de udev en /dev/disk/by-* existen precisamente porque la enumeración de dispositivos del kernel no es estable entre reinicios.
  • Dato 5: ZFS almacena etiquetas en el disco (cuatro etiquetas por miembro vdev en implementaciones típicas), por eso los pools suelen poder importarse incluso cuando cambian las rutas.
  • Dato 6: Los nombres “by-path” codifican la ruta de conexión física (bus PCI, puerto HBA, ranura del chasis) y son estables hasta que mueves cables o HBAs.
  • Dato 7: En los inicios del almacenamiento de consumo, los números de serie de los discos a veces se duplicaban o se rellenaban de forma extraña por chips puente; WWN suele comportarse mejor.
  • Dato 8: En entornos multipath suele haber nodos de dispositivo por cada camino y un dispositivo consolidado del mapper; elegir el incorrecto puede causar dispositivos “flapping” en ZFS.

Qué debes usar: by-id, WWN y cuándo by-path es aceptable

Elige una identidad estable: enlaces by-id basados en WWN

En la mayoría de sistemas Linux modernos encontrarás enlaces simbólicos bajo /dev/disk/by-id. Para SAS/SATA/NVMe, normalmente obtienes varias variantes:
vendor/model/serial y, a menudo, una basada en WWN. Las entradas basadas en WWN suelen verse como:
wwn-0x5000cca2... (SATA/SAS) o nvme-eui.000000... / nvme-uuid.... (NVMe).

Para ZFS, prefiera formas WWN/EUI/UUID porque están pensadas para ser globalmente únicas y es menos probable que se mutilen por un puente USB-SATA o un HBA peculiar.
Si solo tienes symlinks de vendor+serial, eso todavía puede estar bien, pero debes validar la unicidad en todo el chasis.

Cuándo by-path es útil

/dev/disk/by-path te dice dónde está enchufado el disco. Eso es oro operativo cuando estás haciendo “buscar el disco físico para extraer”
en un datacenter ruidoso a las 3 a.m. Pero no es una identidad si planeas mover el disco a otro puerto del controlador. Es una dirección.

Yo uso by-path para resolución de problemas y mapeo de ranuras, y by-id/WWN para la pertenencia al pool. Esa división mantiene a los humanos cuerdos y los pools estables.

Qué evitar

  • Evitar: /dev/sdX siempre. Incluso en servidores “simples”. Especialmente en servidores “simples”.
  • Evitar: nodos de disco sin particiones si estás en un entorno donde herramientas podrían escribir metadatos (algunos instaladores, algunas utilidades RAID).
  • Evitar: mezclar dispositivos mapper de multipath y dispositivos de ruta directa dentro del mismo pool.
  • Evitar: confiar en /dev/disk/by-label o en etiquetas de sistema de archivos para identificar miembros vdev de ZFS; no están pensados para eso.

Cómo ZFS recuerda los dispositivos (y qué significa realmente “ruta de dispositivo faltante”)

ZFS no confía simplemente en una cadena de ruta. Escribe la configuración del pool y etiquetas vdev directamente en los discos. Por eso puedes mover un pool a otro host,
importarlo, y ZFS a menudo puede determinar qué pertenece dónde. Pero la ruta sigue importando porque es lo que ZFS intenta primero y lo que los operadores ven en las alertas.

Una situación de “ruta de dispositivo faltante” suele caer en uno de estos recipientes:

  • Ruta cambiada, disco presente: El disco está bien, pero el SO lo presentó bajo otro nodo. Clásico reordenamiento /dev/sdX.
  • Disco ausente por completo: Problemas de HBA, backplane, energía, cableado, mala configuración de multipath o un disco realmente muerto.
  • Disco presente pero rechazado: Desajuste de tamaño de sector, tabla de particiones obsoleta, disco de reemplazo equivocado o el nodo de dispositivo incorrecto (por ejemplo, una sola ruta de un dispositivo multipath).
  • Permisos/tiempos de udev: Intentos de importación en inicio temprano, reglas udev faltantes en initramfs o capas de cifrado no desbloqueadas todavía.

Tu trabajo es decidir en cuál de esos recipientes estás rápidamente. Entonces puedes o bien relabelar rutas (inofensivo) o empezar a tratar al hardware como culpable (necesario).

Una cita que vale la pena pegar en una nota adhesiva (idea parafraseada): La esperanza no es una estrategia. En ingeniería y operaciones es literal.

Guion de diagnóstico rápido

Este es el orden que uso cuando suena el pager y alguien ya pregunta si necesitamos conmutar por error. La meta es encontrar el cuello de botella rápido:
¿es nomenclatura, conectividad o un dispositivo fallando?

Primero: confirma qué piensa ZFS que falta

  • Ejecuta zpool status -P para forzar rutas completas y capturar el nombre exacto “UNAVAIL”.
  • Comprueba si la entrada faltante es un disco entero, una partición o un dispositivo mapper.

Segundo: confirma si el SO puede ver el disco por IDs estables

  • Lista /dev/disk/by-id y /dev/disk/by-path.
  • Usa lsblk -o NAME,SIZE,MODEL,SERIAL,WWN,HCTL,TYPE,MOUNTPOINTS para unir identidad y topología.

Tercero: decide si esto es “deriva de ruta” o “pérdida de hardware”

  • Si el WWN existe y coincide con tu inventario/notas, probablemente es deriva de nombres. Usa zpool online o zpool replace con la ruta by-id correcta.
  • Si el WWN está ausente o el disco falta en lsblk, revisa los logs del kernel (dmesg) y el estado del controlador.

Cuarto: evita empeorarlo

  • No empieces a extraer discos basándote en /dev/sdX.
  • No ejecutes zpool clear como “arreglo”. Eso solo borra errores; no trae discos de vuelta a la existencia.

Quinto: elige la acción más pequeña y segura

  • Para deriva pura de rutas: actualiza ZFS a la ruta estable mediante replace (incluso reemplazando un dispositivo por sí mismo, usando el nombre by-id estable).
  • Para fallo real de dispositivo: reemplaza con un disco nuevo y realiza resilver. Si hay errores de checksum en otros sitios, trata el pool como contaminado y haz un scrub.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas son cosas reales que ejecutas en la consola. Cada una incluye qué te dice la salida y qué decisión debería desencadenar.
Úsalas como bloques de construcción; no las conviertas en scripts por imitación sin entender el entorno (multipath y cifrado cambian las reglas).

Tarea 1: Comprobar salud del pool con rutas completas

cr0x@server:~$ sudo zpool status -P
  pool: tank
 state: DEGRADED
status: One or more devices could not be opened.  Sufficient replicas exist for
        the pool to continue functioning in a degraded state.
config:

        NAME                                      STATE     READ WRITE CKSUM
        tank                                      DEGRADED     0     0     0
          mirror-0                                DEGRADED     0     0     0
            /dev/sda2                             UNAVAIL      0     0     0  cannot open
            /dev/disk/by-id/wwn-0x5000c500a1b2c3d4-part2  ONLINE       0     0     0

errors: No known data errors

Qué significa: ZFS no encuentra /dev/sda2. El otro lado del mirror está presente. Huele fuertemente a deriva de rutas.
Decisión: No reemplaces hardware todavía. Primero encuentra qué disco solía ser /dev/sda y vuelve a enlazar ZFS a una ruta by-id.

Tarea 2: Confirmar que el disco existe bajo by-id

cr0x@server:~$ ls -l /dev/disk/by-id/ | sed -n '1,12p'
total 0
lrwxrwxrwx 1 root root  9 Dec 26 02:10 ata-SAMSUNG_MZ7KM960HAHP-00005_S3Z1NX0K123456 -> ../../sdb
lrwxrwxrwx 1 root root 10 Dec 26 02:10 ata-SAMSUNG_MZ7KM960HAHP-00005_S3Z1NX0K123456-part2 -> ../../sdb2
lrwxrwxrwx 1 root root  9 Dec 26 02:10 wwn-0x5002538d4098abcd -> ../../sdb
lrwxrwxrwx 1 root root 10 Dec 26 02:10 wwn-0x5002538d4098abcd-part2 -> ../../sdb2
lrwxrwxrwx 1 root root  9 Dec 26 02:10 wwn-0x5000c500a1b2c3d4 -> ../../sdc
lrwxrwxrwx 1 root root 10 Dec 26 02:10 wwn-0x5000c500a1b2c3d4-part2 -> ../../sdc2

Qué significa: Tienes identificadores estables. El /dev/sda2 faltante probablemente se convirtió en /dev/sdb2 o /dev/sdc2.
Decisión: Identifica qué WWN pertenece al miembro vdev faltante (vía etiquetas ZFS o registros previos) y vuelve a adjuntar usando esa ruta by-id.

Tarea 3: Unir nodos de dispositivo a WWN/serie/topología en una vista

cr0x@server:~$ lsblk -o NAME,SIZE,MODEL,SERIAL,WWN,HCTL,TYPE,MOUNTPOINTS
NAME   SIZE MODEL              SERIAL          WWN                HCTL       TYPE MOUNTPOINTS
sdb  893.8G SAMSUNG MZ7KM960   S3Z1NX0K123456  0x5002538d4098abcd 1:0:0:0    disk
├─sdb1   1G                                      0x5002538d4098abcd 1:0:0:0  part
└─sdb2 892G                                      0x5002538d4098abcd 1:0:0:0  part
sdc  893.8G SAMSUNG MZ7KM960   S3Z1NX0K654321  0x5000c500a1b2c3d4  2:0:0:0    disk
├─sdc1   1G                                      0x5000c500a1b2c3d4 2:0:0:0  part
└─sdc2 892G                                      0x5000c500a1b2c3d4 2:0:0:0  part

Qué significa: Ahora puedes hablar en identidades (WWN/serie) y puntos finales físicos (HCTL).
Decisión: Si tienes un runbook o notas de activos que mapean WWN a ranura, aquí dejas de adivinar.

Tarea 4: Buscar errores a nivel kernel rápidamente

cr0x@server:~$ dmesg -T | egrep -i 'sd[a-z]|nvme|ata|sas|scsi|reset|I/O error|timed out' | tail -n 20
[Thu Dec 26 02:09:51 2025] sd 2:0:0:0: [sdc] tag#13 FAILED Result: hostbyte=DID_OK driverbyte=DRIVER_OK cmd_age=0s
[Thu Dec 26 02:09:51 2025] sd 2:0:0:0: [sdc] tag#13 Sense Key : Not Ready [current]
[Thu Dec 26 02:09:51 2025] sd 2:0:0:0: [sdc] tag#13 Add. Sense: Logical unit not ready, cause not reportable
[Thu Dec 26 02:09:52 2025] sd 2:0:0:0: [sdc] tag#21 timing out command, waited 180s
[Thu Dec 26 02:10:04 2025] scsi 2:0:0:0: rejecting I/O to offline device

Qué significa: Esto no es “solo nombres”. La ruta del disco/controlador está enferma: timeouts y “offline device”.
Decisión: Trátalo como hardware/conectividad. Revisa cableado/backplane/HBA y planifica un reemplazo. No lo pongas en línea esperando que mejore.

Tarea 5: Consultar eventos de ZFS para ver cambios recientes en dispositivos

cr0x@server:~$ sudo zpool events -v | tail -n 25
TIME                           CLASS
Dec 26 02:10:06.912726000      resource.fs.zfs.statechange
  pool = tank
  vdev_guid = 11801824156334312345
  vdev_path = /dev/sda2
  vdev_state = UNAVAIL
  vdev_ashift = 12
Dec 26 02:10:07.102938000      resource.fs.zfs.statechange
  pool = tank
  vdev_guid = 9938450195345123456
  vdev_path = /dev/disk/by-id/wwn-0x5000c500a1b2c3d4-part2
  vdev_state = ONLINE
  vdev_ashift = 12

Qué significa: ZFS cree que /dev/sda2 fue una ruta vdev real. También aprendes ashift (importante al reemplazar).
Decisión: Si planeas un replace, coincide con ashift. Usa estos eventos para la línea de tiempo del incidente; suelen ser más claros que el ruido de syslog.

Tarea 6: Localizar el vdev faltante por GUID en las etiquetas del disco

cr0x@server:~$ sudo zdb -l /dev/disk/by-id/wwn-0x5002538d4098abcd | sed -n '1,40p'
------------------------------------
LABEL 0
------------------------------------
    version: 5000
    name: 'tank'
    state: 0
    txg: 1923481
    pool_guid: 8012456789012345678
    vdev_tree:
        type: 'disk'
        id: 0
        guid: 11801824156334312345
        path: '/dev/sda2'
        phys_path: 'pci-0000:3b:00.0-sas-0x5000c500d00dbeef-lun-0'

Qué significa: Has encontrado el disco que ZFS piensa que es /dev/sda2. La etiqueta incluso registra la ruta antigua.
Decisión: Este disco es tu miembro faltante. Ahora puedes volver a adjuntarlo bajo una ruta estable sin adivinar cuál sdX es hoy.

Tarea 7: Reemplazar un dispositivo por sí mismo para actualizar la ruta a by-id

cr0x@server:~$ sudo zpool replace tank /dev/sda2 /dev/disk/by-id/wwn-0x5002538d4098abcd-part2
invalid vdev specification
use '-f' to override the following errors:
/dev/disk/by-id/wwn-0x5002538d4098abcd-part2 is part of active pool 'tank'

Qué significa: ZFS te está protegiendo de hacer algo ambiguo. Estás “reemplazando” con un dispositivo ya en el pool.
Decisión: Usa -f intencionalmente al hacer el truco de “reemplazar-por-sí-mismo” para reescribir la ruta almacenada al symlink estable.

cr0x@server:~$ sudo zpool replace -f tank /dev/sda2 /dev/disk/by-id/wwn-0x5002538d4098abcd-part2

Qué significa: No noticias es buena noticia. ZFS aceptó la nueva asignación de ruta.
Decisión: Vuelve a ejecutar zpool status -P y confirma que el pool ahora referencia entradas by-id en todas partes.

Tarea 8: Poner un dispositivo en línea tras una pérdida transitoria

cr0x@server:~$ sudo zpool online tank /dev/disk/by-id/wwn-0x5000c500a1b2c3d4-part2
bringing device online

Qué significa: ZFS intentará reanudar I/O. Si la ruta subyacente sigue fallando, se volverá a caer.
Decisión: Si el disco se desconecta repetidamente, deja de tratarlo como transitorio. Escala a hardware y planifica reemplazo.

Tarea 9: Vigilar el progreso de resilver como si importara

cr0x@server:~$ sudo zpool status -P tank
  pool: tank
 state: DEGRADED
status: One or more devices is currently being resilvered.
config:

        NAME                                              STATE     READ WRITE CKSUM
        tank                                              DEGRADED     0     0     0
          mirror-0                                        DEGRADED     0     0     0
            /dev/disk/by-id/wwn-0x5002538d4098abcd-part2  ONLINE       0     0     0  (resilvering)
            /dev/disk/by-id/wwn-0x5000c500a1b2c3d4-part2  ONLINE       0     0     0

scan: resilver in progress since Thu Dec 26 02:14:03 2025
        128G / 892G scanned at 1.12G/s, 6.5G / 892G issued at 58.1M/s, 0% done, 04:14:23 to go

Qué significa: Issued es lo que realmente se está escribiendo. Si scanned es rápido pero issued es lento, estás limitado por escrituras, no por lecturas.
Decisión: Si el tiempo de resilver es enorme, considera aligerar la carga, comprobar discos SMR o investigar throttling del controlador.

Tarea 10: Confirmar que cada vdev ahora usa rutas estables

cr0x@server:~$ sudo zpool status -P | egrep '/dev/(sd|vd|xvd)'

Qué significa: No tener salida es la meta: significa que no estás referenciando nodos efímeros.
Decisión: Si aún ves /dev/sd*, programa un mantenimiento controlado para reescribirlos mediante replace-with-self.

Tarea 11: Identificar si por accidente estás usando una sola ruta en una configuración multipath

cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,WWN,PKNAME | egrep 'mpath|dm-|sd[a-z] '
sda  disk  1.8T 0x600508b1001c2d3e4f5a6b7c8d9e0001
dm-2 mpath 1.8T 0x600508b1001c2d3e4f5a6b7c8d9e0001
sdb  disk  1.8T 0x600508b1001c2d3e4f5a6b7c8d9e0001

Qué significa: El mismo WWN aparece en múltiples nodos sd* (rutas distintas), y también en dm-2 como dispositivo multipath consolidado.
Decisión: Para ZFS en multipath, generalmente quieres el dispositivo mapper consolidado (por ejemplo, /dev/mapper/mpath*) o una ruta DM consistente,
no una de las patas brutales /dev/sd*. Mezclar es cómo obtienes caos intermitente de “dispositivo eliminado”.

Tarea 12: Mostrar propiedades udev para un disco específico (¿por qué cambió by-id?)

cr0x@server:~$ udevadm info --query=property --name=/dev/sdb | egrep 'ID_SERIAL=|ID_WWN=|ID_MODEL=|ID_PATH='
ID_MODEL=SAMSUNG_MZ7KM960HAHP-00005
ID_SERIAL=SAMSUNG_MZ7KM960HAHP-00005_S3Z1NX0K123456
ID_WWN=0x5002538d4098abcd
ID_PATH=pci-0000:3b:00.0-sas-0x5000c500d00dbeef-lun-0

Qué significa: udev te está diciendo el WWN y la ruta física. Si ID_WWN falta, podrías estar detrás de un puente que no lo reporta.
Decisión: Si falta el WWN, considera usar la entrada by-id más estable disponible y verifica la unicidad en todos los discos.

Tarea 13: Verificar tablas de particiones y asegurar que usas la partición correcta

cr0x@server:~$ sudo sgdisk -p /dev/disk/by-id/wwn-0x5002538d4098abcd
Disk /dev/disk/by-id/wwn-0x5002538d4098abcd: 1875385008 sectors, 894.3 GiB
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): 7A2B2C0D-9D2A-4B4A-8C31-2E1DA1A0C9B8
Partition table holds up to 128 entries
Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048         2099199   1024.0 MiB  EF00  EFI System
   2         2099200      1875384319   893.3 GiB   BF01  ZFS

Qué significa: Puedes confirmar qué partición es la miembro ZFS (aquí, código de partición BF01).
Decisión: Si por accidente apuntas ZFS al disco entero cuando tu estándar es particiones (o viceversa), detente y corrige antes de reemplazar.

Tarea 14: Importar un pool cuando las rutas cambiaron (modo seguro primero)

cr0x@server:~$ sudo zpool import
   pool: tank
     id: 8012456789012345678
  state: DEGRADED
 action: The pool can be imported despite missing or damaged devices.
 config:

        tank                                      DEGRADED
          mirror-0                                DEGRADED
            11801824156334312345                  UNAVAIL  cannot open
            wwn-0x5000c500a1b2c3d4-part2           ONLINE

Qué significa: ZFS puede ver el pool leyendo etiquetas, incluso si falta un vdev. Observa que muestra un GUID en lugar de una ruta para el faltante.
Decisión: Importa en modo solo lectura si no estás seguro de si estás mirando los discos correctos, especialmente en entornos de almacenamiento compartido.

cr0x@server:~$ sudo zpool import -o readonly=on -d /dev/disk/by-id tank
cannot import 'tank': one or more devices is currently unavailable

Qué significa: Incluso con escaneo explícito por by-id, algo falta lo suficiente como para bloquear la importación (la política depende de la topología vdev).
Decisión: No fuerces la importación a menos que entiendas la redundancia. Ve a buscar el dispositivo faltante mediante cableado/logs del HBA o confirma que tienes réplicas suficientes.

Tres microhistorias corporativas desde las trincheras

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

Una compañía mediana ejecutaba una plataforma de VM con respaldo ZFS en un par de servidores de almacenamiento. Nada exótico: estantes SAS, vdevs en espejo, monitorización decente.
El pool se creó originalmente durante un “fin de semana de migración urgente”, que es como nace toda deuda técnica. Los vdev se añadieron usando /dev/sdX.

Meses después añadieron un HBA nuevo y movieron un cable de estante para ordenar el rack. El siguiente reinicio llegó con un pool degradado y un miembro vdev “faltante”.
El ingeniero on-call vio /dev/sdc ausente y supuso que era “el tercer disco en ese chasis”, porque a los humanos les encanta el pensamiento ordinal.
Extrajeron lo que creyeron que era la unidad correcta, la reemplazaron y ejecutaron zpool replace con el nuevo /dev/sdc.

El sistema aceptó el comando. Por supuesto que sí: /dev/sdc existía. Simplemente no era el disco que creían. El “faltante” seguía presente,
renombrado a /dev/sdf tras el cambio de controlador. Mientras tanto, habían retirado físicamente un lado del mirror perfectamente sano y lo reemplazaron por un disco en blanco.
Por un breve periodo, empezó el resilver mientras el disco original restante llevaba todo el vdev solo.

El siguiente giro fue predecible y cruel: durante el resilver, el disco original restante devolvió errores de lectura. Vejez, sectores latentes, lo que sea.
Ahora la única copia buena de algunos bloques había estado en el disco que se sacaron. El resultado no fue pérdida total del pool, pero sí imágenes de VM corrompidas y una semana de limpieza.
El postmortem fue contundente: el desencadenante no fue “fallo de disco”, fue “tratamos /dev/sdX como identidad.”

Reconstruyeron la práctica operativa alrededor del nombrado por WWN y añadieron una regla: nadie toca un sled hasta que el WWN en la consola coincida con el WWN en la etiqueta física.
Les ralentizó los reemplazos cinco minutos. Les salvó de sí mismos para siempre.

Microhistoria 2: La optimización que salió mal

Otro sitio tenía un ingeniero al que le gustaban los sistemas ordenados. Quería que los nombres de vdev de ZFS reflejaran los números de ranura física, así que estandarizó en /dev/disk/by-path.
Se veía precioso en zpool status: podías apuntar una linterna al rack y encontrar el disco rápido.

Entonces compras reemplazaron un modelo de HBA SAS por uno más nuevo porque el antiguo estaba “fuera de vida”. Mismo proveedor, mismo tipo de cable, mismos estantes. El equipo de hardware hizo la actualización.
De repente cada symlink by-path cambió porque las direcciones PCI y la enumeración del expansor SAS cambiaron. No había nada malo con los discos. Las “direcciones” cambiaron.

La importación de ZFS comenzó a fallar de forma intermitente en el arranque temprano porque el initramfs no tenía las reglas udev actualizadas y porque esos nombres by-path no se creaban todavía.
Ops intentó parchearlo añadiendo sleeps a los scripts de arranque. Eso no es ingeniería; es superstición.

Eventualmente migraron a by-id basado en WWN para la pertenencia al pool y mantuvieron by-path solo para herramientas de mapeo humano. La “optimización” había sido legibilidad dentro de ZFS,
pero convirtió la configuración del pool en rehén de la topología del bus. Genial para diagramas; terrible para confiabilidad.

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

Un equipo de una gran empresa operaba pools ZFS para artefactos de build e imágenes de contenedores. El entorno era intencionalmente aburrido: vdevs en espejo, hot spares,
y un estándar escrito: todos los pools usan nombres by-id basados en WWN, solo particiones, y cada reemplazo incluye un scrub tras el resilver.
A nadie le encantaba. Era proceso.

Un fin de semana un evento de energía rebotó un rack. Tras el reinicio, un servidor arrancó con un pool degradado y dos discos mostrando comportamiento extraño en los logs del kernel.
El on-call pudo identificar inmediatamente qué discos físicos estaban involucrados porque su runbook guardaba los WWN y el mapeo de ranuras del chasis.
No adivinaron. No “probaron algunos comandos”. Siguieron la checklist.

Un disco estaba realmente muerto. El otro estaba bien pero se reenumeró. Porque el pool usaba rutas WWN estables, ZFS no se confundió.
La única acción necesaria fue reemplazar el disco muerto y dejar que el resilver corriera. El sistema siguió sirviendo todo el tiempo con rendimiento predecible.

La victoria silenciosa fue que no pasó nada sorprendente. La gerencia nunca se enteró. Ese es el objetivo de la práctica aburrida: incidentes que no se convierten en reuniones.

Migrar un pool existente a rutas de dispositivo estables (sin drama)

Si creaste tu pool con /dev/sdX, puedes arreglarlo sin reconstruirlo. La técnica es simple: reemplaza cada miembro vdev
por sí mismo, pero referenciado mediante la ruta by-id estable. ZFS actualiza la ruta almacenada y tu futura salida de zpool status deja de mentir.

Reglas antes de tocar producción

  • Confirma unicidad: Asegúrate de que cada nombre by-id que planeas usar mapée exactamente a un disco.
  • Prefiere particiones: Si estandarizas en -part2 (o similar), sigue así. La consistencia importa para automatización y seguridad.
  • Un disco a la vez: Especialmente en RAIDZ donde un error es más difícil de deshacer, pero también en mirrors porque los humanos se confían.
  • Captura el estado: Guarda la salida de zpool status -P antes y después.

Secuencia práctica de migración

Empieza listando el pool con rutas completas. Luego, para cada miembro que sea una ruta cruda /dev/sd*, encuentra la ruta by-id correspondiente y ejecuta un replace forzado.
Ejemplo para un miembro de mirror registrado como /dev/sda2:

cr0x@server:~$ sudo zpool status -P tank
  pool: tank
 state: ONLINE
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          mirror-0  ONLINE       0     0     0
            /dev/sda2  ONLINE     0     0     0
            /dev/sdb2  ONLINE     0     0     0

Ahora mapea /dev/sda2 a un ID estable:

cr0x@server:~$ readlink -f /dev/disk/by-id/wwn-0x5002538d4098abcd-part2
/dev/sda2

Luego reemplaza-por-sí-mismo para reescribir la ruta almacenada:

cr0x@server:~$ sudo zpool replace -f tank /dev/sda2 /dev/disk/by-id/wwn-0x5002538d4098abcd-part2

Repite para cada miembro /dev/sd* restante. Cuando termines, zpool status -P debería mostrar solo rutas by-id.
Si aún ves un /dev/sdX suelto, no lo ignores. Así mueren los estándares: una excepción a la vez.

Broma #2: Las interrupciones de almacenamiento son como el trabajo dental: evitables con mantenimiento regular, pero los humanos insisten en aprender por las malas.

Errores comunes: síntomas → causa raíz → arreglo

1) El pool muestra UNAVAIL para /dev/sdX tras reinicio

Síntomas: zpool status muestra una ruta /dev/sdX faltante; los discos parecen “movidos.”

Causa raíz: Renumeración de dispositivos por el kernel; ZFS registró nombres inestables.

Arreglo: Identifica el disco correcto vía WWN/serie (lsblk, zdb -l) y reescribe las rutas usando zpool replace -f con by-id.

2) Reemplazar un disco “funciona”, pero empieza a resilver el disco equivocado

Síntomas: Comienza el resilver en un disco que no pretendías; otro disco queda faltante; pánico.

Causa raíz: Usaste /dev/sdX y reemplazaste el nodo de dispositivo equivocado, o confundiste disco físico con dispositivo lógico.

Arreglo: Para. Confirma WWNs y etiquetas ZFS. Usa zpool status -P, lsblk y zdb -l. Si es necesario, deja offline el dispositivo errado y reevalúa antes de continuar.

3) La importación del pool falla en el arranque temprano pero funciona manualmente después

Síntomas: El sistema arranca sin el pool; zpool import manual más tarde tiene éxito.

Causa raíz: Los symlinks udev no están presentes todavía en initramfs; carrera entre descubrimiento de dispositivos y servicio de importación; capas de cifrado no abiertas.

Arreglo: Asegura que initramfs incluya las reglas udev y módulos necesarios; ordena servicios para que los dispositivos de bloque existan antes de importar; para vdevs cifrados, asegura que zfs-load-key/cryptsetup se ejecuten antes de importar/montar.

4) Los dispositivos hacen flap ONLINE/OFFLINE bajo carga

Síntomas: Los logs del kernel muestran timeouts; ZFS marca vdev como offline; vuelve brevemente; se repite.

Causa raíz: Cable malo, backplane, problemas de firmware del HBA, o estar usando una sola ruta en un entorno multipath.

Arreglo: Revisa dmesg, valida la configuración de multipath, reemplaza el cable/backplane sospechoso, actualiza firmware si está validado. Prefiere dispositivos mapper multipath estables si hay multipath en juego.

5) Los nombres by-id cambian tras una actualización de firmware

Síntomas: El symlink by-id de un disco se ve diferente que antes (formato de serial, prefijo del proveedor).

Causa raíz: Firmware/chips puente pueden cambiar cómo se reportan las cadenas de inquiry; las reglas udev derivan IDs de estas.

Arreglo: Prefiere identificadores WWN/EUI; verifica con udevadm info. Si los identificadores cambiaron realmente, actualiza las rutas ZFS usando replace-with-self a la nueva forma estable.

6) Usaste by-path y luego moviste cables durante mantenimiento

Síntomas: El pool arranca degradado; todas las “direcciones” se ven distintas; los operadores insisten “los discos están en las mismas ranuras.”

Causa raíz: by-path codifica la topología de conexión; mover un cable o HBA la cambia.

Arreglo: Usa by-id/WWN para la pertenencia al pool. Mantén by-path para mapeo/flujo de trabajo con LED, no como identificador autoritativo en ZFS.

7) El disco de reemplazo se une pero rinde terriblemente durante el resilver

Síntomas: El resilver avanza lentamente; latencias elevadas; rendimiento “issued” bajo.

Causa raíz: Disco SMR en una carga que espera CMR; política de caché de escritura del controlador; tamaños de sector desajustados provocando read-modify-write; carga de producción intensa.

Arreglo: Verifica el tipo de modelo de disco, política de caché y tamaños de sector. Considera usar una clase de disco conocida para reemplazos y moderar las cargas durante el resilver.

8) ZFS ve el disco pero se niega a usarlo sin -f

Síntomas: zpool replace se queja de que el dispositivo forma parte de un pool activo o tiene etiquetas existentes.

Causa raíz: Estás reemplazando con el mismo dispositivo físico (reescritura de ruta), o el disco tiene etiquetas ZFS obsoletas de membresías anteriores.

Arreglo: Para reescrituras de ruta, usa deliberadamente zpool replace -f. Para etiquetas obsoletas en un reemplazo real, limpia etiquetas con zpool labelclear en el dispositivo correcto antes de continuar.

Listas de verificación / plan paso a paso

Lista A: Crear un pool de la manera adulta

  1. Identifica discos por WWN/EUI/UUID, no por /dev/sdX.
  2. Usa particiones de forma consistente (por ejemplo, -part2 para el miembro ZFS).
  3. Registra un mapeo de WWN → ranura del chasis/bahía en tu runbook.
  4. Crea el pool usando rutas /dev/disk/by-id/wwn-...-partN.
  5. Verifica inmediatamente con zpool status -P que ZFS almacenó rutas by-id.
  6. Haz un scrub después del burn-in y periódicamente; trata los scrubs como advertencia temprana, no como higiene opcional.

Lista B: Tras un reinicio, el pool está degradado con una ruta faltante

  1. Ejecuta zpool status -P y captura la salida.
  2. Revisa lsblk -o NAME,SIZE,MODEL,SERIAL,WWN,HCTL para la identidad del disco faltante.
  3. Busca en dmesg errores I/O/timeouts. Si aparecen, asume hardware hasta demostrar lo contrario.
  4. Usa zdb -l en discos by-id candidatos para matchear el GUID/path del vdev.
  5. Si es deriva de ruta: zpool replace -f hacia la ruta by-id y confirma el estado.
  6. Si es pérdida de hardware: agenda reemplazo; no intentes “clear” para evadir la física.

Lista C: Migración controlada de sdX a by-id en un pool existente

  1. Programa una ventana de mantenimiento si el pool es crítico; esto es seguro, pero la seguridad incluye tiempo para humanos.
  2. Ejecuta zpool status -P e identifica todas las entradas /dev/sd*.
  3. Para cada una, confirma que el symlink by-id objetivo resuelve a la misma partición (readlink -f).
  4. Ejecuta zpool replace -f pool oldpath new-by-id-path un dispositivo a la vez.
  5. Tras cada cambio, vuelve a ejecutar zpool status -P y confirma que la nueva ruta está almacenada.
  6. Cuando termines, busca referencias residuales a /dev/sd y arréglalas.
  7. Documenta la lista de WWN en tu runbook de ops y, si la tienes, en tu CMDB.

Lista D: Reemplazo de disco sin convertirlo en un thriller

  1. Identifica el disco fallido por WWN en la salida de ZFS, no por letra de dispositivo.
  2. Asocia WWN a ranura física usando el mapeo del chasis.
  3. Deja offline el miembro vdev (si aún está ONLINE pero sospechoso) antes de sacar el hardware.
  4. Inserta el reemplazo y confirma que su WWN y tamaño coinciden con lo esperado.
  5. Particiona de forma consistente (o replica la tabla de particiones desde un hermano sano).
  6. Ejecuta zpool replace usando rutas by-id, luego monitoriza el resilver hasta completarse.
  7. Haz un scrub tras el resilver y revisa cualquier error de checksum con seriedad.

Preguntas frecuentes

1) Si ZFS almacena etiquetas en disco, ¿por qué importan las rutas?

Porque las rutas son lo que ZFS intenta primero y sobre lo que operas. Las etiquetas ayudan a ZFS a encontrar pools, pero la cadena de ruta sigue siendo la realidad operativa:
aparece en alertas, scripts y decisiones humanas. Hazla estable.

2) ¿Debo usar /dev/disk/by-id o /dev/disk/by-uuid?

Para vdevs ZFS, usa /dev/disk/by-id (estilo WWN/EUI/UUID). by-uuid suele referirse a UUIDs de sistemas de archivos; ZFS no es “un sistema de archivos sobre un bloque” en ese sentido.

3) ¿Es suficientemente bueno vendor+serial en by-id?

A menudo sí, especialmente para discos SAS/SATA empresariales. Pero WWN/EUI suele ser mejor. Si estás detrás de puentes USB o controladores baratos,
vendor+serial puede ser poco fiable o duplicarse. Valida la unicidad antes de confiar en ello.

4) ¿Y el nombrado NVMe? /dev/nvme0n1 también cambia.

Correcto. La numeración de controladores NVMe puede desplazarse. Usa entradas by-id como nvme-eui.* o nvme-uuid.* para membresía ZFS.
Trata nvme0n1 como un apodo temporal, igual que sda.

5) ¿Puedo cambiar rutas de vdev sin resilver?

Reemplazar un dispositivo por sí mismo para actualizar la ruta típicamente no requiere copiar datos si es realmente el mismo dispositivo.
ZFS aún puede hacer algunas verificaciones. La clave es la corrección: confirma identidad primero (WWN + zdb -l).

6) ¿Debo usar discos completos o particiones para vdevs ZFS?

Elige un estándar y cúmplelo. Las particiones te dan una intención más clara y reducen sorpresas con herramientas que escriben metadatos.
Los vdev de disco entero pueden estar bien en entornos controlados. En la realidad corporativa mixta, las particiones suelen ser más seguras.

7) ¿Qué significa “cannot open” en zpool status?

Significa que ZFS intentó abrir la ruta que tiene registrada y falló. Eso puede deberse a que la ruta ya no existe (renombrada),
el dispositivo se fue, o permisos/disponibilidad incorrectos durante el arranque. Tu próximo paso es comprobaciones de visibilidad en el SO (lsblk, dmesg, /dev/disk/by-id).

8) ¿Es by-path alguna vez la elección correcta para ZFS?

Rara vez, y solo si tu modelo operativo trata la conexión física como la identidad estable (backplane fijo, sin movimientos de cable, controladores consistentes),
y aceptas que el mantenimiento de hardware puede reescribir “identidades.” La mayoría de equipos no operan así. Usa WWN para identidad; usa by-path para ubicación.

9) Mi symlink by-id apunta a un sdX distinto tras el reinicio. ¿Es malo?

Es normal y precisamente la razón de ser de by-id. El symlink sigue la identidad del disco aunque cambie la asignación de letras del kernel.
ZFS debería referenciar el symlink, no el sdX subyacente.

10) ¿Puedo importar un pool escaneando solo /dev/disk/by-id?

Sí, con zpool import -d /dev/disk/by-id. Esto puede reducir ambigüedad en hosts con muchos dispositivos transitorios.
No soluciona hardware faltante, pero ayuda a evitar importar el pool equivocado desde el conjunto incorrecto de discos.

Conclusión: próximos pasos que puedes hacer hoy

Si recuerdas una cosa: /dev/sdX no es la identidad de un disco. Es el estado de ánimo del kernel. ZFS recordará fielmente lo que le digas,
lo cual es reconfortante hasta que deja de serlo.

Pasos prácticos:

  1. Ejecuta zpool status -P en cada host y busca /dev/sd* (o /dev/nvme*) en las rutas vdev.
  2. Para cada entrada inestable, mapea a un symlink by-id basado en WWN y realiza un replace-with-self controlado usando zpool replace -f.
  3. Anota los mapeos WWN → ranura y guárdalos donde on-call los encuentre rápido.
  4. Actualiza tus estándares de construcción: los nuevos pools se crean solo con rutas by-id/WWN y particionado consistente.
  5. Cuando un pool se degrade, sigue el playbook: identificar, verificar y luego actuar. Sin adivinar. Sin “clear y rezar”.

Haz esto una vez, correctamente, y la próxima vez que ocurra un shuffle de letras de dispositivo apenas lo notarás. Eso es el mayor cumplido que puede ofrecer la producción.

← Anterior
El furor del metaverso: cómo ‘el futuro’ se convirtió en un meme de la noche a la mañana
Siguiente →
CPU de Docker al 100%: identifica el contenedor ruidoso y limita correctamente

Deja un comentario