Warum dauert rename() länger, wenn zuerst fsync() aufgerufen wird?

Warum dauert rename() länger, wenn zuerst fsync() aufgerufen wird?

Warum dauert rename() in diesem Test länger, wenn zuerst fsync() aufgerufen wird?

Umgebung: btrfs, mechanische Festplatte, Debian 9-Container, läuft auf Kernel 5.0.17-200.fc29.x86_64.

Testbefehl: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

Vergleichen Sie die Ergebnisse von 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

Die aktuelle Strategie dpkg(z. B. in Debian 9) ist ausgefeilter, als Sie vielleicht denken. Ich bin mir jedoch nicht sicher, ob sie in diesem Fall wirklich Auswirkungen hätte. Wenn Sie weitere Einzelheiten wünschen, finden Sie in dieser Frage einige Hintergrundinformationen:Könnte AIO fsync die Dpkg-Leistung verbessern?

Ich weiß nicht, ob das relevant ist, aber mir fällt ein, dass fsync() auf manchen Dateisystemen auch das Verzeichnis effektiv synchronisieren kann. Damit wird sichergestellt, dass neu erstellte Dateien auf der Festplatte sichtbar sind, bevor fsync() zurückkehrt. Ich habe irgendwo gelesen, dass das auf ext2 nicht passiert, aber auf ext4 schon. Als teilweisen Beweis sieheext4: Lassen Sie fsync dieses Mal das übergeordnete Verzeichnis wirklich im No-Journal synchronisieren

Falls Sie von den Zeitverzögerungen überrascht sind sync, kann ich bestätigen, dass das dpkgErsetzen der einzelnen fsync()-Aufrufe durch einen globalen sync()-Aufruf die Gesamtzeit auf etwa 13 Sekunden zu reduzieren scheint. Und ich habe auf meinem System nichts Unzulängliches daran gefunden. Ich dpkghabe diesen Ansatz nur wegen anderer potenzieller Nebenwirkungen nicht mehr verwendet.[1][2]

Antwort1

Basierend auf der Commit-Beschreibung gehe ich davon aus, dass die Verzögerungen bei rename() verursacht werden durchBtrfs: Synchronisierungsprotokoll nach Protokollierung des neuen Namens. Dies wurde im Kernel v4.19 hinzugefügt.

Sorgen Sie dafür, dass die Protokollierung des neuen Dateinamens (die beim Erstellen eines Hardlinks oder beim Umbenennen erfolgt) im Protokoll erhalten bleibt.

Dieser Ansatz ist nicht nur einfacher, [...] sondern bietet uns auch dasselbe Verhalten wie ext4, xfs und f2fs (möglicherweise auch andere Dateisysteme).

Ich glaube nicht, dass der zweite Satz richtig ist!

Fairerweise muss ich darauf hinweisen, dpkgdass vergessen wird, die Verzeichnisse mit den Dateien per fsync() zu synchronisieren, bevor das Paket als korrekt installiert aufgezeichnet wird. Dieses Verhalten von btrfs passt jedoch nicht ganz perfekt zum Rest von Linux.

Ich glaube nicht, dass XFS den neuen Verzeichniseintrag innerhalb von rename() synchronisiert (d. h. absichtlich wartet, bis er gespeichert ist). Meine Vermutung, dass innerhalb von XFS rename() keine synchronen Schreibvorgänge durchgeführt werden, basiert teilweise auf diesem Thread:https://marc.info/?l=linux-xfs&m=139863577410237&w=2

Für ext4 habe ich Beweise dafür erwähnt, dassfsync()könnte den neuen Verzeichniseintrag synchronisieren, bevor er zurückkehrt. Aber ich glaube nicht, dass rename() von ext4 dies tut.

Ich habe auf aktuelle Diskussionen überAIO fsync()-Operationen, und wie sie eine effiziente Stapelverarbeitung von Metadatenaktualisierungen ermöglichen könnten. Über ein hypothetisches AIO rename() wurde nicht viel diskutiert, da üblicherweise davon ausgegangen wird, dass rename() keine synchrone Operation ist!

(btrfs kommt mir generell etwas verdächtig vor. Ich sehe, dass dieser Bugfix für die Datenintegrität in den letzten paar Releases enthalten war, und es war nicht der einzige beängstigend klingende Fix in derÄnderungsprotokollfür diese Versionen).


Ich denke, die Verzögerungen bei rename() müssen durch die BTRFS_NEED_LOG_SYNCRückgabewerte aus der letzten Zeile vonbtrfs_log_neuer_name().

Ich habe dies herausgefunden, indem ichCPU-Auszeit. Es aggregiert die Wartezeit nach Stacktrace. Die Stacktraces sehen folgendermaßen aus:

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

verwandte Informationen