fsync() が最初に呼び出されると rename() が長くかかるのはなぜですか?

fsync() が最初に呼び出されると rename() が長くかかるのはなぜですか?

このテストでfsync()が最初に呼び出されると、rename()が長くかかるのはなぜですか?

環境:btrfs、機械式ハードディスク、Debian 9コンテナ、カーネル5.0.17-200.fc29.x86_64で実行。

テストコマンド: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

FORCE_UNSAFE_IO=""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

現在の戦略dpkg(例:Debian 9)は思ったよりも複雑です。しかし、それが実際にイベントに影響を与えるかどうかはわかりません。詳細については、この質問にいくつかの背景知識があります。AIO fsyncはdpkgのパフォーマンスを向上させることができますか?

これが関連しているかどうかはわかりませんが、一部のファイルシステムでは、fsync()がディレクトリを効果的に同期させることができることがわかりました。これは、fsync()が返される前に新しく作成されたファイルがディスクに表示されるようにするためです。 ext2ではこれは起こりませんが、ext4では何が起こるかをどこかで読みました。部分的な証拠として以下を参照してください。ext4:今回は、fsyncにログなしで親ディレクトリを同期させます。

sync追跡時間に驚いた場合は、dpkg個々のfsync()呼び出しをグローバルsync()呼び出しに置き換えるパッチを適用すると、全体の時間が約13秒に短縮されるようです。私のシステムで何の欠陥も見つかりませんでした。 dpkg私は他の潜在的な副作用のためにこの方法の使用をやめました。[1][2]

ベストアンサー1

コミットの説明によれば、 rename() の遅延が次のために発生すると予想しました。Btrfs:新しい名前を記録した後のログ同期。これはカーネルv4.19に追加されました。

ハードリンクが作成されたとき、または名前が変更されたときに発生した新しいファイル名の履歴がログに残ります。

このアプローチはより簡単なだけでなく、[...] ext4、xfs、およびf2fs(および他のファイルシステム)と同じ動作を提供します。

2番目の文章が正しいとは思わない!

公平に言えば、dpkgパッケージが正しくインストールされていると記録する前に、ファイルを含むディレクトリをfsync()することを忘れてしまったことを指摘する必要があります。ただし、このbtrfsの動作は、残りのLinuxとまったく一致しません。

私はXFSがrename()で新しいディレクトリエントリを同期するとは信じていません(つまり、意図的にそれが続くのを待ちます)。 XFS rename() 内の同期書き込みに関する私の前提は、部分的に次のスレッドに基づいています。https://marc.info/?l=linux-xfs&m=139863577410237&w=2

ext4の場合、私が言及した証拠は次のとおりです。fsync()新しいディレクトリエントリが返される前に同期することができます。しかし、私はext4の rename() がこれを行うとは思いません。

最近の議論につながります。AIO fsync() 操作そして、メタデータ更新の効率的なバッチ処理を可能にする方法について説明します。通常、 rename() は同期操作ではないと仮定するため、仮想 AIO rename() については多くの議論はありません。

(通常、btrfsは私に少し不思議に思えます。つまり、ここ数回のリリースでこのデータ整合性のバグ修正が行われたのを見ましたが、ひどく聞こえる唯一のものではありません)。変更ログこのバージョンの場合)。


私は rename() 遅延がBTRFS_NEED_LOG_SYNC最後の行から返されるべきだと思います。btrfs_log_new_name()

私が見つけた方法は次のとおりです。CPU時間オフ。スタックトレースで待ち時間を集計します。スタックトレースは次のとおりです。

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

おすすめ記事