중복 제거 워프 속도 의 고급 읽기 전용 파일 시스템.
Linux 및 Windows용 고속 고압축 읽기 전용 파일 시스템입니다.
DwarFS는 특히 매우 중복된 데이터에 대해 매우 높은 압축률을 달성하는 데 중점을 둔 읽기 전용 파일 시스템입니다.
중복되는 경우 잘 압축 되어야 하기 때문에 이는 별로 흥미롭지 않게 들릴 것입니다. 그러나 다른 읽기 전용 압축 파일 시스템에서는 이러한 중복성을 제대로 활용하지 못한다는 사실을 발견했습니다. 다른 압축 파일 시스템과 비교하려면 여기를 참조하세요.
DwarFS는 또한 속도 면에서 타협하지 않으며 내 사용 사례에서는 SquashFS와 동등하거나 더 나은 성능을 발휘하는 것으로 나타났습니다. 내 주요 사용 사례의 경우 DwarFS 압축은 SquashFS 압축보다 훨씬 뛰어나고 파일 시스템 구축 속도가 6배 빠르며 일반적으로 DwarFS에서 파일에 액세스하는 속도가 더 빠르며 CPU 리소스를 덜 사용합니다.
DwarFS의 기능에 대한 아이디어를 제공하기 위해 총 크기가 39GiB인 비디오 파일 세트에서 DwarFS와 SquashFS를 빠르게 비교합니다. 특이한 점은 각각의 고유한 비디오 파일에 서로 다른 오디오 스트림 세트가 포함된 두 개의 형제 파일이 있다는 것입니다(이것은 실제 사용 사례입니다). 따라서 비디오와 오디오 데이터 모두에 중복성이 있지만 스트림이 인터리브되고 동일한 블록이 일반적으로 매우 멀리 떨어져 있기 때문에 압축에 이러한 중복성을 활용하는 것이 어렵습니다. SquashFS는 본질적으로 소스 데이터를 전혀 압축하지 못하는 반면, DwarFS는 이론상 최대값에 가까운 거의 3배까지 크기를 줄일 수 있습니다.
$ du -hs dwarfs-video-test
39G dwarfs-video-test
$ ls -lh dwarfs-video-test.*fs
-rw-r--r-- 1 mhx users 14G Jul 2 13:01 dwarfs-video-test.dwarfs
-rw-r--r-- 1 mhx users 39G Jul 12 09:41 dwarfs-video-test.squashfs
또한 SquashFS 이미지를 마운트하고 fio-3.34를 사용하여 임의 읽기 처리량 테스트를 수행할 때 squashfuse
와 squashfuse_ll
모두 약 230MiB/s에서 최고치를 기록합니다.
$ fio --readonly --rw=randread --name=randread --bs=64k --direct=1
--opendir=mnt --numjobs=4 --ioengine=libaio --iodepth=32
--group_reporting --runtime=60 --time_based
[...]
READ: bw=230MiB/s (241MB/s), 230MiB/s-230MiB/s (241MB/s-241MB/s), io=13.5GiB (14.5GB), run=60004-60004msec
이에 비해 DwarFS는 20GiB/s의 무작위 읽기 속도 를 유지합니다.
READ: bw=20.2GiB/s (21.7GB/s), 20.2GiB/s-20.2GiB/s (21.7GB/s-21.7GB/s), io=1212GiB (1301GB), run=60001-60001msec
DwarFS의 특징은 다음과 같습니다.
유사성 해시 함수를 사용하여 유사성을 기준으로 파일을 클러스터링합니다. 이렇게 하면 파일 경계를 넘어 중복성을 더욱 쉽게 활용할 수 있습니다.
압축되지 않은 파일 시스템의 크기를 줄이기 위해 파일 시스템 블록 전체에 대한 분할 분석입니다. 이는 압축된 파일 시스템을 사용할 때 메모리를 절약하므로 캐시에 더 많은 데이터를 보관할 수 있으므로 잠재적으로 더 높은 캐시 적중률을 허용합니다.
파일 또는 파일 조각을 분류한 다음 개별 카테고리를 다르게 처리하는 분류 프레임워크입니다. 예를 들어, 압축할 수 없는 파일을 압축하거나 FLAC 압축을 사용하여 PCM 오디오 데이터를 압축하는 데 시간을 낭비하지 않아도 됩니다.
고도의 멀티스레드 구현. 파일 시스템 생성 도구와 FUSE 드라이버 모두 시스템의 많은 코어를 효과적으로 활용할 수 있습니다.
나는 2013년에 DwarFS 작업을 시작했고 나의 주요 사용 사례와 주요 동기는 약 30GB의 디스크 공간을 차지하는 수백 가지의 서로 다른 Perl 버전이 있다는 것이었고 내 하드 디스크 공간의 10% 이상을 소비하고 싶지 않았습니다. 내가 필요할 때를 위해 주변에 보관하십시오.
그때까지 나는 Cromfs를 사용하여 관리 가능한 크기로 압축했습니다. 그러나 파일 시스템 이미지를 빌드하는 데 걸리는 시간 때문에 점점 더 짜증이 나고, 설상가상으로 약 한 시간 정도 후에 충돌이 발생하는 경우가 더 많았습니다.
나는 분명히 SquashFS도 조사했지만 Cromfs의 압축률에 가까운 곳은 없었습니다.
이것만으로는 DwarFS를 작성하기에 충분하지 않았지만 동시에 나는 최신 C++ 표준의 최근 개발 및 기능에 꽤 집착했고 C++ 취미 프로젝트를 진행하고 싶었습니다. 그리고 저는 꽤 오랫동안 FUSE로 뭔가를 하고 싶었어요. 마지막으로, 압축 파일 시스템의 문제에 대해 잠시 생각해 보았는데 꼭 시도해 보고 싶은 몇 가지 아이디어가 있었습니다.
코드의 대부분은 2013년에 작성되었으며, 가끔씩 정리, 버그 수정, 리팩토링을 두 번 수행했지만 출시가 만족스러울 정도의 상태에 도달한 적은 한 번도 없었습니다. Facebook의 (아주 멋진) Folly 라이브러리에 의존하여 빌드하기에는 너무 어색했고 문서도 없었습니다.
올해 다시 프로젝트를 진행해 보니 상황이 예전만큼 암울해 보이지는 않았습니다. Folly는 이제 CMake로 빌드되므로 방금 하위 모듈로 가져왔습니다. 대부분의 다른 종속성은 널리 사용 가능해야 하는 패키지에서 충족될 수 있습니다. 그리고 나는 몇 가지 기초적인 문서도 작성했습니다.
DwarFS는 일반적으로 기본적으로 최소한의 변경만으로 문제 없이 빌드됩니다. 그렇지 않은 경우 문제를 제기해 주세요. 최신 종속성 세트를 결정하는 데 도움이 될 수 있는 Ubuntu(22.04 및 24.04), Fedora Rawhide 및 Arch용 Docker 이미지를 사용하여 CI 작업을 설정했습니다. 릴리스 tarball에서 빌드하려면 git 저장소에서 빌드하는 것보다 종속성이 덜 필요합니다. 특히 릴리스 tarball에서 빌드할 때는 ronn
도구, Python 및 mistletoe
Python 모듈이 필요하지 않습니다.
알아야 할 몇 가지 사항이 있습니다.
하위 모듈로 포함되고 DwarFS와 함께 구축되는 Folly 및 fbthrift 라이브러리를 분리하려고 시도하는 경향이 있습니다. 나는 그 정서에 동의하지만 불행히도 나쁜 생각입니다. Folly는 ABI 안정성에 대해 어떠한 주장도 하지 않는다는 사실 외에도(즉, Folly의 한 버전에 대해 빌드된 바이너리를 다른 버전에 대해 동적으로 링크할 수는 없습니다), 다른 컴파일로 빌드된 Folly 라이브러리에 대해 안전하게 링크하는 것조차 불가능합니다. 옵션. C++ 표준 버전과 같은 미묘한 차이로도 런타임 오류가 발생할 수 있습니다. 자세한 내용은 이 문제를 참조하세요. 현재 DwarFS가 두 라이브러리의 최소 하위 집합을 구축하고 있으므로 외부 버전의 folly/fbthrift를 사용하는 것조차 불가능합니다. 이들은 dwarfs_common
라이브러리에 번들로 포함되어 있으며 내부적으로 엄격하게 사용됩니다. 즉, DwarFS 라이브러리에 대해 빌드하는 데 Folly 또는 fbthrift 헤더가 필요하지 않습니다.
시스템에 설치된 GoogleTest 버전을 사용할 때 비슷한 문제가 발생할 수 있습니다. GoogleTest 자체에서는 빌드의 일부로 다운로드할 것을 권장합니다. 그러나 cmake
호출에 -DPREFER_SYSTEM_GTEST=ON
전달하면 시스템 설치 버전을 사용할 수 있습니다. 자신의 책임하에 사용하십시오.
다른 번들 라이브러리(즉, fmt
, parallel-hashmap
, range-v3
)의 경우 최소 필수 버전을 충족하는 한 시스템에 설치된 버전이 사용됩니다. 그렇지 않으면 빌드 중에 기본 버전을 가져옵니다.
각 릴리스에는 다운로드할 수 있는 Linux-x86_64
, Linux-aarch64
및 Windows-AMD64
용으로 사전 구축된 정적으로 링크된 바이너리가 있습니다. 이는 종속성 없이 실행 되어야 하며 특히 소스에서 도구를 쉽게 빌드할 수 없는 이전 배포판에서 유용할 수 있습니다.
바이너리 타르볼 외에도 각 아키텍처에 사용할 수 있는 범용 바이너리가 있습니다. 이러한 범용 바이너리에는 단일 실행 파일에 모든 도구( mkdwarfs
, dwarfsck
, dwarfsextract
및 dwarfs
FUSE 드라이버)가 포함되어 있습니다. 이러한 실행 파일은 upx를 사용하여 압축되므로 개별 도구를 결합한 것보다 훨씬 작습니다. 그러나 이는 실행될 때마다 바이너리의 압축을 풀어야 하므로 상당한 오버헤드가 발생할 수 있음을 의미하기도 합니다. 이것이 문제인 경우 "클래식" 개별 바이너리를 사용하거나 범용 바이너리의 압축을 풀 수 있습니다. 예:
upx -d dwarfs-universal-0.7.0-Linux-aarch64
범용 바이너리는 적절한 도구 이름을 딴 기호 링크를 통해 실행될 수 있습니다. 예:
$ ln -s dwarfs-universal-0.7.0-Linux-aarch64 mkdwarfs
$ ./mkdwarfs --help
파일 시스템이 심볼릭 링크를 지원하는 경우 Windows에서도 작동합니다.
> mklink mkdwarfs.exe dwarfs-universal-0.7.0-Windows-AMD64.exe
> .mkdwarfs.exe --help
또는 --tool=<name>
명령줄의 첫 번째 인수로 전달하여 도구를 선택할 수 있습니다.
> .dwarfs-universal-0.7.0-Windows-AMD64.exe --tool=mkdwarfs --help
dwarfs.exe
Windows 바이너리와 마찬가지로 범용 Windows 바이너리는 WinFsp 프로젝트의 winfsp-x64.dll
에 의존합니다. 그러나 범용 바이너리의 경우 DLL이 느리게 로드되므로 DLL 없이도 다른 모든 도구를 계속 사용할 수 있습니다. 자세한 내용은 Windows 지원 섹션을 참조하세요.
DwarFS는 CMake를 빌드 도구로 사용합니다.
Boost와 Folly를 모두 사용하지만 후자는 실제로 패키지를 제공하는 배포판이 거의 없기 때문에 하위 모듈로 포함되어 있습니다. Folly 자체에는 여러 가지 종속성이 있으므로 여기에서 최신 목록을 확인하세요.
또한 매우 공간 효율적이고 메모리 매핑이 가능하며 잘 정의된 형식으로 메타데이터를 저장하기 위해 Facebook Thrift, 특히 frozen
라이브러리를 사용합니다. 이는 하위 모듈로도 포함되어 있으며 DwarFS가 작동할 만큼만 포함된 매우 축소된 라이브러리와 컴파일러만 빌드합니다.
그 외에 DwarFS는 실제로 FUSE3과 Folly가 이미 의존하고 있는 압축 라이브러리 세트(즉, lz4, zstd 및 liblzma)에만 의존합니다.
테스트를 사용하여 빌드하면 googletest에 대한 종속성이 자동으로 해결됩니다.
적절한 기반 시스템의 좋은 출발점은 아마도 다음과 같습니다.
$ apt install
gcc
g++
clang
git
ccache
ninja-build
cmake
make
bison
flex
fuse3
pkg-config
binutils-dev
libacl1-dev
libarchive-dev
libbenchmark-dev
libboost-chrono-dev
libboost-context-dev
libboost-filesystem-dev
libboost-iostreams-dev
libboost-program-options-dev
libboost-regex-dev
libboost-system-dev
libboost-thread-dev
libbrotli-dev
libevent-dev
libhowardhinnant-date-dev
libjemalloc-dev
libdouble-conversion-dev
libiberty-dev
liblz4-dev
liblzma-dev
libzstd-dev
libxxhash-dev
libmagic-dev
libparallel-hashmap-dev
librange-v3-dev
libssl-dev
libunwind-dev
libdwarf-dev
libelf-dev
libfmt-dev
libfuse3-dev
libgoogle-glog-dev
libutfcpp-dev
libflac++-dev
nlohmann-json3-dev
gcc
로 빌드할 때 최적화 수준은 릴리스 빌드에 대해 CMake 기본값인 -O3
대신 -O2
로 설정됩니다. 최소한 gcc-10
까지의 버전에서는 -O3
빌드가 -O2
사용한 빌드보다 최대 70% 느립니다.
먼저 릴리스 아카이브의 압축을 풉니다.
$ tar xvf dwarfs-x.y.z.tar.xz
$ cd dwarfs-x.y.z
또는 git 리포지토리를 복제할 수도 있지만 이 경우에는 더 많은 종속성이 있으며 릴리스 아카이브에는 리포지토리에서 빌드할 때 생성해야 하는 대부분의 자동 생성 파일이 포함되어 있으므로 빌드가 더 오래 걸릴 수 있습니다.
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs
모든 종속성이 설치되면 다음을 사용하여 DwarFS를 빌드할 수 있습니다.
$ mkdir build
$ cd build
$ cmake .. -GNinja -DWITH_TESTS=ON
$ ninja
그런 다음 다음을 사용하여 테스트를 실행할 수 있습니다.
$ ctest -j
모든 바이너리는 기본적으로 jemalloc을 메모리 할당자로 사용합니다. 일반적으로 glibc
또는 tcmalloc
할당자에 비해 훨씬 적은 시스템 메모리를 사용하기 때문입니다. jemalloc
사용을 비활성화하려면 cmake
명령줄에서 -DUSE_JEMALLOC=0
전달합니다.
DwarFS 라이브러리, 도구, FUSE 드라이버를 독립적으로 빌드/설치하는 것도 가능합니다. 이는 DwarFS를 패키징할 때 가장 흥미롭습니다. 도구와 FUSE 드라이버를 사용하려면 라이브러리가 빌드되었거나 이미 설치되어 있어야 합니다. 라이브러리만 빌드하려면 다음을 사용하십시오.
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=ON -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=OFF
라이브러리가 테스트되고 설치되면 다음을 사용하여 도구(예: mkdwarfs
, dwarfsck
, dwarfsextract
)를 빌드할 수 있습니다.
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=ON -DWITH_FUSE_DRIVER=OFF
FUSE 드라이버를 빌드하려면 다음을 사용하십시오.
$ cmake .. -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF -DWITH_FUSE_DRIVER=ON
설치는 다음과 같이 쉽습니다.
$ sudo ninja install
하지만 놀기 위해 도구를 설치할 필요는 없습니다.
정적으로 연결된 바이너리를 구축하려는 시도는 권장되지 않으며 공식적으로 지원되지 않습니다. 즉, 정적 바이너리를 빌드 할 수 있는 환경을 설정하는 방법은 다음과 같습니다.
이것은 ubuntu-22.04-live-server-amd64.iso
로 테스트되었습니다. 먼저 위에 종속성으로 나열된 모든 패키지를 설치합니다. 또한 다음을 설치하십시오.
$ apt install ccache ninja libacl1-dev
ccache
와 ninja
선택사항이지만 빠른 컴파일에 도움이 됩니다.
배포판에 따라 일부 라이브러리(예: Ubuntu용 libarchive
및 libmagic
의 정적 버전을 빌드하고 설치해야 합니다.
$ wget https://github.com/libarchive/libarchive/releases/download/v3.6.2/libarchive-3.6.2.tar.xz
$ tar xf libarchive-3.6.2.tar.xz && cd libarchive-3.6.2
$ ./configure --prefix=/opt/static-libs --without-iconv --without-xml2 --without-expat
$ make && sudo make install
$ wget ftp://ftp.astron.com/pub/file/file-5.44.tar.gz
$ tar xf file-5.44.tar.gz && cd file-5.44
$ ./configure --prefix=/opt/static-libs --enable-static=yes --enable-shared=no
$ make && make install
그게 다야! 이제 DwarFS용 정적 바이너리를 빌드해 볼 수 있습니다.
$ git clone --recurse-submodules https://github.com/mhx/dwarfs
$ cd dwarfs && mkdir build && cd build
$ cmake .. -GNinja -DWITH_TESTS=ON -DSTATIC_BUILD_DO_NOT_USE=ON
-DSTATIC_BUILD_EXTRA_PREFIX=/opt/static-libs
$ ninja
$ ninja test
mkdwarfs, dwarfs, dwarfsck 및 dwarfsextract에 대한 매뉴얼 페이지를 확인하십시오. 각 바이너리에 대해 --man
옵션을 사용하여 매뉴얼 페이지에 액세스할 수도 있습니다. 예:
$ mkdwarfs --man
dwarfs 매뉴얼 페이지에는 읽기 전용 DwarFS 이미지 위에 쓰기 가능한 파일 시스템 마운트를 생성하기 위해 overlayfs로 DwarFS를 설정하는 예도 나와 있습니다.
DwarFS 파일 시스템 형식에 대한 설명은 dwarfs-format에서 찾을 수 있습니다.
mkdwarfs
의 내부 작동에 대한 높은 수준의 개요가 이 시퀀스 다이어그램에 표시됩니다.
CMake를 사용하여 프로젝트를 빌드하는 경우 DwarFS 라이브러리를 사용하는 것은 매우 간단합니다. 빠른 시작을 위해 라이브러리를 사용하여 DwarFS 이미지에 대한 정보(예: dwarfsck
)를 인쇄하거나 추출(예: dwarfsextract
)하는 예제 코드를 살펴보세요.
5개의 개별 라이브러리가 있습니다.
dwarfs_common
에는 다른 모든 라이브러리에 필요한 공통 코드가 포함되어 있습니다. 인터페이스는 dwarfs/
에 정의되어 있습니다.
dwarfs_reader
에는 DwarFS 이미지에서 데이터를 읽는 데 필요한 모든 코드가 포함되어 있습니다. 인터페이스는 dwarfs/reader/
에 정의되어 있습니다.
dwarfs_extractor
에는 libarchive
사용하여 DwarFS 이미지를 추출하는 데 필요한 ccode가 포함되어 있습니다. 인터페이스는 dwarfs/utility/filesystem_extractor.h
에 정의되어 있습니다.
dwarfs_writer
에는 DwarFS 이미지를 만드는 데 필요한 코드가 포함되어 있습니다. 인터페이스는 dwarfs/writer/
에 정의되어 있습니다.
dwarfs_rewrite
에는 DwarFS 이미지를 다시 작성하는 코드가 포함되어 있습니다. 인터페이스는 dwarfs/utility/rewrite_filesystem.h
에 정의되어 있습니다.
internal
하위 폴더의 헤더는 빌드 시에만 액세스할 수 있으며 설치되지 않습니다. tool
하위 폴더도 마찬가지입니다.
판독기 및 추출기 API는 상당히 안정적이어야 합니다. 작성자 API가 변경될 가능성이 높습니다. 그러나 이 프로젝트가 버전 1.0.0에 도달하기 전에는 API 안정성이 보장되지 않습니다.
Windows 운영 체제에 대한 지원은 현재 실험적입니다. 지난 20년 동안 Unix 세계에서만 거의 독점적으로 일했기 때문에 Windows 개발 경험이 다소 제한되어 있으며 Windows 코드에는 분명히 버그와 거친 부분이 있을 것으로 예상합니다.
DwarFS 파일 시스템 드라이버의 Windows 버전은 멋진 WinFsp 프로젝트에 의존하며 해당 winfsp-x64.dll
은 dwarfs.exe
드라이버에서 검색할 수 있어야 합니다.
Linux에서 사용하든 Windows에서 사용하든 다양한 도구는 거의 동일하게 작동해야 합니다. 파일 시스템 이미지는 Linux와 Windows 간에 복사할 수 있으며 한 OS에서 생성된 이미지는 다른 OS에서도 제대로 작동합니다.
하지만 지적할 만한 몇 가지 사항이 있습니다.
DwarFS는 Linux에서와 마찬가지로 Windows에서도 하드링크와 심볼릭 링크를 모두 지원합니다. 그러나 하드링크와 심볼릭 링크를 생성하려면 Windows에서 관리자 권한이 필요한 것 같습니다. 따라서 예를 들어 일종의 링크가 포함된 DwarFS 이미지를 추출하려는 경우 올바른 권한이 없으면 오류가 발생할 수 있습니다.
WinFsp의 문제로 인해 현재 심볼릭 링크는 마운트된 파일 시스템 외부를 가리킬 수 없습니다. 또한 WinFsp의 또 다른 문제로 인해 드라이브 문자가 포함된 심볼릭 링크는 잘못된 대상 경로와 함께 나타납니다.
Windows의 DwarFS 드라이버는 API를 통해 하드링크 수를 올바르게 보고하지만 현재 이러한 수는 Windows 파일 시스템 계층에 올바르게 전파되지 않습니다. 이는 아마도 WinFsp의 문제로 인한 것 같습니다.
Windows에서 DwarFS 이미지를 마운트하는 경우 마운트 지점이 존재하지 않아야 합니다. 이는 마운트 지점이 실제로 존재해야 하는 Linux와 다릅니다. 또한 DwarFS 이미지를 드라이브 문자로 마운트할 수도 있습니다. 예:
dwarfs.exe image.dwarfs Z:
mkdwarfs
의 필터 규칙에는 Windows 또는 Linux에서 실행되는지 여부에 관계없이 항상 Unix 경로 구분 기호가 필요합니다.
vcpkg 덕분에 Windows에서 구축하는 것은 그리 복잡하지 않습니다. 다음을 설치해야 합니다.
Visual Studio 및 MSVC C/C++ 컴파일러
힘내
CMake
닌자
WinFsp
WinFsp
C:Program Files (x86)WinFsp
에 설치될 것으로 예상됩니다. 그렇지 않은 경우 cmake/win.bat
를 통해 CMake를 실행할 때 WINFSP_PATH
설정해야 합니다.
이제 vcpkg
및 dwarfs
복제해야 합니다.
> cd %HOMEPATH%
> mkdir git
> cd git
> git clone https://github.com/Microsoft/vcpkg.git
> git clone https://github.com/mhx/dwarfs
그런 다음 부트스트랩 vcpkg
:
> .vcpkgbootstrap-vcpkg.bat
그리고 DwarFS를 빌드합니다.
> cd dwarfs
> mkdir build
> cd build
> ..cmakewin.bat
> ninja
완료되면 테스트를 실행할 수 있습니다. 컴퓨터의 CPU 코어 수에 따라 CTEST_PARALLEL_LEVEL
설정합니다.
> set CTEST_PARALLEL_LEVEL=10
> ninja test
이제 DwarFS 라이브러리 및 도구( mkdwarfs
, dwarfsck
, dwarfsextract
)를 Homebrew에서 사용할 수 있습니다.
$ brew install dwarfs
$ brew test dwarfs
DwarFS 파일 시스템 드라이버의 macOS 버전은 멋진 macFUSE 프로젝트에 의존합니다. 공식이 추가될 때까지 DwarFS FUSE 드라이버를 수동으로 빌드해야 합니다.
macOS에서 구축하는 것은 비교적 간단합니다.
홈브류 설치
Homebrew를 사용하여 필요한 종속성을 설치합니다.
$ brew install cmake ninja macfuse brotli howard-hinnant-date double-conversion
fmt glog libarchive libevent flac openssl nlohmann-json pkg-config
range-v3 utf8cpp xxhash boost zstd
macFUSE를 처음 설치하는 경우 시스템 환경설정 / 개인정보 보호 및 보안 에서 해당 소프트웨어를 명시적으로 허용해야 합니다. 이 후에 재부팅해야 할 가능성이 높습니다.
릴리스 페이지에서 릴리스 타르볼을 다운로드하고 추출합니다.
$ wget https://github.com/mhx/dwarfs/releases/download/v0.10.0/dwarfs-0.10.0.tar.xz
$ tar xf dwarfs-0.10.0.tar.xz
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON
$ cmake --build dwarfs-build
$ ctest --test-dir dwarfs-build -j
brew install
에서 macfuse
생략하고 위의 첫 번째 cmake
명령 대신 다음을 사용할 수 있습니다. $ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_FUSE_DRIVER=OFF
$ cmake --fresh -B dwarfs-build -S dwarfs-0.10.0 -GNinja -DWITH_TESTS=ON -DWITH_LIBDWARFS=OFF -DWITH_TOOLS=OFF
$ sudo cmake --install dwarfs-build
그게 다야!
천체 사진은 엄청난 양의 원시 이미지 데이터를 생성할 수 있습니다. 하룻밤 동안에는 수십 기가바이트의 데이터가 쌓일 가능성이 높습니다. 대부분의 천체 사진 전용 카메라에서 이 데이터는 결국 FITS 이미지 형식으로 나타납니다. 이는 일반적으로 압축되지 않고 표준 압축 알고리즘으로 잘 압축되지 않으며 특정 압축된 FITS 형식이 있지만 널리 지원되지는 않습니다.
압축 형식 중 하나(간단히 "Rice"라고 함)는 상당히 잘 압축되고 속도가 매우 빠릅니다. 그러나 압축 FITS 구현에는 몇 가지 단점이 있습니다. 가장 심각한 단점은 컬러 센서와 해상도가 16비트 미만인 센서만큼 압축이 좋지 않다는 것입니다.
DwarFS는 Rice 압축의 기본 아이디어를 기반으로 하는 ricepp
(Rice++) 압축을 지원하지만 몇 가지 개선 사항이 있습니다. 즉, 색상 및 낮은 비트 심도 이미지를 훨씬 더 효과적으로 압축하고 휴리스틱에 의존하는 대신 압축 중에 항상 최적의 솔루션을 검색합니다. .
ASI1600MM 카메라로 촬영한 129개의 이미지(어두운 부분, 플랫한 부분, 밝은 부분)를 사용한 예를 살펴보겠습니다. 각 이미지는 32MiB이므로 총 데이터 용량은 4GiB입니다. 표준 fpack
도구를 사용하여 이를 압축하는 데 약 16.6초가 걸리며 총 출력 크기는 2.2GiB입니다.
$ time fpack */*.fit */*/*.fit
user 14.992
system 1.592
total 16.616
$ find . -name '*.fz' -print0 | xargs -0 cat | wc -c
2369943360
그러나 이로 인해 모든 응용 프로그램이 실제로 읽을 수 있는 *.fz
파일이 남게 됩니다.
DwarFS를 사용하면 다음과 같은 결과를 얻을 수 있습니다.
$ mkdwarfs -i ASI1600 -o asi1600-20.dwarfs -S 20 --categorize
I 08:47:47.459077 scanning "ASI1600"
I 08:47:47.491492 assigning directory and link inodes...
I 08:47:47.491560 waiting for background scanners...
I 08:47:47.675241 scanning CPU time: 1.051s
I 08:47:47.675271 finalizing file inodes...
I 08:47:47.675330 saved 0 B / 3.941 GiB in 0/258 duplicate files
I 08:47:47.675360 assigning device inodes...
I 08:47:47.675371 assigning pipe/socket inodes...
I 08:47:47.675381 building metadata...
I 08:47:47.675393 building blocks...
I 08:47:47.675398 saving names and symlinks...
I 08:47:47.675514 updating name and link indices...
I 08:47:47.675796 waiting for segmenting/blockifying to finish...
I 08:47:50.274285 total ordering CPU time: 616.3us
I 08:47:50.274329 total segmenting CPU time: 1.132s
I 08:47:50.279476 saving chunks...
I 08:47:50.279622 saving directories...
I 08:47:50.279674 saving shared files table...
I 08:47:50.280745 saving names table... [1.047ms]
I 08:47:50.280768 saving symlinks table... [743ns]
I 08:47:50.282031 waiting for compression to finish...
I 08:47:50.823924 compressed 3.941 GiB to 1.201 GiB (ratio=0.304825)
I 08:47:50.824280 compression CPU time: 17.92s
I 08:47:50.824316 filesystem created without errors [3.366s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
5 dirs, 0/0 soft/hard links, 258/258 files, 0 other
original size: 3.941 GiB, hashed: 315.4 KiB (18 files, 0 B/s)
scanned: 3.941 GiB (258 files, 117.1 GiB/s), categorizing: 0 B/s
saved by deduplication: 0 B (0 files), saved by segmenting: 0 B
filesystem: 3.941 GiB in 4037 blocks (4550 chunks, 516/516 fragments, 258 inodes)
compressed filesystem: 4037 blocks/1.201 GiB written
3.4초 이내에 데이터를 fpack
출력 크기의 거의 절반인 1.2GiB로 압축합니다.
많은 디스크 공간을 절약하는 것 외에도 데이터를 NAS에 저장할 때 유용할 수 있습니다. 다음은 먼저 압축되지 않은 원시 데이터를 사용하여 1Gb/s 네트워크 연결을 통해 액세스된 동일한 데이터 세트를 비교한 것입니다.
find /mnt/ASI1600 -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 36.0455 s, 117 MB/s
다음으로 동일한 공유에서 DwarFS 이미지를 사용합니다.
$ dwarfs /mnt/asi1600-20.dwarfs mnt
$ find mnt -name '*.fit' -print0 | xargs -0 -P4 -n1 cat | dd of=/dev/null status=progress
4229012160 bytes (4.2 GB, 3.9 GiB) copied, 14.3681 s, 294 MB/s
약 2.5배 빠른 속도입니다. 느린 외장 하드 드라이브에서도 비슷한 결과를 볼 수 있습니다.
현재 DwarFS에는 파일 시스템 이미지에 복구 정보를 추가하는 기능이 내장되어 있지 않습니다. 그러나 보관 목적으로 손상된 이미지를 복구할 수 있도록 이러한 복구 정보를 가지고 있는 것이 좋습니다.
다행히 par2cmdline과 같은 것을 사용하면 비교적 간단합니다.
$ par2create -n1 asi1600-20.dwarfs
DwarFS가 파일 시스템 이미지에서 문제를 감지한 경우에만 필요하므로 이미지 옆(또는 다른 저장소)에 배치할 수 있는 두 개의 추가 파일이 생성됩니다. 문제가 있으면 실행할 수 있습니다
$ par2repair asi1600-20.dwarfs
이미지의 5%( par2create
에서 사용하는 기본값) 미만이 손상된 경우 이미지를 복구할 수 있을 가능성이 높습니다.
확장된 속성은 현재 지원되지 않습니다. mkdwarfs
사용하여 DwarFS 이미지를 빌드할 때 소스 파일 시스템에 저장된 모든 확장 속성은 현재 유지되지 않습니다.
즉, 마운트된 DwarFS 이미지의 루트 inode는 현재 Linux에서 하나 또는 두 개의 확장 속성을 노출합니다.
$ attr -l mnt
Attribute "dwarfs.driver.pid" has a 4 byte value for mnt
Attribute "dwarfs.driver.perfmon" has a 4849 byte value for mnt
dwarfs.driver.pid
속성은 단순히 DwarFS FUSE 드라이버의 PID를 포함합니다. dwarfs.driver.perfmon
속성에는 성능 모니터의 현재 결과가 포함되어 있습니다.
또한 각 일반 파일은 기본 inode에 대한 정보와 함께 dwarfs.inodeinfo
속성을 노출합니다.
$ attr -l "05 Disappear.caf"
Attribute "dwarfs.inodeinfo" has a 448 byte value for 05 Disappear.caf
속성에는 기본 inode에 대한 정보가 포함된 JSON 개체가 포함되어 있습니다.
$ attr -qg dwarfs.inodeinfo "05 Disappear.caf"
{
"chunks": [
{
"block": 2,
"category": "pcmaudio/metadata",
"offset": 270976,
"size": 4096
},
{
"block": 414,
"category": "pcmaudio/waveform",
"offset": 37594368,
"size": 29514492
},
{
"block": 419,
"category": "pcmaudio/waveform",
"offset": 0,
"size": 29385468
}
],
"gid": 100,
"mode": 33188,
"modestring": "----rw-r--r--",
"uid": 1000
}
예를 들어, 이는 특정 파일이 여러 블록에 어떻게 분산되어 있는지 또는 파일에 어떤 범주가 할당되었는지 확인하는 데 유용합니다.
SquashFS, xz
, lrzip
, zpaq
및 wimlib
테스트는 모두 64GiB RAM을 갖춘 8코어 Intel(R) Xeon(R) E-2286M CPU @ 2.40GHz에서 수행되었습니다.
Cromfs 테스트는 64GiB RAM을 갖춘 6코어 Intel(R) Xeon(R) CPU D-1528 @ 1.90GHz에서 이전 버전의 DwarFS를 사용하여 수행되었습니다.
EROFS 테스트는 64GiB RAM을 갖춘 Intel(R) Core(TM) i9-13900K에서 DwarFS v0.9.8 및 EROFS v1.7.1을 사용하여 수행되었습니다.
모든 테스트 동안 시스템은 대부분 유휴 상태였습니다.
소스 디렉토리에는 284개 개별 릴리스의 1139개 Perl 설치가 포함되어 있으며 1,927,501개 파일과 330,733개 디렉토리에 총 47.65GiB의 데이터가 포함되어 있습니다. 소스 디렉토리는 tar 아카이브에서 970 EVO Plus 2TB NVME 드라이브의 XFS 파티션으로 새로 압축이 풀렸으므로 해당 내용의 대부분이 캐시되었을 가능성이 높습니다.
나는 DwarFS의 기본 설정인 SquashFS에 대해 동일한 압축 유형 및 압축 수준을 사용하고 있습니다.
$ time mksquashfs install perl-install.squashfs -comp zstd -Xcompression-level 22
Parallel mksquashfs: Using 16 processors
Creating 4.0 filesystem on perl-install-zstd.squashfs, block size 131072.
[=========================================================/] 2107401/2107401 100%
Exportable Squashfs 4.0 filesystem, zstd compressed, data block size 131072
compressed data, compressed metadata, compressed fragments,
compressed xattrs, compressed ids
duplicates are removed
Filesystem size 4637597.63 Kbytes (4528.90 Mbytes)
9.29% of uncompressed filesystem size (49922299.04 Kbytes)
Inode table size 19100802 bytes (18653.13 Kbytes)
26.06% of uncompressed inode table size (73307702 bytes)
Directory table size 19128340 bytes (18680.02 Kbytes)
46.28% of uncompressed directory table size (41335540 bytes)
Number of duplicate files found 1780387
Number of inodes 2255794
Number of files 1925061
Number of fragments 28713
Number of symbolic links 0
Number of device nodes 0
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 330733
Number of ids (unique uids + gids) 2
Number of uids 1
mhx (1000)
Number of gids 1
users (100)
real 32m54.713s
user 501m46.382s
sys 0m58.528s
DwarFS의 경우 기본값을 고수합니다.
$ time mkdwarfs -i install -o perl-install.dwarfs
I 11:33:33.310931 scanning install
I 11:33:39.026712 waiting for background scanners...
I 11:33:50.681305 assigning directory and link inodes...
I 11:33:50.888441 finding duplicate files...
I 11:34:01.120800 saved 28.2 GiB / 47.65 GiB in 1782826/1927501 duplicate files
I 11:34:01.122608 waiting for inode scanners...
I 11:34:12.839065 assigning device inodes...
I 11:34:12.875520 assigning pipe/socket inodes...
I 11:34:12.910431 building metadata...
I 11:34:12.910524 building blocks...
I 11:34:12.910594 saving names and links...
I 11:34:12.910691 bloom filter size: 32 KiB
I 11:34:12.910760 ordering 144675 inodes using nilsimsa similarity...
I 11:34:12.915555 nilsimsa: depth=20000 (1000), limit=255
I 11:34:13.052525 updating name and link indices...
I 11:34:13.276233 pre-sorted index (660176 name, 366179 path lookups) [360.6ms]
I 11:35:44.039375 144675 inodes ordered [91.13s]
I 11:35:44.041427 waiting for segmenting/blockifying to finish...
I 11:37:38.823902 bloom filter reject rate: 96.017% (TPR=0.244%, lookups=4740563665)
I 11:37:38.823963 segmentation matches: good=454708, bad=6819, total=464247
I 11:37:38.824005 segmentation collisions: L1=0.008%, L2=0.000% [2233254 hashes]
I 11:37:38.824038 saving chunks...
I 11:37:38.860939 saving directories...
I 11:37:41.318747 waiting for compression to finish...
I 11:38:56.046809 compressed 47.65 GiB to 430.9 MiB (ratio=0.00883101)
I 11:38:56.304922 filesystem created without errors [323s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
waiting for block compression to finish
330733 dirs, 0/2440 soft/hard links, 1927501/1927501 files, 0 other
original size: 47.65 GiB, dedupe: 28.2 GiB (1782826 files), segment: 15.19 GiB
filesystem: 4.261 GiB in 273 blocks (319178 chunks, 144675/144675 inodes)
compressed filesystem: 273 blocks/430.9 MiB written [depth: 20000]
█████████████████████████████████████████████████████████████████████████████▏100% |
real 5m23.030s
user 78m7.554s
sys 1m47.968s
따라서 이 비교에서 mkdwarfs
CPU 시간과 벽시계 시간 측면에서 모두 mksquashfs
보다 6배 이상 빠릅니다 .
$ ll perl-install.*fs
-rw-r--r-- 1 mhx users 447230618 Mar 3 20:28 perl-install.dwarfs
-rw-r--r-- 1 mhx users 4748902400 Mar 3 20:10 perl-install.squashfs
압축률 측면에서 DwarFS 파일 시스템은 SquashFS 파일 시스템보다 10배 이상 작습니다 . DwarFS를 사용하면 콘텐츠가 원래 크기의 0.9%(!) 미만으로 압축 되었습니다. 이 압축 비율은 사용된 실제 디스크 공간이 아닌 개별 파일에 저장된 데이터만 고려합니다. du
에 따르면 원래 XFS 파일 시스템에서 소스 폴더는 52 GiB를 사용하므로 DwarFS 이미지는 실제로 원래 공간의 0.8%만 사용합니다 .
다음은 zstd
대신 lzma
압축을 사용한 또 다른 비교입니다.
$ time mksquashfs install perl-install-lzma.squashfs -comp lzma
real 13m42.825s
user 205m40.851s
sys 3m29.088s
$ time mkdwarfs -i install -o perl-install-lzma.dwarfs -l9
real 3m43.937s
user 49m45.295s
sys 1m44.550s
$ ll perl-install-lzma.*fs
-rw-r--r-- 1 mhx users 315482627 Mar 3 21:23 perl-install-lzma.dwarfs
-rw-r--r-- 1 mhx users 3838406656 Mar 3 20:50 perl-install-lzma.squashfs
실행 속도가 훨씬 빨라지고 결과 이미지가 훨씬 작아진다는 사실이 즉시 명백해집니다. 그럼에도 불구하고 mkdwarfs
SquashFS 이미지보다 약 4배 더 빠르며 12배 더 작은 이미지를 생성합니다. DwarFS 이미지는 원본 파일 크기의 0.6%에 불과합니다.
그렇다면 기본적으로 zstd
대신 lzma
사용하는 것은 어떨까요? 그 이유는 lzma
가 zstd
보다 압축 해제 속도가 약 10배 느리기 때문입니다. 가끔 압축된 파일 시스템의 데이터에만 액세스하는 경우에는 큰 문제가 아닐 수 있지만 광범위하게 사용하면 zstd
의 성능이 향상됩니다.
위의 비교는 완전히 공평하지 않습니다. mksquashfs
기본적으로 128KiB의 블록 크기를 사용하는 반면, mkdwarfs
기본적으로 16MiB 블록을 사용하거나 -l9
를 사용하면 64MiB 블록도 사용합니다. 두 파일 시스템에 동일한 블록 크기를 사용하면 예상대로 그 차이가 훨씬 덜 극명해집니다.
$ time mksquashfs install perl-install-lzma-1M.squashfs -comp lzma -b 1M
real 15m43.319s
user 139m24.533s
sys 0m45.132s
$ time mkdwarfs -i install -o perl-install-lzma-1M.dwarfs -l9 -S20 -B3
real 4m25.973s
user 52m15.100s
sys 7m41.889s
$ ll perl-install*.*fs
-rw-r--r-- 1 mhx users 935953866 Mar 13 12:12 perl-install-lzma-1M.dwarfs
-rw-r--r-- 1 mhx users 3407474688 Mar 3 21:54 perl-install-lzma-1M.squashfs
심지어 DwarFS가 최대 2개의 이전 파일 시스템 블록에서 파일 청크를 참조할 수 있도록 하는 기능( -B3
)을 사용하기 때문에 여전히 완전히 공평하지는 않습니다.
그러나 요점은 더 큰 블록 크기나 역참조를 지원하지 않기 때문에 이것이 실제로 SquashFS가 가장 뛰어난 부분이라는 것입니다. 아래에서 볼 수 있듯이 DwarFS가 기본적으로 사용하는 더 큰 블록이 반드시 성능에 부정적인 영향을 미치는 것은 아닙니다.
DwarFS에는 다른 압축 알고리즘을 사용하여 기존 파일 시스템을 다시 압축하는 옵션도 있습니다. 이는 파일 시스템을 완전히 재구축하지 않고도 다양한 알고리즘과 옵션을 비교적 빠르게 실험할 수 있으므로 유용할 수 있습니다. 예를 들어, 위의 파일 시스템을 가능한 최상의 압축( -l 9
)으로 다시 압축합니다.
$ time mkdwarfs --recompress -i perl-install.dwarfs -o perl-lzma-re.dwarfs -l9
I 20:28:03.246534 filesystem rewrittenwithout errors [148.3s]
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
filesystem: 4.261 GiB in 273 blocks (0 chunks, 0 inodes)
compressed filesystem: 273/273 blocks/372.7 MiB written
████████████████████████████████████████████████████████████████████▏100%
real 2m28.279s
user 37m8.825s
sys 0m43.256s