このテストで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