
Después de leer algunos artículos sobre la caché de páginas de Linux VFS y los parámetros ajustables, dirty_ratio
tenía la impresión de que la caché de páginas funcionaría como capa de caché de lectura y escritura.
Pero usar la prueba simple a continuación funciona bien para mejorar la velocidad de lectura de archivos que se encuentran en el caché de la página pero que no parecen funcionar en escrituras.
p.ej
Borre el caché y escriba en el archivo.
# swapoff -a
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/dev/zero of=/home/flo/test bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.182474 s, 172 MB/s
Compruebe que el archivo esté realmente en la caché de la página
# vmtouch /home/flo/test
Files: 1
Directories: 0
Resident Pages: 7680/7680 30M/30M 100%
Elapsed: 0.000673 seconds
Leer del archivo para confirmar que realmente proviene del caché.
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.00824169 s, 3.8 GB/s
Suelte el caché y vuelva a leer para comprobar la diferencia de velocidad.
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.132531 s, 237 MB/s
Como no estoy usando DIRECT_IO con dd, esperaba que el caché de la página se usara como un tipo de caché de reescritura. Y en base a dirty_ratio
o dirty_expire_centiseconds
... eventualmente los datos se enviarían al disco.
¿Alguien puede explicar cómo VFS maneja el proceso de lectura y escritura de manera diferente, especialmente durante las escrituras y por qué no hay ganancia de velocidad?
¿Hay alguna manera de hacer que el vfs sea más agresivo en el almacenamiento en caché de escritura para que se comporte más como el caché de reescritura que puede encontrar en un controlador raid, por ejemplo?
Gracias
flo
Respuesta1
man ext4 tiene esta introducción sobre (no) auto_da_alloc
opción:
Muchas aplicaciones rotas no usan fsync()...
Parece haber una larga historia (alguna tragedia sobre la pérdida de datos) detrás de esto. Que tiene que ver conasignación retrasadade bloques del sistema de archivos. Ext2/3 no tenía eso, pero es una característica bastante importante no sólo de ext4.
Si la aplicación no se sincroniza, ni el usuario manualmente, ni el kernel solo después de 30 segundos, entonces es mejor que el sistema de archivos lo haga de inmediato cuando se trate de una reescritura de archivos. De lo contrario, con DA, pueden suceder fácilmente cosas malas en caso de un corte de energía. Cosas peores que simplemente perder los últimos cambios.
Sin conv=notruncate
el comando dd actúa como una "aplicación" al sobrescribir. Tiene que deshacerse del archivo existente para crear uno nuevo; de lo contrario, obtendrá una mezcla si el archivo existente es más largo.
Con mount -o remount,noauto_da_alloc ...
puede desactivar este comportamiento en ext4. Ahora la escritura en bloque se puede realizar mucho tiempo después del truncamiento.
El siguientenivel de agresiónsería aumentar el tiempo de vencimiento de 30 segundos y el intervalo de verificación de 5 segundos (los valores dirty_..._centisecs en /proc/sys/vm/) para las reescrituras periódicas. Con el 30/5 predeterminado, algunos archivos nuevos se escribirán medio minuto después, a menos que sea muy rápido para eliminarlos más rápido.
Cuanto más agresivo sea el VFS con las páginas no utilizadas, menos agresivo tendrá que ser el sistema de archivos con el dispositivo de bloqueo.
Opciones de montaje y parámetros de escritura
]# findmnt --real
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda3 ext4 rw,relatime,noauto_da_alloc
|-/root/sda1 /dev/sda1 ext2 rw,relatime
`-/root/16 /dev/sda16 ext4 rw,relatime
En una configuración como esta, una sobrescritura se sincroniza inmediatamente en sda16, pero no en los otros dos.
Por el momento (creo que) desactivé por completo la reescritura periódica.
]# grep '' /proc/sys/vm/*centisecs
/proc/sys/vm/dirty_expire_centisecs:720000
/proc/sys/vm/dirty_writeback_centisecs:0
Y ahora por fin estoy juntando páginas sucias:
]# grep nr_dirty /proc/vmstat
nr_dirty 10077
nr_dirty_threshold 437320
nr_dirty_background_threshold 174671
Iintentarpara reunirlos y acercarme de alguna manera a la proporción de fondo predeterminada del 10%. Ayer me sincronicé cuando entré en suspensión de RAM. Tiene sentido: ¿quién quiere dormir con MB de páginas sucias?
mm/writeback.c
Es muy complejo en detalle, se dicen los comentarios. Un problema es no perder el punto de aceleración cuando "1000 dd empiezan a ensuciarse a la vez". La "reescritura" parece apuntar a alrededor de este 10% de bg, a largo plazo. Como muestra mi ejemplo anterior, este 10% (de la RAM total/disponible) tarda mucho en llenarse en condiciones de uso normal (mínimo). Un minuto de navegación ensucia unas 1.000 páginas, aproximadamente.
Después de la teoría, la prueba específica.
Probé 10 bloques en dos de los sistemas de archivos enumerados anteriormente:
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0076396 s, 1.4 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00514406 s, 2.0 GB/s
-> con noauto_da_alloc en la partición raíz (sda3, arriba), la sobrescritura es aún más rápida.
En el ext4 montado por defecto (sda16 arriba) se ralentiza:
]# rm test10
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00800839 s, 1.3 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0740824 s, 142 MB/s
...porque toda la sobrescritura está sincronizada, como vmstat 1 |cut...
se muestra:
0 0
0 0
0 0
-----io----
bi bo
0 10240
0 0
0 0
Manualmente sync
con asignación retrasada
Lo bueno de esto es que lo haces cuando quieres y puedes hacerlo en archivos individuales, pero también en unidades completas.
Además: desmontar, apagar (y suspender) lo tiene incluido.
Lo malo es: riesgo de "corrupción" de longitud cero cuando ocurre un bloqueo/fallo de energía entre una (sobre)escritura y una sincronización. Lo que significa que realmente solo tienes como seguro lo que pones en un almacenamiento externo, o dos.
No puedo encontrar un resultado final. No hay una solución fácil, sólo explicaciones largas (pero al menos lógicas).
Respuesta2
Para ver el comportamiento rápido, tengo que hacerlo rm test
primero. Por ejemplo, veo dd
un informe de 1 GB/s en lugar de 150 MB/s.
Referencias:
auto_da_alloc
enhombre ext4.- Artículo de LWN.net "ext4 y pérdida de datos".
- XFS hace lo mismo en este caso, pero no en el otro caso, ext4 (cambiando el nombre de un archivo existente):https://www.spinics.net/lists/xfs/msg36717.html.
Aunque las referencias solo explican por qué pensé en probar esto, en realidad no explican por qué hace que el IO se bloquee.
En mi computadora, el bloqueo solo parecía ocurrir dentro del nuevo código WBT ("regulación de escritura")... que se agregó en 2016,despuéshiciste tu pregunta. no he analizadopor quécausaría esto. Y desapareció cuando WBT está desactivado.
Mi versión del kernel es 4.18.16-200.fc28.x86_64
.
strace -T
muestra que todo el tiempo se pasó en close(), lo que tiene más sentido para mí. Intenté usarlo perf
también. No funcionó como se suponía, pero mostró rastros de pila como
dd 17068 [003] 475165.381526: sched:sched_switch: dd:17068 [120] T ==> kworker/3:1H:19326 [100]
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c6a8 schedule+0x28 ([kernel.kallsyms])
ffffffffa30def32 io_schedule+0x12 ([kernel.kallsyms])
ffffffffa3461ed7 wbt_wait+0x337 ([kernel.kallsyms])
ffffffffa342ee33 blk_queue_bio+0x123 ([kernel.kallsyms])
ffffffffa342d114 generic_make_request+0x1a4 ([kernel.kallsyms])
ffffffffa342d3c5 submit_bio+0x45 ([kernel.kallsyms])
ffffffffa3377d78 ext4_io_submit+0x48 ([kernel.kallsyms])
ffffffffa335da2c ext4_writepages+0x70c ([kernel.kallsyms])
ffffffffa3209311 do_writepages+0x41 ([kernel.kallsyms])
ffffffffa31f808e __filemap_fdatawrite_range+0xbe ([kernel.kallsyms])
ffffffffa334b9ec ext4_release_file+0x6c ([kernel.kallsyms])
ffffffffa32a9d4e __fput+0xae ([kernel.kallsyms])
ffffffffa30cf474 task_work_run+0x84 ([kernel.kallsyms])
ffffffffa3003e6e exit_to_usermode_loop+0xce ([kernel.kallsyms])
ffffffffa300425d do_syscall_64+0x14d ([kernel.kallsyms])
ffffffffa3a00088 entry_SYSCALL_64_after_hwframe+0x44 ([kernel.kallsyms])
7fcca3a60654 __close+0x14 (/usr/lib64/libc-2.27.so)
lo que me recordó que actualmente estaba probando el deadline
programador de E/S, con WBT ("regulación de reescritura") habilitado. ¡Desactivar WBT (incluso cambiando a CFQ, que es incompatible) me dio un comportamiento rápido nuevamente!
Los perf
comandos que usé para ver esto fueron:
sudo perf record -e sched:sched_stat_sleep -e sched:sched_switch -e sched:sched_process_exit -gP -o ~/perf.data dd if=/dev/zero of=test bs=1M count=30
sudo perf script -i ~/perf.data | cat
Respuesta3
Simplemente no lo uses dd
. Por ejemplo, use cp
y obtendrá el caché de página para escrituras.