이 테스트에서 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"
vs. 결과를 비교해 보세요 .
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(및 기타 파일 시스템)와 동일한 동작을 제공합니다.
두 번째 문장이 옳다고 생각하지 않습니다!
공평하게 말하자면, 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