Hay dos tipos de migraciones: las que planificas y las que tu almacenamiento te obliga a realizar a las 2 a.m. tras una actualización de firmware “menor”. Si gestionas pools ZFS en espejo, zpool split es una de las pocas herramientas que puede convertir una migración en una operación controlada y en su mayoría aburrida: literalmente separas un lado de tus mirrors y te vas con un segundo pool.
Esto no es un cuento de hadas de “clon instantáneo” para marketing. Dividir un pool es algo decisivo: cambias la postura de redundancia, creas una segunda identidad para el almacenamiento y haces promesas a tu yo futuro sobre importabilidad, puntos de montaje, claves de cifrado y el estado del último grupo de transacciones (TXG) cuando tiraste del seguro. Bien hecho, es una semilla de DR limpia o un arranque rápido para migración. Hecho de forma descuidada, es un billete hacia el país de “¿por qué producción montó la copia de DR y empezó a escribir en ella?”.
Qué es realmente zpool split (y qué no es)
zpool split toma un pool que contiene vdevs en espejo y crea un nuevo pool separando miembros del mirror. Conceptualmente: cada vdev mirror es un par (o más) de discos; el split te permite despegar un disco de cada mirror para formar un nuevo pool con la misma estructura de datasets y metadatos. No es copiar bloques; es reasignar la propiedad de discos existentes.
Por eso es rápido. También explica la primera regla del split: solo obtienes un “pool completo” si tienes suficientes mirrors como para donar un miembro de cada vdev en espejo. Si tu pool es un único vdev mirror de dos discos, un split aún puede crear un nuevo pool, pero efectivamente estás convirtiendo un disco en un pool de un solo disco. Eso puede ser aceptable para una etapa temporal de migración y puede ser inaceptable para cualquier cosa con la que planees dormir tranquilo.
Para qué sirve
- Etapa de migración: Split, envía discos (o muévelos a un nuevo chasis), importa y habrás trasladado la identidad del pool sin transferencia por red.
- Creación de semilla de DR: Divide para crear rápidamente un pool DR inicial y luego usa
zfs sendincremental para mantenerlo actualizado. - Duplicación rápida de entornos: Clona un árbol de datasets de producción para un trabajo puntual de análisis y luego destruye el pool split.
Lo que no es
- No es una copia de seguridad. Si tus datos están corruptos, con suerte tendrás dos copias de la corrupción.
- No es un mecanismo de snapshots. El pool dividido refleja el estado del pool en el límite TXG cuando se realizó el split, no es un snapshot de dataset que puedas navegar.
- No sustituye una estrategia de replicación. Es una herramienta en la caja de herramientas, no la caja entera.
Broma #1: Dividir un pool mirror es como fotocopiar la llave de tu casa serrándola a la mitad: tendrás dos llaves, pero la cerradura puede empezar a tener opiniones.
Datos & contexto histórico (el “porqué” del control)
ZFS tiene buena memoria, al igual que los ingenieros que dejaron flujos operativos montados sobre él. Aquí hay algunos hechos y puntos de contexto que explican por qué existe zpool split y cómo terminó en runbooks reales:
- ZFS se diseñó alrededor del almacenamiento agrupado, no dispositivos por sistema de ficheros. Por eso operaciones como split actúan sobre la topología del pool, no sobre “un filesystem” como hacían herramientas antiguas.
- Los mirrors siempre fueron el vdev “amigable operacionalmente”. En producción, los mirrors son populares porque se sanan rápido, degradan de forma predecible y toleran reemplazos de disco mezclados mejor que los vdevs paridad.
- El formato en disco es portátil entre sistemas que comparten feature flags. Importar un pool en otro host es normal, pero solo si las feature flags coinciden y el SO las soporta.
- Split es una transformación de topología, no un movimiento de datos. Por eso es instantáneo comparado con
zfs send, y también por eso cambia tu redundancia de inmediato. - Históricamente, las migraciones por “sneakernet” eran comunes. Antes de que 10/25/40/100GbE baratos fueran ubicuos (y confiables al 95% de utilización por 12 horas), mover discos era un camino legítimo de migración.
- Los checksums de ZFS hicieron mover discos más seguro que en sistemas de ficheros antiguos. Al importar en el extremo remoto tienes verificación end-to-end mediante scrub y checksums por bloque.
- Los GUIDs de pool y las rutas de dispositivos están intencionalmente abstraídos. ZFS rastrea GUIDs de vdev; los nombres de dispositivos del SO pueden cambiar y el pool aún así importará—si usaste rutas estables by-id en primer lugar.
- Las feature flags convirtieron “importa en cualquier lado” en “importa donde debe”. Habilitar características nuevas puede bloquear la importación en plataformas más antiguas; split no cambia eso, pero te obliga a enfrentarlo.
- Los entornos de arranque y root-on-ZFS hicieron el split más interesante. Dividir un pool que contiene el SO es posible, pero entonces entras en el terreno de compatibilidad del bootloader y los host IDs.
Cuándo usar split vs send/receive vs replicación
Si tienes un pool mirror y acceso físico a los discos, split es la forma más rápida de crear un segundo pool con el mismo árbol de datasets. Pero “rápido” no es lo mismo que “mejor”. Así es como decido.
Usa zpool split cuando
- Tienes vdevs en espejo y puedes ceder temporalmente un lado.
- Necesitas una semilla DR rápida y la ventana de replicación por red es inaceptable.
- Quieres migrar un pool grande a nuevo hardware sin saturar enlaces por días.
- Puedes tolerar una reducción temporal de redundancia en el pool origen (porque tras el split, el origen tendrá menos miembros del mirror).
Prefiere zfs send | zfs receive cuando
- Necesitas semántica punto-en-el-tiempo: snapshots, incrementales, opciones de rollback.
- No puedes reducir la redundancia en producción ni siquiera brevemente.
- Tus vdevs no son mirrors (RAIDZ no se divide así).
- Necesitas transformar propiedades como recordsize, cifrado o layout de datasets durante la migración y quieres control deliberado.
Prefiere replicación verdadera cuando
- Necesitas DR continuo auditado con objetivos RPO y RTO.
- Debes conservar puntos históricos (políticas de retención de snapshots).
- Tienes múltiples destinos downstream o necesitas replicar a través de límites de confianza.
Broma #2: La transferencia de datos más rápida sigue siendo una persona cargando discos—hasta que alguien los pone en una mochila con un imán, y ahora has inventado arte de performance.
Preflight: qué confirmar antes de dividir
Dividir un pool es sencillo. Dividir un pool y estar seguro de lo que ocurre después es donde los adultos se ganan el café.
Confirmar topología: solo mirrors
Necesitas vdevs mirror. Si tu pool incluye vdevs RAIDZ, zpool split no hará lo que quieres. Los pools de topología mixta son comunes en entornos “crecimos con el tiempo”—confirma lo que realmente tienes.
Confirmar feature flags y soporte del SO destino
Si divides un pool en un host con características ZFS más nuevas activadas y luego intentas importar en un appliance más antiguo, puede que la importación sea rechazada. Este es el modo de fallo #1 “funcionó en laboratorio” que he visto en migraciones empresariales.
Confirmar manejo de claves de cifrado
El cifrado nativo de ZFS (a nivel dataset) se mueve con los datos en disco. El pool split contendrá datasets cifrados; importar no es lo mismo que montar. Asegúrate de que el host receptor tiene acceso a las claves y sabes si se cargan automáticamente o manualmente.
Confirmar IDs de dispositivo estables
En Linux, /dev/sdX es una sugerencia, no un contrato. Usa /dev/disk/by-id para mayor cordura. En el destino, la enumeración de dispositivos será diferente; ZFS suele encontrarlos, pero tu tiempo de resolución explota si no puedes mapear “este número de serie” a “este miembro vdev”.
Confirmar estrategia de puntos de montaje
Tras el split e import, los datasets pueden montarse automáticamente. Eso está bien hasta que se montan en el host equivocado con rutas equivocadas, y de repente tienes dos servidores escribiendo en copias distintas creyéndose autoritarias. Planifica tus mountpoints y la postura de canmount antes de importar.
Tareas prácticas: comandos y cómo leer la salida
Las siguientes tareas están escritas como si estuvieras en un host Linux con OpenZFS. Ajusta nombres de servicios y rutas según tu plataforma. Cada tarea es algo que he ejecutado en serio o que desearía haber ejecutado antes de que el pager se presentara.
Tarea 1: Inventariar el pool y confirmar mirrors
cr0x@server:~$ sudo zpool status -v tank
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_AAA ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_BBB ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_CCC ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_DDD ONLINE 0 0 0
errors: No known data errors
Interpretación: Quieres que cada vdev de primer nivel sea mirror-N. Si ves raidz o discos individuales, el split será parcial o imposible. También revisa errores existentes; dividir un mirror degradado crea un nuevo pool que puede nacer enfermo.
Tarea 2: Comprobar la presión I/O actual antes de hacer algo disruptivo
cr0x@server:~$ iostat -x 2 3
Linux 6.8.0 (server) 12/25/2025 _x86_64_ (32 CPU)
avg-cpu: %user %nice %system %iowait %steal %idle
6.12 0.00 1.88 0.74 0.00 91.26
Device r/s w/s rkB/s wkB/s await svctm %util
nvme0n1 5.0 40.0 640.0 5120.0 2.10 0.15 0.70
Interpretación: Un split es rápido, pero el riesgo operativo viene de lo que haces alrededor (scrubs, exports, imports). Si el pool ya está saturado (%util cerca de 100% y await alto), programa una ventana más tranquila.
Tarea 3: Confirmar feature flags y postura de compatibilidad
cr0x@server:~$ sudo zpool get all tank | egrep 'feature@|compatibility|version'
tank compatibility - default
tank feature@async_destroy enabled local
tank feature@bookmarks enabled local
tank feature@encryption enabled local
tank feature@edonr enabled local
Interpretación: El pool split llevará estas features. Si el host destino no las soporta, la importación puede fallar. Trata “feature enabled” como un requisito estricto para la pila destino.
Tarea 4: Capturar la lista de datasets y propiedades críticas (mountpoints, canmount)
cr0x@server:~$ sudo zfs list -r -o name,used,avail,mountpoint,canmount,encryption,keylocation tank
NAME USED AVAIL MOUNTPOINT CANMOUNT ENCRYPTION KEYLOCATION
tank 220G 700G /tank on off -
tank/apps 80G 700G /tank/apps on aes-256-gcm file:///root/keys/apps.key
tank/home 40G 700G /tank/home on off -
tank/vm 100G 700G /tank/vm on aes-256-gcm prompt
Interpretación: Este es tu mapa de “qué se montará dónde”. En un host de DR, puede que quieras canmount=off hasta estar listo. También nota keylocation y si las claves son en fichero o por prompt.
Tarea 5: Crear un conjunto de “snapshots de seguridad” (opcional pero casi siempre sensato)
cr0x@server:~$ sudo zfs snapshot -r tank@pre-split-2025-12-25
cr0x@server:~$ sudo zfs list -t snapshot -r tank | tail -5
tank/apps@pre-split-2025-12-25 0B -
tank/home@pre-split-2025-12-25 0B -
tank/vm@pre-split-2025-12-25 0B -
Interpretación: Un split no requiere snapshots, pero los snapshots te dan rollback y opciones de send/receive si el plan de “mover discos” se tuerce. Es un seguro barato.
Tarea 6: Aplacar escritores riesgosos (bases de datos, imágenes de VM) y verificar
cr0x@server:~$ sudo systemctl stop postgresql
cr0x@server:~$ sudo systemctl stop libvirtd
cr0x@server:~$ sudo lsof +D /tank/vm | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Interpretación: Para una migración/semilla DR quieres al menos consistencia por crash; para bases de datos quieres consistencia a nivel de aplicación si puedes. Si lsof todavía muestra ficheros ocupados bajo datasets críticos, no estás quiesced.
Tarea 7: Ejecutar una comprobación rápida de salud y considerar programar un scrub
cr0x@server:~$ sudo zpool status tank
pool: tank
state: ONLINE
scan: scrub repaired 0B in 00:21:33 with 0 errors on Sun Dec 22 02:14:01 2025
config:
...
errors: No known data errors
Interpretación: Si el último scrub es antiguo o hay errores, soluciona eso primero. Dividir un pool no es el momento para descubrir que un miembro del mirror ha estado lanzando errores de checksum silenciosamente.
Tarea 8: Realizar el split para crear un nuevo nombre de pool
cr0x@server:~$ sudo zpool split tank tank_dr
cr0x@server:~$ sudo zpool status -v tank
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_AAA ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_CCC ONLINE 0 0 0
errors: No known data errors
cr0x@server:~$ sudo zpool status -v tank_dr
pool: tank_dr
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank_dr ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_BBB ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_DDD ONLINE 0 0 0
errors: No known data errors
Interpretación: En muchas configuraciones, el nuevo pool se crea a partir del “otro lado” de cada mirror. Nota que tank_dr aquí aparece ahora con vdevs de primer nivel de un solo disco (no mirrors) porque cada mirror contribuyó con un disco. Esta es la parte que la gente olvida: a menudo cambias redundancia por portabilidad. Si quieres que el pool split también sea mirror, necesitas discos adicionales para adjuntar después en el destino.
Tarea 9: Ajustar inmediatamente la postura de auto-mount en el pool split (recomendado)
cr0x@server:~$ sudo zfs set canmount=off tank_dr
cr0x@server:~$ sudo zfs set mountpoint=/tank_dr tank_dr
cr0x@server:~$ sudo zfs list -o name,mountpoint,canmount tank_dr
NAME MOUNTPOINT CANMOUNT
tank_dr /tank_dr off
Interpretación: Esto evita montajes accidentales en el host origen (o en un host destino que importe automáticamente). Puedes volver a habilitar montajes por dataset más tarde.
Tarea 10: Exportar el pool split para traslado físico
cr0x@server:~$ sudo zpool export tank_dr
cr0x@server:~$ sudo zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 1.81T 220G 1.60T - - 3% 11% 1.00x ONLINE -
Interpretación: Exporta limpiamente para que la importación en destino no parezca un “pool robado” de un host todavía vivo. Esto reduce fricción de importación y previene conflictos accidentales de multi-import.
Tarea 11: En el destino, localizar discos por ID estable e importar primero en solo lectura
cr0x@drhost:~$ sudo ls -l /dev/disk/by-id/ | egrep 'SAMSUNG_SSD_1TB_(BBB|DDD)'
lrwxrwxrwx 1 root root 9 Dec 25 09:02 ata-SAMSUNG_SSD_1TB_BBB -> ../../sdb
lrwxrwxrwx 1 root root 9 Dec 25 09:02 ata-SAMSUNG_SSD_1TB_DDD -> ../../sdc
cr0x@drhost:~$ sudo zpool import
pool: tank_dr
id: 15277416958755799222
state: ONLINE
action: The pool can be imported using its name or numeric identifier.
config:
tank_dr ONLINE
ata-SAMSUNG_SSD_1TB_BBB ONLINE
ata-SAMSUNG_SSD_1TB_DDD ONLINE
cr0x@drhost:~$ sudo zpool import -o readonly=on -o cachefile=none tank_dr
cr0x@drhost:~$ sudo zpool get readonly tank_dr
NAME PROPERTY VALUE SOURCE
tank_dr readonly on local
Interpretación: La importación en solo lectura es un aterrizaje fantástico. Te permite inspeccionar datasets, validar la estructura y confirmar que no trajiste los discos equivocados—sin cambiar el estado en disco.
Tarea 12: Cargar claves de cifrado y montar deliberadamente
cr0x@drhost:~$ sudo zfs load-key -r tank_dr/apps
Enter passphrase for 'tank_dr/apps':
cr0x@drhost:~$ sudo zfs mount -a
cannot mount 'tank_dr': legacy mountpoint, use mount(8)
cr0x@drhost:~$ sudo zfs get -o name,property,value tank_dr | egrep 'mountpoint|canmount'
tank_dr mountpoint /tank_dr
tank_dr canmount off
Interpretación: Si pusiste canmount=off, un montaje masivo no montará el dataset superior. Eso es intencional. Monta los datasets hijos específicos que necesites, después de cargar claves y de confirmar que los puntos de montaje no colisionarán con rutas locales.
Tarea 13: Convertir el pool split de nuevo a mirrors en el destino (adjuntar discos nuevos)
cr0x@drhost:~$ sudo zpool status tank_dr
pool: tank_dr
state: ONLINE
config:
NAME STATE READ WRITE CKSUM
tank_dr ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_BBB ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_DDD ONLINE 0 0 0
errors: No known data errors
cr0x@drhost:~$ sudo zpool attach tank_dr ata-SAMSUNG_SSD_1TB_BBB /dev/disk/by-id/ata-SAMSUNG_SSD_1TB_EEE
cr0x@drhost:~$ sudo zpool attach tank_dr ata-SAMSUNG_SSD_1TB_DDD /dev/disk/by-id/ata-SAMSUNG_SSD_1TB_FFF
cr0x@drhost:~$ sudo zpool status tank_dr
pool: tank_dr
state: ONLINE
scan: resilver in progress since Thu Dec 25 09:24:11 2025
52.1G scanned at 1.20G/s, 12.4G issued at 290M/s, 220G total
12.4G resilvered, 5.64% done, 00:12:31 to go
config:
NAME STATE READ WRITE CKSUM
tank_dr ONLINE 0 0 0
mirror-0 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_BBB ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_EEE ONLINE 0 0 0
mirror-1 ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_DDD ONLINE 0 0 0
ata-SAMSUNG_SSD_1TB_FFF ONLINE 0 0 0
Interpretación: Así restauras redundancia tras enviar un pool split con un solo disco por vdev. Las tasas de resilver dependen de ashift, recordsize, comportamiento del disco y carga. Planifica el tiempo en consecuencia.
Tarea 14: Hacer el pool escribible y establecer cachefile para persistencia
cr0x@drhost:~$ sudo zpool export tank_dr
cr0x@drhost:~$ sudo zpool import -o readonly=off tank_dr
cr0x@drhost:~$ sudo zpool set cachefile=/etc/zfs/zpool.cache tank_dr
cr0x@drhost:~$ sudo zpool get cachefile tank_dr
NAME PROPERTY VALUE SOURCE
tank_dr cachefile /etc/zfs/zpool.cache local
Interpretación: La importación en solo lectura fue para validación; ahora pasas a operaciones normales. Establecer cachefile asegura que el pool sea recordado tras reinicios (dependiente de la plataforma).
Tarea 15: Validar integridad de datos con un scrub después de la importación
cr0x@drhost:~$ sudo zpool scrub tank_dr
cr0x@drhost:~$ sudo zpool status tank_dr
pool: tank_dr
state: ONLINE
scan: scrub in progress since Thu Dec 25 10:02:18 2025
88.3G scanned at 1.10G/s, 88.3G issued at 1.10G/s, 220G total
0B repaired, 40.15% done, 00:01:52 to go
config:
...
errors: No known data errors
Interpretación: Un scrub tras la relocación es el movimiento de adulto. Detecta problemas de transporte, cables malos, HBAs marginales y “ese disco que solo falla cuando está frío”.
Listas de verificación / plan paso a paso
Checklist A: Semilla DR vía split (downtime mínimo, sorpresas mínimas)
- Confirmar que el pool usa solo mirrors:
zpool status. - Confirmar scrub reciente y limpio según tu apetito de riesgo.
- Registrar propiedades de datasets: mountpoints, canmount, estado de cifrado.
- Crear snapshots recursivos como respaldo y para incrementales futuros.
- Aplacar aplicaciones de alta actividad si necesitas consistencia a nivel de aplicación.
- Ejecutar
zpool splitpara creartank_dr. - Poner
canmount=offy/o ajustar mountpoints entank_drpara evitar montajes accidentales. - Exportar
tank_dr. - Mover discos, importar en solo lectura en destino, confirmar datasets y propiedades.
- Cargar claves de cifrado y montar selectivamente.
- Añadir discos nuevos y adjuntar para re-mirror, permitir que resilver termine.
- Scrub, luego pasar a replicación (sends incrementales) en adelante.
Checklist B: Migración a un nuevo host (manteniendo nombres de servicio y rutas sensatas)
- Decidir el momento de corte autoritativo: ¿cuándo el destino se vuelve escribible?
- Antes del split: poner
canmount=offen datasets críticos si quieres montarlos manualmente tras la importación. - Split y export del nuevo pool.
- En el host nuevo: importar con
-o altroot=/mntpara inspección si quieres cero riesgo de montar en rutas de producción. - Validar:
zfs list,zpool status, comprobar que se puedan cargar claves de cifrado. - Cuando estés listo: export/import normalmente, establecer mountpoints correctos, habilitar montajes.
- Iniciar servicios y validar salud a nivel aplicación.
Tres micro-historias del mundo corporativo (fallos y la que salvó el día)
1) Incidente causado por una suposición errónea: “El pool split es una copia de seguridad”
En una empresa mediana con un backend ZFS altamente espejado, un equipo creó una semilla DR separando un pool de producción y enviando los discos a un segundo sitio. Hicieron la mecánica correctamente: split, export, import, mount. Se sintieron bien. Demasiado bien.
Dos meses después, un desarrollador aplicó una migración de esquema que eliminó un conjunto de tablas de manera que la app no lo notó de inmediato. El daño fue silencioso: las escrituras siguieron y la monitorización miraba tasas de peticiones, no corrección de datos. Cuando descubrieron el problema, fueron a “la copia DR”. Tenía los mismos datos faltantes. Por supuesto: no estaban haciendo replicación basada en snapshots con retención; simplemente habían creado una segunda copia viva y periódicamente volvían a split como “actualización”.
La suposición errónea fue sutil: “Tenemos otro pool, por tanto tenemos recuperación.” Pero la recuperación requiere tiempo como dimensión—historial, puntos en el tiempo, retención—y el pool split no tenía nada de eso. Era un clon, no una copia de seguridad.
La corrección operativa fue sencilla pero dolorosa: implementaron snapshots disciplinados (con nombres y retención), y luego replicación incremental. Aún usaron split para sembrar rápidamente almacenamiento DR, pero solo como primer paso en una canalización real de DR.
La corrección cultural fue la mayor ganancia: dejaron de llamar al pool split “backup” en tickets y dashboards. Las palabras importan. Si lo nombras “backup”, alguien eventualmente apostará el negocio a ello.
2) Optimización que salió mal: “Hagamos el split en hora punta; es instantáneo”
Otra organización tenía un pool mirror que sustentaba un cluster de virtualización. Alguien propuso un plan inteligente: hacer el split durante horas de trabajo porque el split en sí es instantáneo, luego exportar y mover discos tras la ventana de cambios de la noche. Sonaba eficiente. La primera mitad era verdad. La segunda fue donde la realidad llegó con recibos.
Dividir el pool redujo inmediatamente el número de miembros de mirror en producción. El pool permaneció ONLINE, pero el perfil de rendimiento cambió. Algunas cargas que se beneficiaban de “paralelismo accidental” de lecturas desde los mirrors (y algo de calor de caché) se vieron compitiendo más agresivamente por IOPS. La latencia subió, no catastróficamente, pero lo suficiente como para disparar timeouts en un servicio interno muy parlanchín. El servicio empezó a fallar, los reintentos aumentaron y el amplificador de carga convirtió una pequeña subida de latencia en un incidente menor.
Aprendieron dos lecciones prácticas. Primero: en sistemas reales, las operaciones “instantáneas” pueden tener efectos de segundo orden. Quitar miembros del mirror puede cambiar la planificación y el comportamiento de colas de formas que tu benchmark feliz nunca ejercitó. Segundo: las migraciones no son solo operaciones de almacenamiento; son eventos de rendimiento. Si tu servicio está ajustado al límite, los cambios de topología se notan.
La remediación fue simple: hacer el split en una ventana tranquila, y si necesitas seguridad diurna, usar una semilla basada en snapshots para replicación. También añadieron una puerta de rendimiento pre-split: si la latencia al percentil 95 ya está elevada, no se hacen cambios de topología.
3) Práctica aburrida pero correcta que salvó el día: IDs de dispositivo estables y exports disciplinados
Una de las migraciones basadas en split más exitosas que he visto fue casi agresivamente poco interesante. El equipo tenía una regla: los pools se construyen usando rutas estables /dev/disk/by-id siempre, sin excepciones. También tenían la costumbre de exportar pools antes de cualquier movimiento físico—incluso si “solo vamos a reiniciar para nuevo firmware”.
Durante una migración de centro de datos, dividieron un pool mirror en un pool de migración, lo exportaron y movieron los discos a nuevos hosts. En el destino, la enumeración de dispositivos fue distinta, los HBAs eran diferentes y un par de discos acabaron en un backplane distinto al planeado. Nada de eso importó. zpool import encontró el pool por labels, y el naming by-id dejó claro qué números de serie faltaban cuando un cable no estaba bien conectado.
La práctica aburrida importó de nuevo cuando alguien intentó importar el pool en un host “staging” para inspeccionar datos mientras el host destino se montaba en rack. Como el pool había sido exportado limpiamente, no hubo confusión de “el pool estaba en uso antes”, ni import forzado, ni riesgo de que dos sistemas pensaran que lo poseían al mismo tiempo.
No pasó nada dramático, que es precisamente el punto. En producción, “no pasó nada dramático” es una característica que se gana con hábitos que parecen pedantes hasta que dejan de serlo.
Guía de diagnóstico rápido (qué comprobar primero, segundo, tercero)
Cuando una migración basada en split va lenta o extraña, no tienes tiempo para convertirte en filósofo. Este es el orden de triage rápido que uso para encontrar el cuello de botella y decidir si parar, continuar o retroceder.
Primero: ¿Es un problema de salud ZFS o del SO/hardware?
cr0x@server:~$ sudo zpool status -x
all pools are healthy
cr0x@server:~$ dmesg | tail -30
[...]
[ 8921.221] ata9.00: exception Emask 0x0 SAct 0x0 SErr 0x0 action 0x6 frozen
[ 8921.223] blk_update_request: I/O error, dev sdc, sector 12345678 op 0x0:(READ)
Decisión: Si dmesg muestra errores/timeout de I/O, para y estabiliza el hardware antes de culpar a ZFS. ZFS puede sobrevivir mucho, pero no puede negociar con un enlace SATA que está realizando danza interpretativa.
Segundo: ¿Un resilver/scrub domina el I/O?
cr0x@drhost:~$ sudo zpool status tank_dr
pool: tank_dr
state: ONLINE
scan: resilver in progress since Thu Dec 25 09:24:11 2025
180G scanned, 95G issued, 220G total
95G resilvered, 43.18% done, 00:08:41 to go
Decisión: Si hay resilver activo, el rendimiento suele ser “funcionando como diseñado”. O esperas o ajustas expectativas. Si el negocio necesita rendimiento ya, considera posponer algunas cargas hasta que termine el resilver.
Tercero: ¿Estás limitado por CPU, ARC o disco?
cr0x@drhost:~$ sudo arcstat 2 5
time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c
09:40:01 812 121 14 0 0 31 4 90 11 42G 64G
09:40:03 905 188 20 0 0 45 5 143 15 42G 64G
Decisión: Tasas de miss altas durante pruebas de migración pueden parecer “almacenamiento lento” cuando en realidad es caché fría. Calienta las cargas o prueba con condiciones de caché realistas. Si la CPU está alta y usas cifrado/compresión, verifica si estás limitado por CPU.
Cuarto: ¿Los montajes y propiedades están haciendo algo sorprendente?
cr0x@drhost:~$ sudo zfs get -r -o name,property,value canmount,mountpoint tank_dr | head -20
NAME PROPERTY VALUE
tank_dr canmount off
tank_dr mountpoint /tank_dr
tank_dr/apps canmount on
tank_dr/apps mountpoint /tank/apps
Decisión: Si un dataset hijo aún apunta a un mountpoint de producción (como /tank/apps), puedes montar sobre directorios existentes en el host DR. Así es como terminas “probando DR” sobrescribiendo algo que te gustaba.
Errores comunes (con síntomas y correcciones)
Error 1: Dividir sin darse cuenta de que pierdes redundancia
Síntoma: Tras el split, el nuevo pool muestra vdevs de primer nivel de un solo disco; el pool antiguo ahora tiene menos miembros; cambia el rendimiento; cambia la postura de riesgo.
Corrección: Planea usar zpool attach nuevos discos en el destino para restaurar mirrors, o acepta explícitamente el riesgo para un pool de migración de corta vida. Documenta esto en el registro de cambios; tu yo futuro lo olvidará.
Error 2: Importar y auto-montar en rutas de producción
Síntoma: Tras la importación, los datasets se montan bajo rutas que colisionan con directorios existentes; servicios empiezan a leer/escribir en la copia equivocada.
Corrección: Importa con -o altroot=/mnt para inspeccionar, o establece canmount=off antes del export. Solo habilita montajes cuando estés listo.
Error 3: Olvidar flujos de trabajo de claves de cifrado en destino
Síntoma: El pool importa, pero los datasets no montan; las aplicaciones ven directorios vacíos; zfs mount falla por errores relacionados con claves.
Corrección: Confirma zfs get encryption,keylocation,keystatus. Mueve material de claves de forma segura, prueba zfs load-key y no asumas que “importar” equivale a “usable”.
Error 4: Mismatch de feature flags entre origen y destino
Síntoma: zpool import se niega con “unsupported feature(s)” o similar.
Corrección: Actualiza la pila ZFS en destino para soportar las feature flags del pool. Si debes soportar sistemas antiguos, tenías que planear eso antes de habilitar features en el origen—ZFS no hace “downgrade”.
Error 5: Usar nombres de dispositivo inestables y perder rastreo de discos
Síntoma: Importación confusa post-movimiento; no puedes mapear /dev/sdX a discos reales; operaciones erróneas sobre discos se vuelven probables.
Corrección: Construye y opera usando /dev/disk/by-id. Al depurar, usa números de serie como verdad fundamental.
Error 6: Dividir un pool con errores existentes o un mirror degradado
Síntoma: El pool split importa pero los scrubs muestran errores de checksum; los resilvers tardan una eternidad; un disco empieza a lanzar errores de I/O.
Corrección: Estabiliza primero: reemplaza discos fallando, limpia errores mencionados en zpool status -v, ejecuta un scrub y luego divide. Si debes dividir bajo presión, importa en solo lectura en destino y haz un scrub inmediatamente para evaluar el daño.
Error 7: Asumir que split te da un “punto en el tiempo” coherente entre aplicaciones
Síntoma: Bases de datos se recuperan pero con transacciones recientes faltantes o inconsistentes; sistemas de archivos de VM muestran replays de journal.
Corrección: Quiesce las apps o usa snapshots coordinados con hooks de aplicación. Split captura el estado del pool, no la coherencia de la aplicación.
Preguntas frecuentes
1) ¿Hace zpool split una copia de los datos?
No. Reasigna miembros del mirror para formar un nuevo pool. Es rápido porque no mueve bloques; cambia la propiedad de discos existentes.
2) ¿Puedo dividir un pool RAIDZ?
No, no en el sentido de “clonar el pool”. zpool split es para mirrors. Los vdevs RAIDZ no tienen miembros independientes que puedan convertirse en vdevs coherentes por sí mismos.
3) ¿El pool split tendrá los mismos datasets y snapshots?
Sí: los datasets, propiedades y snapshots presentes al momento del split viajan porque los datos en disco son los mismos. Pero recuerda: no es una copia de seguridad. Si el origen tenía corrupción lógica, ahora tienes dos copias de ella.
4) ¿Qué pasa con los GUIDs y nombres de pool?
El nuevo pool obtiene su propia identidad (nuevo nombre de pool, GUID distinto). Esto es bueno: reduce la confusión de “mismo pool importado dos veces”, pero aun así debes tener cuidado con mountpoints y automatizaciones del host.
5) ¿Puedo importar el pool split en otro host mientras el original sigue en funcionamiento?
Sí, a menudo ese es el objetivo. Pero debes exportar el pool split limpiamente y tratarlo como un sistema separado: evita montar en rutas compartidas y asegura que ninguna aplicación escriba en ambas copias a menos que eso esté diseñado explícitamente (normalmente no lo está).
6) ¿Cómo mantengo el pool DR actualizado después de la semilla inicial split?
Generalmente con incrementales basados en snapshots: toma snapshots en el origen y usa zfs send/zfs receive hacia el pool DR. Split es genial para la primera copia; la replicación es cómo la mantienes actualizada.
7) ¿Y el cifrado nativo—el split “lo rompe”?
No. Los metadatos de cifrado forman parte de los datasets. Pero operativamente necesitas las claves en el destino para montar datasets cifrados. Planifica la distribución de claves y prueba la carga de claves antes de declarar victoria.
8) ¿Es seguro ejecutar zpool split mientras el pool está online y en uso?
Se puede hacer en caliente, pero “seguro” depende de tu carga y tolerancia al riesgo. El split en sí es rápido, pero quitar miembros del mirror cambia la redundancia y puede alterar la latencia bajo carga. Para bases de datos e imágenes VM prefiero aplacar o hacerlo en una ventana de baja actividad.
9) ¿Puedo “deshacer” un split?
No hay un comando mágico de deshacer. Puedes volver a adjuntar discos y re-mirror, o destruir un pool y volver a adjuntar sus discos, pero debes tratarlo como un cambio de topología con consecuencias. Si necesitas reversibilidad, considera replicación por snapshots en su lugar.
10) ¿Por qué importar primero en solo lectura?
Porque es la forma más segura de confirmar que trajiste los discos correctos y que el pool está sano sin avanzar el estado en disco. Es una comprobación barata antes de dejar que los servicios se le acerquen.
Conclusión
zpool split es una de esas características de ZFS que se siente como hacer trampa la primera vez que la usas: clon instantáneo de pool, sin copia por red, sin espera. En producción es potente precisamente porque es contundente. No estás creando una “copia” en el sentido de backup—estás creando un segundo pool sacrificando miembros del mirror, y asumes la responsabilidad de la redundancia, comportamiento de montajes, compatibilidad de features y claves.
Si recuerdas tres cosas, recuerda estas: verifica que tienes mirrors, importa primero en solo lectura y controla los montajes como si tu fin de semana dependiera de ello (porque depende). Split es una gran manera de iniciar un plan de migración o DR. El resto del plan—el aburrido ritmo de snapshots, la disciplina de replicación, los scrubs y auditorías—es lo que convierte esa victoria rápida en un sistema en el que puedes confiar.