Sou a: Inici / Usuaris / Victor Carceler / Artículos / Linux 3.10 incluye bcache

Una novedad del próximo núcleo Linux 3.10, bcache

Una novedad del próximo núcleo Linux 3.10, bcache

Tux, la mascota oficial de Linux

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:

  1. Device Drivers > Multiple devices driver support (RAID and LVM) -> Block device as cache
  2. Device Drivers > Multiple devices driver support (RAID and LVM) -> Cache target (EXPERIMENTAL), Snapshot target y Thin provisioning target.

Configuración de make menuconfig para incluir soporte de bcache y, ya que estamos, de dm-cache

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:

  1. 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.
  2. 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
  3. Un mismo cache device puede actuar como cache para varios storage device. En tal caso puede generarse congestión en el cache device y para conseguir un mejor rendimiento convendría saltárselo accediendo directamente a los discos de respaldo. Bcache monitoriza los cache device para detectar la congestión y activar un bypass cuando sea necesario.
  4. Los dispositivos de respaldo se pueden añadir y quitar de un cacheset dinámicamente, mientras están montados y en uso.
  5. Es posible seleccionar la política de cache a utilizar: writethrough, writeback y writearound.
  6. Estabilidad e integridad, es una solución que ya se está utilizando en producción. Promete recovers from unclean shutdown dado que las escrituras no se completan hasta que la cache no está en un estado consistente con el dispositivo de respaldo. Y se perfila como una mejor solución (y más barata) que las unidades de almacenamiento alimentadas con baterías.

 

El modo de operación, gracias a las bcache-tools que conviene descargar, se resume en:

  1. 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
  2. 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.
  3. 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
    echo <UUID> > /sys/block/bcache0/bcache/attach
    Esta operación sólo se debe realizar una vez, en los próximos arranques únicamente será necesario registrar los dispositivos.

 

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:

DispositivoCapacidadRandom 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

Original: http://pommi.nethuis.nl/wp-content/uploads/2012/12/hdd-ssd-scheme.png

 

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:

  1. 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.
  2. 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:

  1. 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#
  2. Registramos los dispositivos
    echo /dev/sd* >/sys/fs/bcache/register_quiet
  3. 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:~#
  4. 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:

Navegació