¿Por qué rename() tarda más cuando se llama primero a fsync()?

¿Por qué rename() tarda más cuando se llama primero a fsync()?

En esta prueba, ¿por qué rename() tarda más cuando se llama primero a fsync()?

Entorno: btrfs, HDD mecánico, contenedor Debian 9, ejecutándose en el kernel 5.0.17-200.fc29.x86_64.

Comando de prueba:dpkg -r linux-image-4.9.0-9-amd64 >/dev/null 2>&1 && sync && time perf_4.9 trace --no-inherit -s dpkg $FORCE_UNSAFE_IO -i linux-image-4.9.0-9-amd64_4.9.168-1_amd64.deb && time sync

Compare los resultados de FORCE_UNSAFE_IO=""vs.FORCE_UNSAFE_IO="--force-unsafe-io"

 dpkg (31632), 374488 events, 100.0%

   syscall            calls    total       min       avg       max      stddev
                               (msec)    (msec)    (msec)    (msec)        (%)
   --------------- -------- --------- --------- --------- ---------     ------
   fsync               3442 14849.586     0.002     4.314   149.959      4.11%
   rename              8463 14573.509     0.003     1.722   358.675      4.80%
   wait4                  7  8043.762     0.004  1149.109  8028.468     99.78%
   read               44025  2151.135     0.000     0.049     3.732      0.57%
   open               19301   213.628     0.002     0.011     0.375      0.90%
   write               7846   165.460     0.003     0.021     0.149      0.42%
   sync_file_range     6834    96.513     0.001     0.014     0.822      2.20%
...
real    0m41.703s
user    0m9.709s
sys 0m6.586s

real    0m0.162s
user    0m0.000s
sys 0m0.003s
 dpkg (1919), 334232 events, 100.0%

   syscall            calls    total       min       avg       max      stddev
                               (msec)    (msec)    (msec)    (msec)        (%)
   --------------- -------- --------- --------- --------- ---------     ------
   wait4                  7  8290.981     0.007  1184.426  8279.676     99.84%
   read               44399  2168.096     0.000     0.049     2.146      0.50%
   fsync                 25   653.530     0.006    26.141    68.754      8.65%
   rename              8463   522.282     0.003     0.062    69.620     22.53%
   open               12467   163.671     0.002     0.013     0.217      0.97%
   write               7846   160.979     0.003     0.021     0.356      0.50%
   sync_file_range     3417    89.676     0.010     0.026     0.841      2.05%
...
real    0m13.498s
user    0m9.643s
sys 0m5.517s

real    0m0.146s
user    0m0.000s
sys 0m0.004s

La estrategia actual dpkg(por ejemplo, en Debian 9) es más sofisticada de lo que imagina. Sin embargo, no estoy seguro de que realmente afecte este caso. Si desea más detalles, hay algunos antecedentes en esta pregunta:¿AIO fsync podría mejorar el rendimiento de dpkg?

No sé si esto es relevante, pero se me ocurre que en algunos sistemas de archivos fsync() también puede sincronizar efectivamente el directorio. Esto es para garantizar que los archivos recién creados sean visibles en el disco antes de que regrese fsync(). Leí en alguna parte que esto no sucede en ext2, pero sí en ext4. Como evidencia parcial, verext4: haga que fsync sincronice el directorio principal sin diario de verdad esta vez

En caso de que le sorprendan los synctiempos finales, puedo confirmar que la aplicación de parches dpkgpara reemplazar las llamadas fsync() individuales con una llamada sync() global parece mantener el tiempo total en aproximadamente 13 segundos. Y no he encontrado nada inadecuado en eso en mi sistema. dpkgSimplemente dejé de usar ese enfoque debido a otros posibles efectos secundarios.[1][2]

Respuesta1

Según la descripción de la confirmación, espero que los retrasos en el cambio de nombre () sean causados ​​porBtrfs: registro de sincronización después de registrar un nuevo nombre. Esto se agregó en el kernel v4.19.

Haga que el registro del nuevo nombre de archivo (lo que ocurre al crear un enlace físico o cambiar el nombre) persista en el registro.

Este enfoque no sólo es más simple, [...] sino que también nos da el mismo comportamiento que ext4, xfs y f2fs (posiblemente también otros sistemas de archivos).

¡No creo que la segunda frase sea correcta!

Para ser justos, debo señalar dpkgque se olvida fsync() de los directorios que contienen los archivos, antes de que registre el paquete como instalado correctamente. Pero este comportamiento de btrfs no coincide exactamente con el resto de Linux.

No creo que XFS sincronice la nueva entrada del directorio dentro de rename() (es decir, espera deliberadamente a que persista). Mi presunción contra cualquier escritura de sincronización dentro de XFS rename() se basa en parte en este hilo:https://marc.info/?l=linux-xfs&m=139863577410237&w=2

Para ext4, mencioné evidencia de quesincronización()podría sincronizar la nueva entrada del directorio antes de que regrese. Pero no creo que rename() de ext4 lo haga.

Me vinculé a discusiones recientes sobreOperaciones AIO fsync()y cómo podrían permitir el procesamiento por lotes eficiente de actualizaciones de metadatos. No ha habido mucha discusión sobre un hipotético rename() de AIO, porque la suposición habitual es que rename() no es una operación sincrónica.

(Btrfs me parece un poco sospechoso en general. Es decir, veo que esta corrección de errores de integridad de datos se realizó en las últimas versiones y no fue la única solución que suena aterradora en elregistro de cambiospara estos lanzamientos).


Creo que los retrasos en el cambio de nombre () deben ser provocados por el BTRFS_NEED_LOG_SYNCretorno de la última línea debtrfs_log_new_name().

La forma en que encontré esto fue usandotiempo fuera de CPU. Agrega el tiempo de espera por seguimiento de pila. Los seguimientos de la pila se ven así:

io_schedule_timeout
wait_for_completion_io
write_all_supers
btrfs_sync_log
btrfs_sync_file
do_fsync
__x64_sys_fsync
do_syscall_64
entry_SYSCALL_64_after_hwframe
-                dpkg (23528)
    9735954

io_schedule_timeout
wait_for_completion_io
write_all_supers
btrfs_sync_log
btrfs_rename2
vfs_rename
do_renameat2
__x64_sys_rename
do_syscall_64
entry_SYSCALL_64_after_hwframe
-                dpkg (23528)
    9147785

io_schedule
bit_wait_io
__wait_on_bit
out_of_line_wait_on_bit
write_all_supers
btrfs_sync_log
btrfs_sync_file
do_fsync
__x64_sys_fsync
do_syscall_64
entry_SYSCALL_64_after_hwframe
-                dpkg (23528)
    4478158

io_schedule
bit_wait_io
__wait_on_bit
out_of_line_wait_on_bit
write_all_supers
btrfs_sync_log
btrfs_rename2
vfs_rename
do_renameat2
__x64_sys_rename
do_syscall_64
entry_SYSCALL_64_after_hwframe
-                dpkg (23528)
    4376109

información relacionada