17 de junio de 2010

Linux y la fragmentación: provocando fragmentación en Ext4

(Nota: Este post es el segundo de una serie de varios artículos sobre la fragmentación. Se recomienda leer la serie completa: 1, 3 y 4).

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 found
prueba-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...

13 comentarios:

  1. Una pregunta que puede resultar estúpida por desconocimiento pero ahí va. En un caso real ¿se haría sync de la forma que tu la estás haciendo en los ejemplos?. Supongo que tendrá influencia en la gestión de caché de disco y la forma de escribir finalmente los datos en él.

    Un saludo.

    ResponderEliminar
  2. Cheli: Si te refieres al "sync" del primer ejemplos, lo he quitado, es de una versión inicial del borrador del post. No hace ningún mal en realidad, pero tampoco ningún bien (los procesos dd se inician en paralelo y el sync casi inmediatamente después)

    Respecto al conv=fsync si, es necesario en Ext4 si quieres emular un log llenándose con el paso del tiempo, ya que si no en Ext4 no se asignarán bloques (que es lo que ocurre con los logs a largo plazo)

    ResponderEliminar
  3. Muy buenos artículos. Los sistemas en los que he visto una mayor fragmentación han sido MTAs de correo. Mucho trasiego de ficheros de muy diversos tamaños ...

    ResponderEliminar
  4. Anónimo8:01 a. m.

    Y no hay ningun defragmentador en linux?
    La unica opcion para desfragmentar es copiar toda la particion a otro FS?

    ResponderEliminar
  5. Anónimo9:07 a. m.

    Muy buen artículo. Espero con ansias el siguiente post.

    ResponderEliminar
  6. Anónimo9:08 a. m.

    rrey supongo que no lo dices en serio, pero no creo que sea talibán antilinux, más bien lo defiende, es absurdo cubrir linux de un halo de perfección mágica, artículos como éste hacen que me guste ser usuario de linux, ayuda a entender como funciona y se ve que no es magia lo que ocurre.

    ResponderEliminar
  7. Gran artículo, sé señor.
    Ahora me da cosa hacer un filefrag de las máquinas que tengo bajo KVM, aunque no está del todo mal:
    filefrag srvdns.dd
    srvdns.dd: 44 extents found, perfection would be 42 extents

    Un saludo.

    ResponderEliminar
  8. Creo que con conv=fsync estás cargandote el delayed allocation y de paso el Multiblock allocator. Ext4 retarda todo lo que puede la escritura real en disco es decir que no escribe bloques de 4Ks como en tu ejemplo. Escribir más tarde => mayor cantidad de datos a escribir + mejores decisiones en la asignación de bloques => menos fragmentación.
    Además los extents no son muy utiles si fuerzas la escritura cada 4Ks porque el asignador de bloques no puede tomar grandes decisiones con tan pocos datos. Vamos que la fragmentación en esta prueba entre este ext4 y un ext3 han de ser similares al no aprovechar las mejoras.

    ResponderEliminar
  9. Angel Roldán: De nuevo, es una simulación de un log que crece con el tiempo. El aumento del tamaño de los archivos con el tiempo es algo normal, y es lo que pretende probar: la prueba no impide que el asignador de bloques vaya colocando los nuevos bloques uno detrás de otro (aumetando el extent de tamaño), y a pesar de ello no lo ha hecho.

    ResponderEliminar
  10. Hola que tal? hablas en el artículo de ext4, la cosa es tan fea así en ext3? existe alguna otra alternativa que fragmente menos, claro no digo que sea perfecto. :P

    Saludos

    ResponderEliminar
  11. Un artículo muy interesante.
    ¡Muchas gracias por escribirlo!

    ResponderEliminar
  12. pero de que linux hablas? en la actualidad ubuntu ha avanzado mucho y ha implementado estrategias para mejorar dudo que hayan pasado por alto este problema, da mas datos de las distros usadas el tipo y año de fabricación de los discos utilizados, ademas el filedefrag no es ni mucho menos el mejor defragmentador en linux!

    ResponderEliminar