Migración de volblocksize en ZFS: por qué normalmente debes recrear el ZVOL

¿Te fue útil?

Heredaste un pool. Las VM parecen “bien” hasta la noche de parches, la noche de backups o esa noche de trabajo de análisis. Alguien dice,
“Cambiemos volblocksize y tendremos mejores IOPS.” Asientes porque suena a una opción. Luego ejecutas el comando, lo acepta, y… nada mejora.
A veces empeora. Entonces aprendes la verdad dolorosa: cambiaste una propiedad, no la física de los bloques ya escritos.

Los ZVOL son engañosamente simples: un dispositivo de bloque con respaldo ZFS. Pero su comportamiento de tamaño de bloque no es como el recordsize
de un dataset tipo filesystem. Cuando “migras” volblocksize, estás mayormente cambiando cómo se disponen las escrituras futuras.
Los datos existentes siguen organizados como antes a menos que los reescribas. En producción, “reescribir” normalmente significa “recrear el ZVOL y mover los datos con intención”.

volblocksize no es una máquina del tiempo

Aquí está el titular: cambiar volblocksize en un ZVOL existente rara vez altera el rendimiento de forma significativa hasta
que los datos son reescritos. ZFS no vuelve atrás y “reempaqueta” un ZVOL solo porque se lo pidas. Puedes establecer la propiedad hoy,
pero los bloques ya en disco mantienen su tamaño original, segmentación y estructura de bloques indirectos.

Eso no es ZFS siendo terco. Es ZFS siendo consistente. ZFS es copy-on-write: escribe bloques nuevos en otro lugar, actualiza metadatos y luego cambia punteros.
No sobrescribe bloques antiguos en sitio. Si quieres que los datos existentes se reescriban usando un nuevo tamaño de bloque, necesitas un flujo de trabajo
que provoque la reescritura lógica completa del volumen: replicación a un nuevo ZVOL, restauración desde backup o una copia a nivel de bloque hacia un destino recién creado.

El resultado práctico: la mayoría de las “migraciones de volblocksize” son en realidad proyectos de “recrear y mover”. El resto es pensamiento mágico,
más una orden de cambio que dice “afinamiento de rendimiento” y un postmortem que dice “sin impacto medible”.

Qué controla realmente volblocksize (y qué no)

volblocksize: la unidad de asignación del ZVOL

Un ZVOL es un dataset ZFS de tipo volume. Exporta un dispositivo de bloque (p. ej., /dev/zvol/pool/vm-101-disk-0)
que los consumidores tratan como un disco. Para ZVOLs, volblocksize es el tamaño máximo de bloque que ZFS asignará para
los datos escritos en el ZVOL.

Si fijas volblocksize=16K, ZFS asignará bloques de hasta 16KiB para los datos del ZVOL. Si lo fijas a 8K,
hasta 8KiB, y así sucesivamente. “Hasta” importa: ZFS aún puede asignar bloques más pequeños cuando la escritura es menor o cuando la compresión
la reduce. Pero el tamaño configurado sesga fuertemente la asignación y el patrón de I/O resultante.

recordsize es para filesystems, no para ZVOLs

En un dataset tipo filesystem, recordsize controla el tamaño máximo de registro para datos de archivos. Se trata de bloques de archivo.
Interactúa con el tamaño de I/O de la aplicación, la compresión y los patrones de acceso aleatorio. En ZVOLs no hay registros de archivo;
hay un disco virtual. El filesystem invitado decide sus propios tamaños de bloque y disposiciones, y ZFS ve escrituras a LBAs.

Si te llevas una idea: el ajuste de recordsize suele ser tolerante porque los filesystems reescriben naturalmente archivos calientes con el tiempo.
Los ZVOLs que respaldan discos de VM pueden permanecer con una disposición antigua durante años porque muchas cargas no reescriben todo el disco virtual—especialmente bases de datos e imágenes de VM de larga vida.

De dónde viene el dolor: amplificación de escritura y desajuste de I/O

La forma más fácil de pensar en un mal volblocksize es el desajuste. Tu carga genera escrituras aleatorias de 4K, pero configuraste
volblocksize=128K. ZFS ahora tiende a asignar (y luego leer/modificar/escribir) trozos mucho más grandes. En cargas con muchas escrituras síncronas,
ese desajuste puede convertirse en picos de latencia, metadatos hinchados y un perfil de I/O que parece un elefante confundido sobre patines.

Otro desajuste es entre volblocksize y el ashift del pool (alineación con el tamaño físico del sector). Puedes “trabajar”
con desalineación, pero la factura llega en forma de I/O extra, peor fragmentación y amplificación de escritura a nivel de dispositivo. El recibo
aparece como latencia.

Broma #1: Cambiar volblocksize en un ZVOL ocupado y esperar mejora instantánea es como pintar de nuevo una carretilla elevadora y llamarla una actualización turbo.

Por qué cambiarlo raramente arregla los datos existentes

Las propiedades de ZFS no siempre son retroactivas

Las propiedades de ZFS caen en categorías. Algunas afectan el comportamiento en tiempo de ejecución inmediatamente (como compression para escrituras futuras),
otras afectan decisiones de metadatos, y otras son principalmente política por defecto para nuevas asignaciones. volblocksize está en la
categoría de “nuevas asignaciones”. No provoca una reescritura de bloques existentes porque eso sería una operación masiva y arriesgada en segundo plano.

Copy-on-write significa “la reescritura sucede solo cuando la carga reescribe”

ZFS asigna bloques nuevos al modificarlos. No va a tocar bloques antiguos para “normalizarlos” a un nuevo tamaño preferido. Así que cuando cambias
volblocksize, solo los bloques escritos después de ese punto probablemente reflejarán el nuevo tamaño. Si tu disco de VM tiene una gran
imagen del SO mayormente estática y un pequeño archivo de base de datos muy cambiante, podrías ver que solo un subconjunto de bloques cambia,
mientras que la mayoría queda atrapada en la disposición antigua.

Incluso si el invitado reescribe, las snapshots pueden fijar bloques antiguos

Las snapshots son otra trampa. Si tienes snapshots frecuentes (backups de VM, puntos de replicación, snapshots “por si acaso” que nunca se borran),
los bloques antiguos permanecen referenciados y no pueden liberarse. El invitado puede reescribir datos, pero los bloques antiguos quedan fijados por snapshots,
dejando la fragmentación y el uso de espacio sin cambios. Tu nuevo diseño convive con el viejo. Enhorabuena, ahora tienes un museo.

La trampa de “aceptó la propiedad”

ZFS acepta gustosamente zfs set volblocksize=... en muchos sistemas cuando un ZVOL no está en uso, o a veces puede rechazarlo con “in use”
dependiendo de la plataforma e implementación de ZFS. La aceptación no significa que obtuviste la migración deseada. Significa que el dataset ahora tiene un valor
de propiedad que guiará futuras asignaciones. Eso es todo.

Por qué recrear suele ser la respuesta limpia

Recrear el ZVOL obliga a que todos los bloques se asignen de nuevo bajo la nueva política. Esa es la única forma determinista de garantizar que
todo el volumen adopte el nuevo comportamiento de volblocksize. Todo lo demás es probabilístico y lento, y se descarrila por snapshots,
patrones de aprovisionamiento fino y reescrituras parciales.

Hechos interesantes y contexto histórico

  • ZFS nació en Sun a mediados de los 2000, diseñado alrededor de la integridad de datos end-to-end, copy-on-write y almacenamiento en pool—ideas que luego se volvieron estándar.
  • Los ZVOL fueron un puente deliberado de “dispositivo de bloque”: permitían a ZFS servir cargas que demandan una abstracción de disco (VMs, objetivos iSCSI) sin forzar un filesystem ZFS dentro del invitado.
  • El énfasis original de ZFS fue la corrección sobre micro-optimizaciones; propiedades como el tamaño de bloque eran perillas de política, no mecanismos de reempaquetado en vivo.
  • Los discos Advanced Format (sectores de 4K) hicieron que los problemas de alineación fueran mainstream; ashift se volvió una decisión crítica en el diseño del pool.
  • El almacenamiento de VMs impulsó la popularidad de los ZVOL porque los hipervisores y herramientas SAN hablan dispositivos de bloque con fluidez, incluso cuando imágenes basadas en archivos podrían ser más simples.
  • La adopción temprana de ZFS-on-Linux aceleró patrones operativos como la replicación zfs send/receive, haciendo normal el “recrear y streamear datos”.
  • La compresión se volvió mainstream no solo por capacidad, sino por rendimiento: menos I/O puede vencer más CPU, especialmente en pools con SSD.
  • Las snapshots cambiaron la cultura operativa: los equipos empezaron a snapshotearlo todo porque era barato—hasta que dejó de serlo, especialmente con bloques fijados y cadenas de retención largas.
  • A medida que la latencia NVMe bajó, la sobrecarga del software y la amplificación de I/O se hicieron más visibles; un mal dimensionamiento de bloques puede desperdiciar la ventaja del hardware rápido.

Guía rápida de diagnóstico

Cuando alguien se queja “el ZVOL está lento”, no empieces cambiando volblocksize. Empieza por averiguar qué capa está mintiendo.
Aquí tienes una secuencia ajustada que encuentra el cuello de botella con rapidez.

1) Primero: ¿es latencia o rendimiento?

  • Si los usuarios se quejan de “VM lenta” y “time outs de DB”, asume latencia.
  • Si los backups o copias masivas son lentos, asume rendimiento—a menos que sean escrituras síncronas.

2) Segundo: ¿la carga está ligada a sync?

  • Revisa el comportamiento de sync y si tienes un SLOG sensato (o ninguno, y eso también puede estar bien).
  • Las escrituras síncronas amplifican cada mala decisión: tamaño de bloque, fragmentación y encolamiento de dispositivo.

3) Tercero: confirma el tamaño de I/O realmente visto por el pool

  • Observa los tamaños de I/O en la capa ZFS. Si ves escrituras de 128K pero la app dice 4K, algo se está coalesciendo—o alguien miente.

4) Cuarto: comprueba fragmentación y bloqueo por snapshots

  • Alta fragmentación más cadenas largas de snapshots puede matar I/O aleatorio incluso en SSD.
  • Si los bloques no pueden liberarse, “tunear” se convierte en placebo.

5) Quinto: solo entonces decide si volblocksize es la palanca

  • Si la carga es I/O aleatorio de 4K/8K (bases de datos, picos de arranque de VM), un volblocksize más pequeño suele ayudar.
  • Si son escrituras/lecturas secuenciales grandes (vídeo, backups dentro del invitado), bloques mayores pueden ayudar—siempre que el invitado emita I/O grande.

Tareas prácticas: comandos, salidas y decisiones

El objetivo de los comandos no es parecer ocupado. Es convertir “creo” en “sé” y luego tomar una decisión que puedas defender en una revisión.
A continuación hay tareas prácticas que uso al diagnosticar o planificar una migración de volblocksize de ZVOL.

Task 1: Identificar el ZVOL y verificar su volblocksize actual

cr0x@server:~$ zfs list -t volume -o name,volsize,volblocksize,compression,sync pool/vm-101-disk-0
NAME                 VOLSIZE  VOLBLOCKSIZE  COMPRESS  SYNC
pool/vm-101-disk-0   200G     128K          lz4       standard

Qué significa: Este ZVOL está configurado para asignar hasta 128K por bloque para futuras escrituras. También está comprimido con lz4.
Sync es standard (honra las solicitudes de la aplicación).

Decisión: Si la carga del invitado es mayormente I/O aleatorio de 4K/8K, 128K es sospechoso. No lo cambies todavía. Mide primero.

Task 2: Comprobar si la propiedad es heredada o está puesta explícitamente

cr0x@server:~$ zfs get -H -o property,value,source volblocksize pool/vm-101-disk-0
volblocksize	128K	local

Qué significa: Está puesto localmente. Alguien lo eligió.

Decisión: Trátalo como un intento de afinamiento intencional. Pregunta qué carga y por qué. Asume que la razón se perdió con el tiempo.

Task 3: Confirmar ashift del pool y layout de vdevs (chequeo de alineación)

cr0x@server:~$ zdb -C pool | sed -n '1,120p'
MOS Configuration:
        version: 5000
        name: 'pool'
        state: 0
        txg: 1234567
        pool_guid: 1234567890123456789
        hostid: 1122334455
        hostname: 'server'
        vdev_tree:
            type: 'root'
            id: 0
            guid: 9876543210987654321
            children[0]:
                type: 'mirror'
                id: 0
                guid: 1111111111111111111
                ashift: 12

Qué significa: ashift: 12 implica sectores de 4K (2^12). Buena base para SSD/HDD modernos.

Decisión: Si ashift fuera 9 (512B) en medios 4K, tendrías problemas más profundos que volblocksize. Planea una migración del pool, no un ajuste de ZVOL.

Task 4: Comprobar el estado “in use” del ZVOL y si un cambio en vivo está permitido

cr0x@server:~$ zfs set volblocksize=16K pool/vm-101-disk-0
cannot set property for 'pool/vm-101-disk-0': volume is busy

Qué significa: El kernel está usando el dispositivo de bloque (mapeado, exportado vía iSCSI, adjuntado a una VM, etc.).

Decisión: No lo fuerces. Planea una migración a un nuevo ZVOL con el tamaño de bloque deseado y luego el corte.

Task 5: Identificar qué consume el ZVOL (VM, iSCSI, multipath)

cr0x@server:~$ ls -l /dev/zvol/pool/vm-101-disk-0
lrwxrwxrwx 1 root root 13 Dec 26 02:10 /dev/zvol/pool/vm-101-disk-0 -> ../../zd0
cr0x@server:~$ lsblk -o NAME,TYPE,SIZE,MOUNTPOINT,FSTYPE /dev/zd0
NAME TYPE  SIZE MOUNTPOINT FSTYPE
zd0  disk  200G

Qué significa: El ZVOL es un dispositivo de disco crudo zd0. Si lo ves montado, mapeado a DM o usado por iSCSI,
eso explica “busy”.

Decisión: Rastrea la cadena de dependencias antes de planear cualquier ventana de migración. La gente se molesta cuando desconectas “solo un disco”.

Task 6: Comprobar recuento de snapshots y riesgo por retención (bloques fijados)

cr0x@server:~$ zfs list -t snapshot -o name,used,refer -s creation | grep '^pool/vm-101-disk-0@' | tail -n 5
pool/vm-101-disk-0@auto-2025-12-26_0000   1.2G   180G
pool/vm-101-disk-0@auto-2025-12-26_0100   600M   180G
pool/vm-101-disk-0@auto-2025-12-26_0200   400M   180G
pool/vm-101-disk-0@auto-2025-12-26_0300   250M   180G
pool/vm-101-disk-0@auto-2025-12-26_0400   200M   180G

Qué significa: Tienes snapshots frecuentes. La columna used sugiere churn activo. Es probable que bloques antiguos estén fijados.

Decisión: Si esperabas que “la carga reescriba sola en el nuevo volblocksize”, las snapshots te sabotean. Migrar a un nuevo ZVOL con una política limpia de snapshots es la ruta sensata.

Task 7: Medir I/O y latencia a nivel de pool

cr0x@server:~$ zpool iostat -v pool 1 5
              capacity     operations     bandwidth
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
pool        4.20T  3.10T   820   2400   45.2M  110M
  mirror    4.20T  3.10T   820   2400   45.2M  110M
    nvme0n1     -      -   410   1200   22.6M   55M
    nvme1n1     -      -   410   1200   22.6M   55M

Qué significa: Estás centrado en escrituras. Es momento de preguntar: ¿son estas escrituras síncronas? ¿Son pequeñas y aleatorias? ¿Son secuenciales?

Decisión: Si el ancho de banda es alto pero persisten quejas de latencia, el problema probablemente sea latencia por sync, encolamiento o amplificación de escritura,
no el throughput bruto.

Task 8: Comprobar I/O por dataset (¿realmente es el ZVOL el punto caliente?)

cr0x@server:~$ zfs iostat -v pool 1 3
                               capacity     operations     bandwidth
dataset                        alloc   free   read  write   read  write
-----------------------------  -----  -----  -----  -----  -----  -----
pool                            4.20T  3.10T      0      0      0      0
  pool/vm-101-disk-0            200G   3.10T    120   1600   3.2M   62M
  pool/vm-102-disk-0            120G   3.10T     40    300   1.1M   10M

Qué significa: vm-101 domina las escrituras.

Decisión: No ajustes el pool globalmente si un ZVOL es el culpable. Arregla el culpable.

Task 9: Comprobar ratio de compresión y si bloques menores dispararán metadatos

cr0x@server:~$ zfs get -H -o property,value compressratio pool/vm-101-disk-0
compressratio	1.45x

Qué significa: La compresión está trabajando. Bloques más pequeños pueden reducir read-modify-write en escrituras pequeñas,
pero pueden aumentar la sobrecarga de metadatos y reducir la eficiencia de compresión en algunos patrones.

Decisión: Si la carga es tipo DB con I/O aleatorio, favorece la corrección y latencia sobre ganancias teóricas de compresión.

Task 10: Confirmar comportamiento TRIM (sanidad de thin provisioning)

cr0x@server:~$ zfs get -H -o property,value autotrim pool
autotrim	on

Qué significa: El pool está emitiendo TRIM automáticamente (comportamiento dependiente de la implementación). Para ZVOLs usados por invitados,
también necesitas soporte de discard en la pila del invitado para reclamar espacio eficazmente.

Decisión: Si el uso de espacio sigue creciendo incluso después de borrados en el invitado, verifica discard del invitado y retención de snapshots antes de culpar a volblocksize.

Task 11: Estimar factibilidad de reescritura con una prueba rápida de copia lógica (offline o en un clone)

cr0x@server:~$ zfs snapshot pool/vm-101-disk-0@pre-migrate
cr0x@server:~$ zfs clone pool/vm-101-disk-0@pre-migrate pool/vm-101-disk-0-clone

Qué significa: Ahora tienes un clone que comparte bloques. Es genial para probar flujos, no para forzar una reescritura.

Decisión: Usa el clone para validar pasos de export/attach, no para “arreglar” la disposición de bloques. Los bloques compartidos permanecen compartidos hasta reescribirse.

Task 12: Crear el nuevo ZVOL con el volblocksize deseado (el paso real de migración)

cr0x@server:~$ zfs create -V 200G -b 16K -o compression=lz4 -o sync=standard pool/vm-101-disk-0-new
cr0x@server:~$ zfs list -t volume -o name,volsize,volblocksize pool/vm-101-disk-0-new
NAME                     VOLSIZE  VOLBLOCKSIZE
pool/vm-101-disk-0-new   200G     16K

Qué significa: Tienes un ZVOL destino limpio con el nuevo tamaño de bloque. Esta es la única forma de garantizar una política de asignación fresca.

Decisión: Comprométete con un plan de corte. El resto es movimiento de datos y disciplina operativa.

Task 13: Copia a nivel de bloque con progreso (migración offline)

cr0x@server:~$ dd if=/dev/zvol/pool/vm-101-disk-0 of=/dev/zvol/pool/vm-101-disk-0-new bs=16M status=progress conv=sync,noerror
21474836480 bytes (21 GB, 20 GiB) copied, 42 s, 511 MB/s

Qué significa: Estás realizando una reescritura lógica sobre el nuevo ZVOL. El destino será asignado usando su política de volblocksize
a medida que llega el stream.

Decisión: Usa esto solo cuando la fuente esté quieta (VM apagada, filesystem limpio) a menos que estés intencionalmente haciendo una copia coherente por crash.
La mayoría de las veces, apágala.

Task 14: Verificar que el invitado vea las mismas expectativas de identidad del disco (UUIDs, particiones)

cr0x@server:~$ sgdisk -p /dev/zvol/pool/vm-101-disk-0-new
Disk /dev/zvol/pool/vm-101-disk-0-new: 419430400 sectors, 200.0 GiB
Sector size (logical/physical): 512/4096 bytes
Disk identifier (GUID): 5A1B2C3D-4E5F-6789-ABCD-0123456789AB
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      419428351   199.0 GiB   8300  Linux filesystem

Qué significa: La tabla de particiones se copió y parece consistente. La salida “Sector size” es útil: si tu invitado espera 4K,
verifica que no lo sorprendas.

Decisión: Si ves tamaños de sector inesperados o particiones faltantes, detente. No procedas al corte hasta entender por qué.

Task 15: Corte intercambiando nombres de ZVOL de forma atómica (con secuencia cuidadosa)

cr0x@server:~$ zfs rename pool/vm-101-disk-0 pool/vm-101-disk-0-old
cr0x@server:~$ zfs rename pool/vm-101-disk-0-new pool/vm-101-disk-0
cr0x@server:~$ zfs list -t volume -o name,volblocksize pool/vm-101-disk-0
NAME                 VOLBLOCKSIZE
pool/vm-101-disk-0   16K

Qué significa: El nombre canónico ahora apunta al ZVOL nuevo, por lo que cualquier automatización que referencia la ruta del dataset sigue funcionando.

Decisión: Mantén el ZVOL viejo hasta validar. Luego destrúyelo intencionalmente, no por impulso.

Estrategias de migración que realmente funcionan

Strategy A: Recrear + copia a nivel de bloque (simple, contundente, eficaz)

Este es el enfoque de dd o imagen. Funciona bien cuando puedes tener downtime y quieres una reescritura determinista.
También es lo más fácil de explicar al change management: “Creamos un volumen nuevo con la geometría correcta y copiamos el disco.”

Compensaciones:

  • Pros: Garantiza reescritura, respeta el nuevo volblocksize, mínima magia ZFS.
  • Contras: Necesita downtime para consistencia; copia también el espacio libre; lento si el disco está mayormente vacío.

Strategy B: Recrear + migración a nivel de archivo dentro del invitado (datos más limpios, pero más piezas móviles)

Si puedes adjuntar un segundo disco a la VM, puedes migrar a nivel de filesystem: crea nuevo ZVOL, adjúntalo al invitado, formátalo,
copia datos (rsync, dump/restore de DB), luego cambia la configuración de arranque. Esto reescribe solo los datos usados y a menudo resulta en menos
fragmentación. Es más lento en tiempo humano, más rápido en tiempo de almacenamiento.

  • Pros: No copia bloques no usados; puede mejorar la disposición del filesystem invitado; a menudo menos downtime.
  • Contras: Requiere cambios en el invitado; más modos de fallo; necesita manejo cuidadoso de la consistencia de la aplicación.

Strategy C: ZFS send/receive es para datasets, no para la “conversión de volblocksize” directa

La gente recurre a zfs send/receive porque es el martillo ZFS. Es excelente para mover datasets y preservar snapshots.
Pero para cambiar volblocksize, no es la bala de plata que quisieras. La replicación preserva la estructura de bloques tal como viene en el stream.
En muchos casos prácticos, un receive no “reblockea” tus datos en el nuevo volblocksize.

Usa send/receive para:

  • Mover el ZVOL a otro pool u host.
  • Preservar snapshots/historial.
  • Patrones de recuperación ante desastres donde la identidad y puntos en el tiempo importan.

Usa recrear-y-copiar cuando:

  • Quieres un cambio determinista en la política de asignación.
  • Quieres romper con cadenas de snapshots y fragmentación heredadas.
  • Quieres un reinicio de rendimiento que realmente puedas medir.

Strategy D: “Dejar que se reescriba de forma natural” (usualmente una trampa)

A veces los equipos cambian volblocksize y esperan que la carga reescriba suficientes datos con el tiempo para que el nuevo tamaño haga efecto.
Esto puede funcionar en casos estrechos: cargas efímeras, runners CI, caches o plantillas de VM que se reimaginan frecuentemente.

Falla cuando:

  • Snapshots fijan bloques antiguos.
  • El disco es mayormente estático (SO + apps instaladas) y el churn es pequeño relativo al total.
  • La carga es “caliente en una pequeña área” (bases de datos), reescribiendo la misma región y aumentando fragmentación sin cambiar el resto.

Una cita sobre fiabilidad para mantenerte honesto

La conocida frase de Brian Kernighan encaja incómodamente bien con cambios de almacenamiento: “Depurar es dos veces más difícil que escribir el código.”
(idea parafraseada)

Las migraciones de almacenamiento no son difíciles porque los comandos sean complejos. Son difíciles porque las suposiciones se multiplican más rápido que los IOPS en una diapositiva de benchmark.

Tres mini-historias del mundo corporativo

Mini-historia 1: El incidente causado por una suposición equivocada

Una empresa mediana ejecutaba un clúster de virtualización con discos de VM respaldados por ZVOLs. Un ingeniero nuevo notó que el volblocksize por defecto
era 8K en algunos ZVOLs antiguos y 128K en otros más nuevos. Asumió “bloques más grandes = mejor throughput” y que “ZFS haría el resto.”
Se creó una orden de cambio para fijar todo a 128K en todo el entorno.

La primera sorpresa fue que algunos volúmenes se negaron a cambiar porque estaban “busy.” El ingeniero lo sorteó reiniciando VMs por lotes y cambiando la propiedad cuando los discos se desacoplaban.
La segunda sorpresa fue sutil: un puñado de VMs de base de datos empezó a mostrar picos periódicos de latencia.

La suposición que les pegó: cambiar la propiedad convertiría la disposición de datos existente. No lo hizo. Tenían un layout mixto: comportamiento antiguo de ~8K en bloques viejos,
nuevas asignaciones a 128K en bloques recientes, más una larga historia de snapshots que fijaba bloques antiguos. Los gráficos de almacenamiento parecían un sistema ocupado—hasta que miraste la latencia de cola y los tiempos de escritura síncrona.

La solución no fue heroica. Fue aburrida. Crearon ZVOLs nuevos de 16K para las VMs de DB, hicieron copias controladas offline a nivel de bloque, cortaron, y redujeron retención de snapshots para esos volúmenes.
El rendimiento se estabilizó y el clúster dejó de tener los “martes misteriosos.”

Lección: un cambio de propiedad no es un plan de migración. Si necesitas migrar, migra.

Mini-historia 2: La optimización que salió mal

Un equipo empresarial gestionaba objetivos iSCSI respaldados por ZVOLs. Tenían una carga que parecía secuencial en papel: dumps ETL nocturnos y grandes transferencias de archivos.
Fijaron volblocksize=256K para “máximo rendimiento de streaming” y en el benchmark se veía genial.

Luego llegó producción. La carga no eran solo dumps; también había operaciones meta-data y un agente en segundo plano haciendo pequeñas escrituras aleatorias
para “rastrear progreso”, además de una herramienta de seguridad que actualizaba archivos minúsculos constantemente. Los iniciadores iSCSI emitían una mezcla de escrituras síncronas de 4K y escrituras asíncronas más grandes.
La latencia subió y aparecieron pausas; los jobs ETL empezaron a perder ventanas. Los dashboards mostraban margen de ancho de banda, lo que llevó a los primeros respondedores a perseguir el problema equivocado: “Pero no estamos saturando el pool.”

Qué pasó: con volblocksize grande, las pequeñas escrituras aleatorias síncronas dispararon más comportamiento read-modify-write y churn de metadatos.
La parte secuencial se aceleró; la latencia de cola empeoró. Y la latencia de cola es lo que notan los usuarios y lo que los sistemas distribuidos amplifican.

El rollback fue incómodo porque intentaron “simplemente poner volblocksize de vuelta.” Eso no reordenó las asignaciones ya existentes; solo cambió futuras escrituras.
Terminaron recreando los ZVOLs a 16K, restaurando desde backups a nivel de aplicación (no a nivel de bloque) y aceptando que la victoria del benchmark nunca representó la producción.

Lección: optimizar para el caso medio es la forma de comprarte outages. Optimiza para la carga mixta fea que realmente corre a las 2 a.m.

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

Un entorno regulado tenía un estándar: cada ZVOL de disco de VM debía crearse desde un script wrapper que fija
volblocksize según la clase de carga (VM general, base de datos, intensivo en logs) y etiqueta el dataset con una nota legible por humanos.
Nadie amaba el script. Todos querían “simplemente crear un volumen.”

Años después, una renovación de almacenamiento los obligó a migrar pools. Durante la planificación descubrieron una dispersión de ZVOLs con tamaños extraños y problemas de rendimiento.
Las etiquetas del script hicieron obvio cuáles volúmenes eran clase DB, cuáles generales y cuáles eran excepciones creadas a mano durante incidentes.

Cuando una base de datos de facturación sensible empezó a mostrar picos de latencia tras el movimiento, el equipo tenía una línea base documentada clara: debía ser 16K. Lo era.
Así que no perdieron una semana discutiendo tamaños de bloque. Revisaron latencia de sync, verificaron salud del SLOG, encontraron un iniciador mal configurado que forzaba flushes y arreglaron el problema real.

La práctica aburrida no fue el script en sí. Fue la insistencia en repetibilidad y metadatos: el sistema describía qué debía ser.
Eso evitó una espiral especulativa de ajustes bajo presión.

Lección: la mejor herramienta de migración es un estándar que aplicaste cuando no estabas en crisis.

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

1) Síntoma: “Cambiamos volblocksize y no pasó nada”

Causa raíz: Los bloques existentes no se reescribieron; la retención de snapshots fijó asignaciones antiguas.

Solución: Recrea el ZVOL con el -b deseado y realiza una reescritura lógica (copia a nivel de bloque offline o restauración a nivel de invitado).
Revisa snapshots y retención; no cargues una década de snapshots en una migración de rendimiento a menos que realmente las necesites.

2) Síntoma: “La latencia de escritura aleatoria subió tras aumentar volblocksize”

Causa raíz: Amplificación read-modify-write y sobrecarga de metadatos en escrituras pequeñas y síncronas.

Solución: Para cargas tipo DB aleatorias, elige volblocksize entre 8K–16K más a menudo que no. Valida con pruebas específicas de la carga,
no con benchmarks secuenciales genéricos. Recrea y reescribe si necesitas consistencia en el layout.

3) Síntoma: “El uso de espacio no bajó tras borrar datos en la VM”

Causa raíz: Discard del invitado no habilitado, snapshots fijan bloques antiguos, o la carga reescribe sin liberar por cadenas de snapshots.

Solución: Confirma discard/TRIM en el invitado, elimina snapshots innecesarias y asegúrate de que la herramienta de backups no esté snapshotteando cada hora forever.

4) Síntoma: “zfs set volblocksize falla con ‘volume is busy’”

Causa raíz: El dispositivo de bloque está adjunto, abierto, mapeado o exportado. Muchas plataformas impiden cambiarlo en uso.

Solución: No programes un tweak en vivo riesgoso. Crea un nuevo ZVOL con el tamaño correcto y migra. Si necesitas downtime casi nulo, usa replicación a nivel de aplicación o mirroring dentro del invitado y luego corta.

5) Síntoma: “Las lecturas son rápidas, las escrituras lentas y la CPU está baja”

Causa raíz: Escrituras síncronas golpeando la ruta de latencia lenta (sin SLOG adecuado, sync mal configurado o almacenamiento que no puede confirmar rápido).

Solución: Confirma el comportamiento de sync en la aplicación y en ZFS. Si despliegas SLOG, hazlo correctamente (medio con protección contra pérdida de energía), o no lo hagas.
No uses sync=disabled como característica de rendimiento a menos que aceptes perder escrituras confirmadas.

6) Síntoma: “Tras la migración, el rendimiento mejoró brevemente y luego empeoró”

Causa raíz: La fragmentación creció por escrituras aleatorias pequeñas continuas; la política de snapshots impedía limpieza; el filesystem invitado puede estar muy fragmentado.

Solución: Revisa la política de snapshots, considera mantenimiento periódico a nivel de invitado (p. ej., mantenimiento DB, trim del filesystem) y monitoriza indicadores de fragmentación.
No trates volblocksize como un ajuste milagroso único.

Broma #2: Las snapshots son como la retención de correo corporativo—todos las aman hasta que descubren que están almacenando cada mala decisión para siempre.

Listas de verificación / plan paso a paso

Lista de decisión: ¿debes recrear el ZVOL?

  • ¿La carga está dominada por I/O aleatorio pequeño (4K–16K)? Si sí, probablemente quieras un volblocksize más pequeño.
  • ¿Tienes una larga cadena de snapshots? Si sí, la “reescritura natural” no convertirá bloques antiguos limpiamente.
  • ¿El volumen está ocupado y no puede cambiar la propiedad? Esa es tu respuesta: recrear y hacer cutover.
  • ¿Necesitas un cambio predecible y medible en una ventana de mantenimiento? Recrea.
  • ¿El volumen es efímero y se reescribe con frecuencia end-to-end? Podrías salirte con solo fijarlo para futuras escrituras.

Paso a paso: recrear y cortar seguro (offline, drama mínimo)

  1. Métricas de referencia. Captura iostat del pool y dataset durante la ventana problemática. Confirma cómo se ve “mal” para poder verificar “mejor”.
  2. Inventario de propiedades. Anota volsize, volblocksize, compression, sync,
    reservation/refreservation y la política de snapshots.
  3. Asegura que puedas revertir. Toma una snapshot final y confirma que los backups son válidos (no solo “configurados”).
  4. Programa downtime o método de consistencia. Apaga la VM o quiescea la aplicación. Decide qué significa “consistente”.
  5. Crea el ZVOL destino. Usa zfs create -V ... -b ... con propiedades explícitas. Sin sorpresas por herencia.
  6. Copia los datos. Usa copia a nivel de bloque para simplicidad, o copia a nivel de invitado para eficiencia. Valida el resultado.
  7. Haz el corte renombrando o readjuntando. Prefiere rename de dataset para compatibilidad con automatización. Confirma rutas de dispositivo.
  8. Arranca y valida. Revisa filesystem del invitado, salud de la aplicación y latencia de almacenamiento.
  9. Monitorea 24–72 horas. Vigila latencia de cola, escrituras síncronas y crecimiento de snapshots.
  10. Retira el ZVOL viejo. Guárdalo durante una ventana de rollback definida, luego destrúyelo intencionalmente. Documenta el cambio.

Paso a paso: si insistes en “cambiar en sitio”

A veces no puedes migrar de inmediato. Si vas a fijar volblocksize sin recrear, hazlo con los ojos abiertos:

  1. Confirma que no hay snapshots que mantendrán los bloques viejos para siempre (o acepta la consecuencia).
  2. Pon la propiedad solo durante un período tranquilo; espera cero mejora inmediata.
  3. Planifica un “evento de reescritura” posterior (restauración desde backup, reimagen, copia completa del disco) que realmente fuerce el cambio de layout.

Preguntas frecuentes

1) ¿Puedo cambiar volblocksize en un ZVOL existente?

A veces puedes establecer la propiedad; a veces rechazará si el volumen está ocupado. Incluso cuando tiene éxito, típicamente afecta solo nuevas asignaciones.
No convierte de forma fiable el layout de datos existente.

2) ¿Por qué recrear el ZVOL funciona cuando cambiar la propiedad no?

Recrear fuerza que todos los bloques se asignen de nuevo bajo la nueva política. Copiar datos a un ZVOL fresco provoca una reescritura lógica completa,
que es lo que realmente necesitas para “migrar” el comportamiento del tamaño de bloque.

3) ¿ZFS send/receive cambia volblocksize?

No lo trates como una herramienta de conversión. Send/receive es excelente para replicación y mover datasets, pero no garantiza una transformación de reblocking
de las asignaciones existentes. Si necesitas un layout determinista, recrea y reescribe.

4) ¿Qué volblocksize debo usar para discos de VM?

Para discos de VM de uso general, 8K–16K es un rango común y práctico. Las bases de datos suelen preferir más pequeño. Cargas secuenciales grandes pueden justificar mayores.
Elige según los tamaños de I/O observados y el comportamiento de sync, no por ideología.

5) ¿Un volblocksize más pequeño siempre es más rápido para I/O aleatorio?

A menudo sí, pero no siempre. Los bloques más pequeños pueden reducir read-modify-write en escrituras pequeñas, pero pueden aumentar la sobrecarga de metadatos y reducir
la eficiencia de compresión. Si estás limitado por CPU en compresión o metadatos, lo pequeño puede perjudicar. Mide con pruebas representativas de producción.

6) ¿Cómo interfieren las snapshots con la migración de volblocksize?

Las snapshots mantienen referencias a bloques antiguos. Incluso si el invitado reescribe datos, los bloques antiguos permanecen asignados y la fragmentación persiste.
Terminas con un layout mixto y con menos beneficios de los esperados.

7) ¿Qué hay de poner sync=disabled para “arreglar latencia”?

Eso no es una solución; es una decisión de negocio para aceptar posible pérdida de escrituras confirmadas en caída de energía. Si puedes aceptar ese riesgo, ok—documentalo.
Si no, resuelve la ruta real de sync (latencia del dispositivo, diseño del SLOG, comportamiento del iniciador).

8) ¿Puedo usar thin provisioning de zvol con seguridad en una migración?

Sí, pero entiende el reclaim. Asegura que discard/TRIM funcione fin a fin (invitado → hipervisor → ZVOL → pool → SSD). Recuerda también que las snapshots pueden derrotar el reclaim.
Migrar mediante restauración a nivel de invitado suele reclamar espacio mejor que copiar a nivel de bloque.

9) ¿Cómo demuestro que el nuevo volblocksize ayudó?

Compara latencia antes/después (especialmente latencia de cola), tiempos de escrituras síncronas y métricas a nivel de aplicación. El ancho de banda del pool por sí solo es una señal débil.
Usa zpool iostat, zfs iostat y mediciones específicas de la carga.

10) Si ya cambié volblocksize, ¿debería volverlo atrás?

Si lo cambiaste y viste regresión, revertir la propiedad puede no deshacer los cambios de layout ya escritos. Puede detener la deriva futura,
pero la solución limpia sigue siendo recrear y reescribir para el volumen afectado.

Próximos pasos que puedes tomar esta semana

Si tienes quejas de rendimiento de ZVOL y una pila de intentos de afinamiento medio recordados, haz esto en orden:

  1. Elige un ZVOL problemático y captura una línea base de 10 minutos durante carga real: zpool iostat -v 1 y zfs iostat -v 1.
  2. Haz inventario de snapshots y retención para ese ZVOL. Si tienes un museo de snapshots, admítelo y planea limpieza o una migración que no arrastre el museo.
  3. Crea un ZVOL de prueba con el volblocksize objetivo y realiza una migración controlada en una ventana de mantenimiento. Mide latencia de cola y comportamiento de la aplicación.
  4. Estandariza la creación: scriptéala, documéntala, etiqueta datasets. El tú del futuro estará cansado y enojado; ayúdalo ahora.

El punto no es adorar un número como 8K o 16K. El punto es convertir la disposición de bloques en una decisión deliberada y luego hacerla cumplir recreando cuando necesites un cambio real.
ZFS te da herramientas afiladas. Úsalas como si fueras a estar de guardia cuando corten.

← Anterior
TLS-RPT para correo: Obtén visibilidad de fallos TLS (y arréglalos)
Siguiente →
Por qué Windows y Linux pueden ofrecer FPS diferentes en la misma CPU

Deja un comentario