El anterior post defendiendo la existencia de fragmentación bajo Linux fue recibido con escepticismo. Para ser justos, la excesiva longitud del anterior post llevó a no extenderlo más de lo necesario. En este post, mostraremos un par de casos triviales en los que se puede observar fragmentación en sistemas Linux usando Ext4.
En primer lugar, una prueba muy simple, escribir dos archivos grandes a la vez. Se lanzan en paralelo dos procesos dd que crearán sendos archivos de 10 GB. Para que no haya dudas, la prueba se hace en un sistema de archivos recién formateado (nota: dd parece ocupar la memoria especificada en bs, es decir, en este test los dos procesos dd ocupan 1GB de RAM)
----------------------------------------------------------------
# for i in `seq 2`; do (dd if=/dev/zero of=prueba-$i bs=512M count=20 &); done
---------------------------------------------------------------- Una vez terminados de crear los archivos, se examina la fragmentación....
----------------------------------------------------------------
# filefrag prueba*
prueba-1: 164 extents foundprueba-2: 155 extents found
----------------------------------------------------------------
Antes de continuar, aclarar que el tamaño máximo de un extent en Ext4 es de 128 MB. Eso quiere decir que dada una asignación de bloques perfecta, un archivo de 10 GB ocuparía 80 extents contiguos. Sin embargo, los archivos recién creados han necesitado el doble (en otros sistemas o con diferentes parámetros de dd puede haber muchos menos o muchos más, y tiene su explicación).
No suena nada bien, y los detalles pueden revisarse comprobando la ubicación y límites de cada extent con filefrag prueba* -v (cuya extensa salida no pondré aquí). En mi caso hay varios extents de tamaño máximo, 32768 bloques -128 MB-, pero también varios de 4096 -16 MB- y alguno incluso con menos, varios de 20 y pico mil, 16 mil, 12 mil...en definitiva: irregular. Si cotejamos datos de la columna "physical" de ambos archivos, el problema es más evidente: los extents de los dos archivos se van entrecruzando. Por ejemplo, el primer extent de archivo-1, el primero de archivo-2, y el segundo extent de archivo-1, van uno detrás de otro.
Y esto es con dos archivos. Imagínense 5 ó 10. O más. Y no estamos hablando de casos extravagantes y sacados de contexto, sino simplemente de copiar archivos.
Hay que ser justos y señalar que esto no es un problema de rendimiento en equipos comunes, ya que una cosa es fragmentarse en pedacitos de pocos KB por todo el disco, y otra hacerlo en pedazos de 128 ó incluso 16 MB, esta fragmentación probablemente ni siquiera se note en benchmaks. Sin embargo, no sirve de excusa para ignorarla. En equipos donde se requieran sistemas de almacenamiento profesionales es de imaginar que Ext4 no de la talla (por esta razón existen empresas con sistemas de archivo e incluso SOs propietarios especializados exclusivamente en optimizar casos como estos). Pero tampoco hay que irse por las nubes, bastaría con copiar dos archivos grandes a la vez a través de una interfaz gráfica para reproducir este problema.
Pero hay otros ejemplos simples. ¿Qué tal, por ejemplo, un archivo vacío al que se añaden 4KB (1 bloque) 200 veces, simulando una especie de archivo de log que va creciendo? En un sistema de archivos Ext4 nuevamente formateado desde cero, por supuesto. Cabría esperar que simplemente se añadieran los 200 bloques uno detrás de otro, ¿verdad?
----------------------------------------------------------------
["oflag=append conv=notrunc" son ambos necesarios para que se vayan añadiendo datos al archivo, "conv=fsync" sincroniza el archivo a disco para asegurarse de que no se queda en RAM]
# for i in `seq 200`; do dd if=/dev/zero of=prueba bs=4K count=1 oflag=append conv=notrunc,fsync; done
[Un montón de datos de salida de dd]
# filefrag prueba
prueba: 9 extents found
----------------------------------------------------------------
Si echamos un ojo a los datos de filefrag prueba -v, resulta que los 200 bloques están divididos en un extent con 184 bloques, otro con 7, dos con 2, y cinco con 1, y los extents no son contiguos entre ellos. Fragmentación discriminada y absurda (tengo una teoría razonable que explique este absurdo comportamiento, pero tendrá que esperar a un artículo posterior).
En definitiva, como se puede ver la fragmentación en Linux ocurre. Probablemente se podrían buscar más casos, algunos de ellos retorcidos como variar el tamaño de los archivos asignados con truncate(1) o archivos "sparse"...pero estos casos son simples y demuestran que no hace falta romperse la cabeza para encontrar fragmentación en Linux. Si quieren encontrar fragmentación en sus propios sistemas, prueben a buscar con filefrag por su $HOME. Sugiero empezar por este:
# filefrag ~/.mozilla/firefox/*.default/*.sqlite
Los archivos places.sqlite, cookies.sqlite, formhistory.sqlite y urlhistory3.sqlite, que corresponden a las bases de datos sqlite que utiliza Firefox en versiones modernas, seguramente estén divididos en varios fragmentos si su perfil de Firefox lleva funcionando un tiempo. Cosas como esta, entre otras, son las que hacen que nada más arrancar Firefox y se trata de introducir una url, la AwesomeBar tarde un poco más en leer el disco y reaccionar. Si son administradores de bases de datos, los archivos de la base de datos pueden tener cierta fragmentación acumulada. /var (las bases de datos de paquetes dpkg/rpm en particular) también son buenos candidatos. ¿A que ahora los desfragmentadores no parecen una idea tan estúpida? (un modo cutre y fácil de imitarlos es copiar el archivo fragmentado en otro y mover el archivo copiado al original)
El próximo post será sobre el funcionamiento de los algoritmos de asignación de bloques de Ext4. Ya puestos, por qué no hacer de esto una serie...