AIO fsync가 dpkg 성능을 향상시킬 수 있습니까?

AIO fsync가 dpkg 성능을 향상시킬 수 있습니까?

데비안 패키지 관리자가 dpkgsync_file_range() + fsync() 대신 AIO fsync() 작업 중 하나를 사용하여 상당한 성능 향상을 얻을 수 있습니까?

[제안된] fsync2() API는 애플리케이션이 피하고 싶어하는 동기식이라는 점을 제외하면 기존 AIO_FSYNC/AIO_FDSYNC API와 본질적으로 동일합니다.

AIO_FSYNC [사용]에 대한 나의 유일한 주장은 "구현은 단지 작업 대기열일 뿐이다"라는 것입니다. 이는 파일 시스템 구현과 독립적이므로 대체로 의미가 없지만 실행된 모든 fsync 작업의 자동 커널 측 병렬화를 허용합니다. 이를 통해 파일 시스템은 동시 fsync 작업을 완료할 때 불필요한 로그 쓰기를 자동으로 최적화할 수 있습니다. XFS, ext4 등은 사용자 응용 프로그램이 많은 수의 프로세스/스레드에서 동시에 fsync()를 실행할 때 이미 이 작업을 수행하고 있습니다.

이 간단한 구현을 통해 XFS에서 간단한 "aio fsync로 압축 해제" 워크로드를 허용합니다(예: "많은 4kB 파일 및 aio_fsync() 일괄 쓰기, 새 배치를 디스패치하기 전에 완료된 fsync() 종료") 워크로드 약 2000개 파일/초(동기 쓰기 IO 대기 시간) 범위) 최대 40,000개 파일/초 이상(백엔드 스토리지에 IOPS 쓰기)

--데이브 치너

예제 워크로드는 apt-get install또는 와 유사합니다 dpkg -i(부분적으로는 설치된 패키지의 파일 크기에 따라 다름 :-). dpkg압축을 푼 모든 파일은 이름을 바꾸기 전에 효과적으로 fsync()해야 합니다.

dpkgTed T'so의 제안을 기반으로 최적화되었습니다. 최적화는 특정 지점에서 sync_file_range()에 대한 호출을 추가하는 것입니다. 이 시스템 호출이 이루어졌습니다.아니요fsync()와 동일한 보장을 제공합니다. 설명서를 읽어보세요동기화파일범위()그리고 눈에 띄는 경고에 유의하세요 :-).

이러한 작업 중 어느 것도 파일의 메타데이터를 기록하지 않습니다. 따라서 애플리케이션이 인스턴스화된 디스크 블록 덮어쓰기를 엄격하게 적용하지 않는 한 충돌 후 데이터를 사용할 수 있다는 보장은 없습니다.

dpkgSYNC_FILE_RANGE_WRITE먼저 패키지의 모든 파일을 쓰는 를 사용하여 각 파일이 작성된 후 즉시 데이터 쓰기 저장을 트리거합니다 . 그런 다음 파일을 두 번째로 탐색하고 SYNC_FILE_RANGE_WAIT_BEFORE사용된 데이터가 다시 기록되도록 호출될 때 까지 기다린 후 fsync()마지막으로 파일 이름을 그 자리에서 바꿉니다.

제출물 보기:

내 가설은 fsync() 작업을 병렬화하면 보다 효율적인 일괄 처리를 허용하여 성능을 향상시킬 수 있다는 것입니다.메타데이터디스크의 메타데이터가 항상 일관되도록 하려면 쓰기, 특히 일괄 관련 장벽/디스크 캐시 플러시가 필요합니다.

편집: 적어도 ext4 파일 시스템을 사용할 때 내 가정은 너무 단순한 것 같습니다.

두 번째 일련의 sync_file_range() 호출 및 작업은 SYNC_FILE_RANGE_WAIT_BEFORE이전에 시작된 쓰기 저장이 완료될 때까지 차단됩니다. 이는 기본적으로 지연된 할당이 해결되었음을 보장합니다. 즉, 데이터 블록이 할당 및 기록되고 inode가 (메모리에서) 업데이트되었지만 반드시 디스크에 푸시되는 것은 아닙니다.

[fsync()] 호출은 실제로 inode를 디스크에 강제로 기록합니다. ext4 파일 시스템의 경우 첫 번째 [fsync()]는 실제로 모든 inode를 디스크에 푸시합니다., 이후의 모든 [fsync()] 호출은 사실상 no-ops입니다(파일 "a", "b" 및 "c"가 모두 동일한 파일 시스템에 있다고 가정). 그러나 이는 (무거운) jbd2 커밋 수를 최소화한다는 의미입니다.

이는 Linux 특정 시스템 호출 ---sync_file_range() ---를 사용하지만 결과적으로 모든 파일 시스템에 대해 전반적으로 더 빠른 성능이 제공됩니다. 따라서 나는 이것이 ext4에 대한 해킹이라고 생각하지 않습니다. 비록 이것이 아마도 ext4를 다른 파일 시스템보다 더 빠르게 만들 수는 있겠지만 말입니다.

--테드 소

일부 다른 파일 시스템은 AIO fsync() 작업을 사용하면 이점을 얻을 수 있습니다.

bcachefs(개발 중) ext4보다 서로 다른 파일 간의 IO를 더 잘 격리한다고 주장합니다. 따라서 테스트는 특히 흥미로울 수 있습니다.

ext4는 순수 AIO fsync() 모드에 최적화되지 않은 것 같습니다(다른 파일 시스템에도 동일한 제약이 있을 수 있다고 생각합니다). 그렇다면 동일한 sync_file_range() 호출을 모두 먼저 수행한 다음 모든 AIO fsync() 작업을 두 번째 패스로 시작하고 작업이 완료되면 모든 파일의 이름을 fsync()로 변경하여 완료하는 것이 가능할 것이라고 생각했습니다.


오래된:

그러한 조사의 첫 번째 단계는 측정이어야 합니다 :-).

fsync() 섹션은 를 사용하여 비활성화할 수 있습니다 echo "force-unsafe-io" > /etc/dpkg/dpkg.cfg.d/force-unsafe-io.

지금까지 나는 Debian 9 컨테이너에서 실행해 보았습니다 apt-get install. strace -f -wc예를 들어, "unsafe io" aptitude패키지에는 동기 fsync() 호출이 495개만 있습니다. 일반 설치 중에는 aptitude1011개의 fsync() 호출이 있습니다. "unsafe io"는 또한 이 SYNC_FILE_RANGE_WAIT_BEFORE호출을 비활성화하여 sync_file_range() 호출 수를 1036에서 518로 줄입니다.

그러나 이것이 평균 시간을 단축시킬지는 불분명합니다. 이 경우 실행 간의 무작위 변동에 지나지 않는 것으로 보입니다. 지금까지 기계식 HDD의 ext4 및 XFS를 테스트했습니다.


apt-get총 크기가 21.7MB인 518개의 압축이 풀린 파일을 나타냅니다(아래 출력 참조).

495 fsync() 호출과 관련하여 "unsafe io"가 요청된 경우에도 지속됩니다.

ext4에서 strace 출력은 나머지 fsync() 호출에 약 11초가 걸리는 것을 보여줍니다. XFS에서 해당 수치는 약 7초입니다. 모든 경우에 설치에 대부분의 시간이 소요됩니다 aptitude.

따라서 "안전하지 않은 io"가 설치에 약간의 개선을 가져오더라도 차이가 실제로 눈에 띄기 전에 시스템의 나머지 부분보다 더 빠른(낮은 대기 시간) 장치에 설치 aptitude해야 하는 것처럼 보입니다 . /var하지만 저는 이 틈새 사례를 최적화하는 데 관심이 없습니다.

실행을 실행하면 strace -f -y -e trace=fsync,rename나머지 fsync() 호출 중 2개는 켜져 있고 그 /etc/ld.so.cache~중 493개는 /var/lib/dpkg/패키지 데이터베이스 내의 파일에 대한 호출임을 보여줍니다.

fsync() 호출은 318에 있습니다. /var/lib/dpkg/updates/이는 dpkg 데이터베이스의 증분입니다 /var/lib/dpkg/status. dpkg 실행이 끝나면 델타가 마스터 데이터베이스("체크포인트")로 롤업됩니다.


The following NEW packages will be installed:
  aptitude aptitude-common libboost-filesystem1.62.0 libboost-iostreams1.62.0 libboost-system1.62.0 libcgi-fast-perl libcgi-pm-perl
  libclass-accessor-perl libcwidget3v5 libencode-locale-perl libfcgi-perl libhtml-parser-perl libhtml-tagset-perl libhttp-date-perl
  libhttp-message-perl libio-html-perl libio-string-perl liblwp-mediatypes-perl libparse-debianchangelog-perl libsigc++-2.0-0v5 libsqlite3-0
  libsub-name-perl libtimedate-perl liburi-perl libxapian30
0 upgraded, 25 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/6000 kB of archives.
After this operation, 21.7 MB of additional disk space will be used.

답변1

이 질문은 이것이 ext4 또는 XFS에 도움이 되지 않는다는 것을 나타냅니다.

또한 더 큰 패키지( linux-image-4.9.0-9-amd64) 설치도 테스트했습니다. 그럼에도 불구하고 여전히 같은 시간이 걸리는 것 같습니다 --force-unsafe-io.

외부 2

ext2에서는 --force-unsafe-io설치 시간이 linux-image50초에서 13초로 단축되었습니다.

제가 테스트를 실행하고 있는 커널은 5.0.17-200.fc29.x86_64입니다 CONFIG_EXT4_USE_FOR_EXT2.

사용자 공간 aio_fsync() 구현을 사용하여 ext2를 테스트했습니다. 그러나 최상의 개선은 AIO fsync() 사용에 의존하지 않습니다.

내 진전은 실제로 부작용 때문이었습니다. 모든 fsync() 작업을 먼저 수행한 다음 모든 rename() 작업을 수행하도록 dpkg를 변경했습니다. 패치되지 않은 dpkg는 fsync()마다 rename()을 호출합니다. 내가 사용하고 있는 AIO의 대기열 깊이는 최대 256입니다. 대기열 깊이가 1인 AIO fsync()는 동기식 fsync()보다 상당히 느립니다. 약간의 오버헤드가 있는 것 같습니다. 최상의 개선을 위해서는 SYNC_FILE_RANGE_WRITE모든 원래 작업을 먼저 완료해야 합니다. 개선된 버전의 설치 시간은 linux-image약 18초 정도이다.

이 작업 순서는 실제로 Ted T'so가 원래 제안한 것입니다 :-D. CONFIG_EXT4_USE_FOR_EXT2fsync()는 상위 디렉터리도 동기화하는 데 도움 이 됩니다 . 모든 파일 이름 작업을 먼저 수행하여 디렉터리당 여러 디스크 업데이트를 방지하려고 합니다. CONFIG_EXT2이전 구현이나 일반 파일 시스템에서는 이런 일이 발생하지 않을 것 같습니다 ext4.

ext4: 이번에는 fsync가 로그 없이 상위 디렉터리를 동기화하도록 합니다.

[...] 분명히 여기에는 ext2 기본 모드도 포함됩니다. [...]

https://elixir.bootlin.com/linux/v5.0.17/source/fs/ext4/fsync.c#L38

 * If we're not journaling and this is a just-created file, we have to
 * sync our parent directory (if it was freshly created) since
 * otherwise it will only be written by writeback, leaving a huge
 * window during which a crash may lose the file.  This may apply for
 * the parent directory's parent as well, and so on recursively, if
 * they are also freshly created.

이전과 마찬가지로 fsync() 단계를 sync()로 대체하면 --force-unsafe-io:-)와 일치하여 놀라울 정도로 좋은 성능을 제공하는 것 같습니다. sync() 또는 syncfs()를 사용할 수 있다면 매우 좋은 것 같습니다.

BTFS

btrfs에서 aio_fsync() 테스트를 시작했을 때 최근 데이터 무결성 수정으로 인해 fsync() 작업으로 인해 파일의 rename()이 차단될 수 있다는 사실을 발견했습니다. 나는 btrfs에 관심이 없다고 결정했습니다.

fsync()가 먼저 호출될 때 rename()이 더 오래 걸리는 이유는 무엇입니까?

관련 정보