Esta semana me tocó implementar un espacio de almacenamiento (Datastore en jerga VMware) utilizando un servidor FreeBSD con sistema de archivos ZFS sobre NFS. Una combinación muy interesante para hosts ESXi, especialmente para almacenar backups y snapshots de máquinas virtuales, ya que al hacer uso de las ventajas de ZFS (compresión y deduplicación) se logra un mejor aprovechamiento de los discos.

El proceso de instalación y configuración de NFS en FreeBSD es bastante simple, tal como lo he explicado anteriormente, y montar un Datastore NFS en un host ESXi es una tarea trivial utilizando el cliente vSphere. Pero, al momento de verificar el funcionamiento del nuevo Datastore implementado con ZFS sobre NFS, los resultados fueron poco más que terribles: una tasa de transferencia entre el host ESXi y el servidor FreeBSD de algo más de 1 Mb/seg. Muy diferente a los resultados que había tenido con clientes GNU/Linux.

Esto ocurre a causa de una situación especial cuando se utiliza NFS implementado con ZFS para un Datastore en un host ESXi. El problema se debe a que el cliente NFSv3 de ESXi fuerza la sincronización (commit) de cada una de las escrituras individualmente. Cuando el cliente se conecta al servidor, siempre solicita una conexión NFSv3 de tipo sync, por ende el servidor NFS se ve forzado a sincronizar todas las escrituras (mediante el comando O_SYNC), independientemente de cómo esté configurado. Esto tiene sentido en el contexto de lo que ESXi hace, ya que necesita que un determinado bloque sea efectivamente escrito en el disco subyacente antes de informar de manera confiable al guest que la escritura se ha realizado.

Sin embargo, cuando de fondo se utiliza ZFS, la sincronización de escrituras provoca que se deba procesar el log de transacciones de ZFS (ZIL, ZFS Intent Log). Asumiendo que el ZIL está activado, por supuesto. Ante cada commit de NFS el sistema de archivos ZFS debe hacer un flush del ZIL. La constante sincronización de escrituras (commit), a causa de que el cliente NFSv3 de ESXi trabaja en modo sync, termina provocando una cantidad enorme de procesamiento (flush) del ZIL. En definitiva, la combinación de ZFS y NFS sobrecarga el ZIL al punto de que el rendimiento se ve afectado en sobremanera.

Es mejor dejar que ZFS escriba los bloques a disco cuando sea el momento adecuado en lugar de pedirle que sincronice constantemente (lo cual fuerza el flush constante del ZIL).

¿Cómo resolver este problema?

Para eliminar este inconveniente es posible optar por diferentes soluciones. Una alternativa consiste en colocar el ZIL en un par de discos rápidos SSD en RAID 1, lo cual mejora el rendimiento. Aunque aún así va a notarse una degradación de la performance, y por supuesto se debe contar con la tecnología al alcance.

Una solución más económica consiste en directamente desactivar el ZIL para aquellos datasets compartidos por NFS (a costa de disminuir la robustez del sistema de archivos ZFS ante crashes):

# zfs set sync=disable tank/dataset 

Aunque deshabilitar el ZIL no será causa de fallas a nivel filesystem, esta configuración no se recomienda para sistemas que requieren mantener la consistencia (por ejemplo servidores de bases de datos).

También es posible deshabilitar completamente el ZIL en el kernel agregando la siguiente línea en el archivo de configuración /etc/loader.conf:

vfs.zfs.zil_disable="1" 

Este cambio es persistente y desactiva el uso del ZIL durante el inicio.

El autor del artículo Speeding up FreeBSD's NFS on ZFS for ESX clients - Technical Musings propone, como solución superadora, hackear el subsistema NFS para que el kernel ignore los commits a disco de los clientes. Haciendo esto, los pedidos de commit del cliente ESXi no afectan el filesystem, lo cual evita el impacto negativo en la performance. A mi parecer esta es una solución algo aventurada, ya que en caso de un crash de sistema se pueden producir fallos e inconsistencias a nivel filesystem. Notar que en este caso no se está haciendo una escritura a disco luego de un commit NFS, sino que es simplemente ignorado y la escritura se produce en otro momento (presumiblemente al llenarse la caché o finalizar la conexión). En cambio, al deshabilitar el ZIL la escritura a disco se hace efectiva, sólo que se pierde el log de transacciones para mantener la consistencia de los datos ante un crash.

Tal como comentaba al inicio, al verificar el rendimiento, luego de finalizar la instalación, la tasa de transferencia de datos a través de la red entre el servidor FreeBSD y el host ESXi era de poco más de 1 Mb/s. Además, monitoreando el sistema con la herramienta atop se podía comprobar una alta contención de disco. Esto se debía a la sobrecarga ocasionada por el ZIL.

Luego de aplicar esta configuración (deshabilitar el ZIL) en tiempo de ejecución, y mientras se realizaba una transferencia de datos desde el host ESXi hacia el servidor FreeBSD, la tasa de transferencia aumentó considerablemente, y de forma inmediata, hasta más de 240 Mb/s. Un valor mucho más razonable para una red Gigabit Ethernet. Por otro lado, la contención de disco disminuyó notablemente, lo que comprobó la alta sobrecarga que le estaba imponiendo el ZIL al sistema de archivos ZFS, al ser gestionado por el subsistema NFS.

Otras optimizaciones

Además de deshabilitar el ZIL, es posible lograr mejoras adicionales deshabilitando el registro de tiempos de acceso, modificando el tamaño de registro, entre otras (ver la guía de tuning de ZFS).

Referencias

ZFS Tuning Guide - FreeBSD Wiki

Speeding up FreeBSD's NFS on ZFS for ESX clients - Technical Musings

The ZFS Intent Log - Neelakanth Nadgir's blog

NFS and ZFS, a fine combination - Bizarre ! Vous avez dit Bizarre ?


Tal vez pueda interesarte


Compartí este artículo