Una novedad del próximo núcleo Linux 3.10, bcache
La versión 3.10 de Linux incluye por primera vez bcache, una capa para los dispositivos de bloques que permite utilizar discos SSD como cache de uno (o varios) discos tradicionales, de manera transparente y con diferentes políticas (write-through y write-back). Así se puede combinar un disco SSD con un disco tradicional para intentar conseguir las ventajas de ambos (gran capacidad y gran velocidad de acceso).
Obviamente la idea de utilizar un dispositivo rápido como cache de uno lento y de mayor capacidad no es nueva. Respecto a los sistemas de ficheros y dispositivos de almacenamiento podemos encontrar implementaciones parecidas: en el sistema de archivos ZFS, en Fusion Drive de Apple o Flashcache de Facebook. En el caso de bcache, que es una evolución de Flashcache, se trabaja a nivel de bloque con total independencia del sistema de archivos utilizado. Otro proyecto relacionado es el target dm-cache que en Linux 3.10 está marcado como experimental. En este último caso se pretende utilizar un dispositivo de bloques local (una partición o disco) como cache para acelerar el acceso a medios de almacenamiento SAN (como recursos iSCSI).
En el momento de escribir este artículo el kernel Linux 3.10 todavía no se ha lanzado, pero gracias a la transparencia propia del software libre se puede seguir su desarrollo al minuto. Así que cuando leí la noticia en Phoronix de que Torvalds acababa de hacer el merge de bcache en la rama principal del kernel me entraron ganas de probarlo. Como no he sido lo suficientemente rápido en hacerlo, he dado tiempo a que en www.kernel.org preparen un archivo con el código fuente de la RC1 (release candidate 1) de la versión 3.10. De haber sido más rápido tendría que haber descargado el código, lo que aún se puede hacer, desde el servidor git.
Descargando e instalando el nuevo núcleo:
El proceso de construcción del núcleo está tan bien automatizado que, una vez instaladas las dependencias necesarias:
usuario@Sputnik:~$ sudo apt-get install git-core libncurses5 libncurses5-dev libelf-dev asciidoc binutils-dev linux-source libncurses5 libncurses5-dev fakeroot build-essential crash kexec-tools makedumpfile kernel-wedge kernel-package
y por supuesto descargado y desarchivado el código fuente:
vcarceler@Sputnik:~$ wget https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.10-rc1.tar.xz --2013-05-14 11:51:31-- https://www.kernel.org/pub/linux/kernel/v3.x/testing/linux-3.10-rc1.tar.xz Resolviendo www.kernel.org (www.kernel.org)... 149.20.4.69, 198.145.20.140 Conectando con www.kernel.org (www.kernel.org)[149.20.4.69]:443... conectado. Petición HTTP enviada, esperando respuesta... 200 OK Longitud: 73128916 (70M) [application/x-xz] Grabando a: “linux-3.10-rc1.tar.xz” 100%[====================================================================================================>] 73.128.916 579K/s en 2m 6s 2013-05-14 11:53:39 (565 KB/s) - “linux-3.10-rc1.tar.xz” guardado [73128916/73128916] vcarceler@Sputnik:~$ tar -xJf linux-3.10-rc1.tar.xz
Bastará con especificar qué componentes de Linux se van a compilar. Esto se hace mediante una configuración para construir el núcleo.
En nuestro caso vamos a partir de la configuración utilizada por el núcleo que estamos utilizando antes de actualizar. Así que entraremos en el directorio del código fuente y ejecutaremos:
vcarceler@Sputnik:~/linux-3.10-rc1$ cp -vi /boot/config-`uname -r` .config «/boot/config-3.2.0-23-generic-pae» -> «.config» vcarceler@Sputnik:~/linux-3.10-rc1$
Una vez copiada la configuración será necesario procesarla con 'make oldconfig', al hacerlo se nos preguntará por los valores de los nuevos parámetros (que existen en Linux 3.10 y no están especificados en nuestra configuración que corresponde a una versión anterior). Cuando nos pregunte escogeremos el valor por defecto manteniendo pulsada la tecla enter.
vcarceler@Sputnik:~/linux-3.10-rc1$ make oldconfig
A partir de la versión 2.6.32 de Linux es posible seleccionar automáticamente aquellos módulos que son necesarios para nuestro hadware, de manera que ahorraremos tiempo al compilar partes de Linux que no necesitamos. Igual que en el apartado anterior, si nos pregunta, podemos escoger el valor por defecto.
vcarceler@Sputnik:~/linux-3.10-rc1$ make localmodconfig
Finalmente podemos lanzar la herramienta que nos despliga el menú de opciones para seleccionar aquellas que convenga.
vcarceler@Sputnik:~/linux-3.10-rc1$ make menuconfig
En nuestro caso, activaremos:
- Device Drivers > Multiple devices driver support (RAID and LVM) -> Block device as cache
- Device Drivers > Multiple devices driver support (RAID and LVM) -> Cache target (EXPERIMENTAL), Snapshot target y Thin provisioning target.
Realmente para utilizar bcache únicamente necesitamos el primer punto, pero como tampoco había probado dm-cache y los otros targets aprovecho para incluirlos.
Una vez que la configuración ha sido guardada viene el trabajo duro para la máquina, compilar!
vcarceler@Sputnik:~/linux-3.10-rc1$ time make -j5
El parámetro -j de make permite especificar el número de ficheros del núcleo que se compilarán en paralelo (cuando sea posible). Normalmente se suele indicar el número de núcleos que tenga nuestra máquina + 1 para garantizar que no habrá ningún núcleo parado.
Una vez compilado podemos instalar los módulos y el núcleo ejecutando:
sudo make modules_install
sudo make install
Después podremos reiniciar la máquina y arrancar con Linux 3.10 - rc1!
Sobre bcache
La herramienta que me ha llevado a compilar una RC de Linux tiene una naturaleza interesante, algunos de sus rasgos son:
- Se distingue entre cacheset, cache device y storage device. El primero, es el agregado formado por uno o varios discos rápidos que actúan como cache y uno o varios discos grandes que guardan los datos. Por supuesto el cache device sería el disco rápido que actúa como cache y el storage device es el disco tradicional que guarda la información.
- Se supone que los cache device son discos SSD y los storage device son discos tradicionales, de manera que todo se orienta hacia conseguir un mayor rendimiento dadas las características de cada dispositivo. A saber:
- Los discos SSD son mucho mejores que los tradicionales en las operaciones de lectura/escritura aleatorias
- Los discos tradicionales no son malos en las operaciones de lectura/escritura secuenciales. Se discrimina (configurable) el tráfico secuencial para que se salte la cache y vaya directamente al disco de respaldo
- Las escrituras aleatorias realizadas en el SSD se convierten en escrituras secuenciales cuando los datos se mueven al disco tradicional
El modo de operación, gracias a las bcache-tools que conviene descargar, se resume en:
- Hay que marcar los dispositivos que se van a utilizar como discos cache o de respaldo. Lo que se puede hacer dispositivo a dispositivo o varios a la vez. Cuando se formatean discos de respaldo y de cache quedan conectados de forma automática.
make-bcache -B /dev/sdb make-bcache -C /dev/sdc make-bcache -B /dev/sda /dev/sdb -C /dev/sdc
- Los dispositivos bcache deben registrarse
echo /dev/sdb > /sys/fs/bcache/register echo /dev/sdc > /sys/fs/bcache/register
Una vez registrados se podrá acceder al correpondiente dispositivo /dev/bcacheN para formatearlo y montarlo con normalidad. - Después de haber registrado los dispositivos de chache y respaldo, es necesario conectar el dispositivo de respaldo con un cache set. Esto se hace utilizando el UUID del cache set en /sys/fs/bcache
Esta operación sólo se debe realizar una vez, en los próximos arranques únicamente será necesario registrar los dispositivos.echo <UUID> > /sys/block/bcache0/bcache/attach
Para ilustrar valores reales podemos leer el excelente artículo SSD caching using Linux and bcache, en el que el autor pone a prueba bcache utilizando los siguientes discos:
Dispositivo | Capacidad | Random ops (read/write) | Sequential (read/write) |
---|---|---|---|
Intel 330 SSD | 60GB | 42000/52000 op/s | 500/450 MB/s |
WD Green Disk (5400 RPM) | 2TB | 100 op/s | 110 MB/s |
Y se puede ilustrar con el esquema que ha preparado el mismo autor
Sobre el entorno de pruebas
Ha llegado el momento de aclarar que no tengo ningún disco SSD a mano para hacer de cache, y mucho menos cuento con los suficientes para que los alumnos repliquen la experiencia como práctica. Это неважно.
No importa porque hasta ahora todo lo he hecho en una máquina virtual con VirtualBox, y:
- VirtualBox permite identificar un disco duro como SSD (para que el SO huésped lo vea como SSD, aunque probablemente a bcache con que sea un dispositivo de bloque le valga)
- VirtualBox permite limitar el ancho de banda disponible para las imágenes de disco
Así que a la máquina virtual le agrego dos discos nuevos, uno de 2GB que va a actuar como SSD y no tendrá limitación de velocidad y otro de 8GB que actuará como un disco tradicional y tendrá su velocidad limitada a 1MB/s.
vcarceler@sombragris:~$ VBoxManage bandwidthctl "Ubuntu-RAID-LVM-Linux-3.10" --name "limit" --add disk --limit 1 vcarceler@sombragris:~$ VBoxManage storageattach "Ubuntu-RAID-LVM-Linux-3.10" --storagectl "Controlador SCSI" --port 1 --bandwidthgroup limit vcarceler@sombragris:~$
Obsérvese que la sentencia utilizada difiere en sintáxis de lo expresado en la documentación oficial de VirtualBox. Esta es la sintaxis válida para la versión de VirtualBox utilizado (que es la 4.1.12 distribuida con Ubuntu 12.04 LTS).
También hay que tener en cuenta un par de factores que pueden alterar el resultado esperado:
- I/O Cache del anfitrión. Nuestros discos virtuales son ficheros en el SO anfitrión. Así que el sistema operativo anfitrión puede utilizar su cache para tratar de acelerar el acceso a estos datos. VirtualBox permite desde su interfaz gráfica desactivar esta opción para el controlador de los discos, de manera que el acceso a los ficheros no haga uso de la cache de la máquina física.
- La cache del propio SO virtualizado. Puesto que Linux utilizará la memoria disponible para acelerar la entrada/salida a disco, nos podemos encontrar con una velocidad de acceso aparente superior a la del dispositivo. Este efecto se puede mitigar cuando el volumen de datos excede en mucho a la capacidad de la cache o bien actuando sobre /proc/sys/vm/min_free_kbytes para indicar a Linux que mantenga libre cierta cantidad de memoria y, por lo tanto, poner un límite a la memoria principal utilizable como cache.
Con esto ya podemos arrancar nuestra máquina virtual y encontrar en /dev/sdb un disco SSD de 2GB y en /dev/sdc un disco tradicional de 8GB que está limitado a una velocidad de acceso de 1MB/s.
Probando bcache en nuestro entorno virtualizado
Un entorno de pruebas virtualizado no es adecuado para medir el desempeño real de bcache pero nos puede servir para familizarizarnos con la herramienta. En este caso la primera tarea será instalar bcache-tools clonando su repositorio git y compilando. En mi caso antes de poder compilar ha sido necesario instalar el paquete uuid-dev.
vcarceler@Sputnik:~$ git clone http://evilpiepirate.org/git/bcache-tools.git
Cloning into 'bcache-tools'...
vcarceler@Sputnik:~$ cd bcache-tools/
vcarceler@Sputnik:~/bcache-tools$
vcarceler@Sputnik:~/bcache-tools$ sudo apt-get install uuid-dev
vcarceler@Sputnik:~/bcache-tools$ make
cc -O2 -Wall -g make-bcache.c bcache.o -luuid -o make-bcache
cc -O2 -Wall -g probe-bcache.c -luuid -o probe-bcache
cc -O2 -Wall -g bcache-super-show.c bcache.o -luuid -o bcache-super-show
vcarceler@Sputnik:~/bcache-tools$ sudo make install
install -m0755 make-bcache bcache-super-show /usr/sbin/
install -m0755 probe-bcache /sbin/
install -m0644 61-bcache.rules /lib/udev/rules.d/
install -m0755 bcache-register /lib/udev/
install -m0755 initramfs/hook /etc/initramfs-tools/hooks/bcache
install -m0644 -- *.8 /usr/share/man/man8
vcarceler@Sputnik:~/bcache-tools$
Y probamos bcache:
- Formateamos los dos disopositivos
root@Sputnik:/mnt# make-bcache -C /dev/sdb -B /dev/sdc
UUID: e78aa303-335e-4ba7-a96f-0a2c07cd62af
Set UUID: e067170c-95a6-4c4a-a122-44f6b8fa9842
version: 0
nbuckets: 4096
block_size: 8
bucket_size: 1024
nr_in_set: 1
nr_this_dev: 0
first_bucket: 1
UUID: 839f2625-f49a-46da-aed0-2611aec00ef7
Set UUID: e067170c-95a6-4c4a-a122-44f6b8fa9842
version: 1
block_size: 8
data_offset: 16
root@Sputnik:/mnt# - Registramos los dispositivos
echo /dev/sd* >/sys/fs/bcache/register_quiet
- Creamos un sistema de archivos y lo montamos
root@Sputnik:~# mkfs.ext4 /dev/bcache0 mke2fs 1.42 (29-Nov-2011) Discarding device blocks: hecho Etiqueta del sistema de ficheros= OS type: Linux Tamaño del bloque=4096 (bitácora=2) Tamaño del fragmento=4096 (bitácora=2) Stride=0 blocks, Stripe width=0 blocks 524288 inodes, 2097150 blocks 104857 blocks (5.00%) reserved for the super user Primer bloque de datos=0 Número máximo de bloques del sistema de ficheros=2147483648 64 bloque de grupos 32768 bloques por grupo, 32768 fragmentos por grupo 8192 nodos-i por grupo Respaldo del superbloque guardado en los bloques: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632 Allocating group tables: hecho Escribiendo las tablas de nodos-i: hecho Creating journal (32768 blocks): hecho Escribiendo superbloques y la información contable del sistema de ficheros: 0/6hecho root@Sputnik:~# mkdir /mnt/bcache0 root@Sputnik:~# mount /dev/bcache0 /mnt/bcache0/ root@Sputnik:~# df -h S.ficheros Tamaño Usados Disp Uso% Montado en /dev/sda1 7,5G 5,5G 2,0G 74% / udev 992M 4,0K 992M 1% /dev tmpfs 401M 280K 401M 1% /run none 5,0M 0 5,0M 0% /run/lock none 1002M 0 1002M 0% /run/shm /dev/bcache0 7,8G 18M 7,4G 1% /mnt/bcache0 root@Sputnik:~#
- Comprobamos que nuestro dispositivo bcache0 está funcionando
root@Sputnik:/sys/fs/bcache/e067170c-95a6-4c4a-a122-44f6b8fa9842# ll total 0 drwxr-xr-x 7 root root 0 may 16 19:35 ./ drwxr-xr-x 3 root root 0 may 16 19:32 ../ -r--r--r-- 1 root root 4096 may 16 19:35 average_key_size lrwxrwxrwx 1 root root 0 may 16 19:35 bdev0 -> ../../../devices/pci0000:00/0000:00:0d.0/ata3/host2/target2:0:0/2:0:0:0/block/sdc/bcache/ -r--r--r-- 1 root root 4096 may 16 19:35 block_size -r--r--r-- 1 root root 4096 may 16 19:35 btree_cache_size -r--r--r-- 1 root root 4096 may 16 19:35 bucket_size lrwxrwxrwx 1 root root 0 may 16 19:35 cache0 -> ../../../devices/pci0000:00/0000:00:0d.0/ata2/host1/target1:0:0/1:0:0:0/block/sdb/bcache/ -r--r--r-- 1 root root 4096 may 16 19:35 cache_available_percent --w------- 1 root root 4096 may 16 19:35 clear_stats -r--r--r-- 1 root root 4096 may 16 19:35 congested -rw-r--r-- 1 root root 4096 may 16 19:35 congested_read_threshold_us -rw-r--r-- 1 root root 4096 may 16 19:35 congested_write_threshold_us -r--r--r-- 1 root root 4096 may 16 19:35 dirty_data --w------- 1 root root 4096 may 16 19:35 flash_vol_create drwxr-xr-x 2 root root 0 may 16 19:35 internal/ -rw-r--r-- 1 root root 4096 may 16 19:35 io_error_halflife -rw-r--r-- 1 root root 4096 may 16 19:35 io_error_limit -rw-r--r-- 1 root root 4096 may 16 19:35 journal_delay_ms -r--r--r-- 1 root root 4096 may 16 19:35 root_usage_percent drwxr-xr-x 2 root root 0 may 16 19:35 stats_day/ drwxr-xr-x 2 root root 0 may 16 19:35 stats_five_minute/ drwxr-xr-x 2 root root 0 may 16 19:35 stats_hour/ drwxr-xr-x 2 root root 0 may 16 19:35 stats_total/ --w------- 1 root root 4096 may 16 19:35 stop -rw-r--r-- 1 root root 4096 may 16 19:35 synchronous -r--r--r-- 1 root root 4096 may 16 19:35 tree_depth --w------- 1 root root 4096 may 16 19:35 unregister root@Sputnik:/sys/fs/bcache/e067170c-95a6-4c4a-a122-44f6b8fa9842#
Y hasta aquí la primera prueba de bcache, ahora podemos valorar su comportamiento en diferentes situaciones. Y sobre todo quien sea el afortunado poseedor de un disco SSD puede hacer algunas pruebas de velocidad que tendrán mayor interés que lo que se pueda medir en un entorno virtualizado.
Más información: