zfsの圧縮オプションの違いによる圧縮率、計算速度の違いを測定

zfsにはファイルシステムの機能として圧縮の機能があります。ファイルの種類に応じて自動的に圧縮がかかるため、特に意識すること無くxfs, ext4より多くのデータを保存することが可能になります。

圧縮機能をONにするとデフォルトではlz4のアルゴリズムが使われますが、他にもgzip(gzip-1〜gzip-9)、lzjb、zleなども選択することができます。
今回は、圧縮率の違いとアプリケーション実行時における速度の違いを見てみたいと思います。

環境

OS : CentOS7.5 (kernel: 3.10.0-862.9.1.el7.x86_64)
CPU : Xeon Gold 6134 (8core, 3.2GHz) x2
Memory : 64GB
Disk : NVMe P4500 4TB x1
zfs : version 0.7.9

圧縮アルゴリズム

下記6種類のアルゴリズムに圧縮無しを加えた7つのケースについて比較を行いました。

lz4(default)
gzip-1
gzip-6
gzip-9
lzjb
zle

zfsの作成

# zfs create NVMe/db
# zfs create NVMe/lz4 -o compress=on
# zfs create NVMe/gzip-1 -o compuress=gzip-1
# zfs create NVMe/gzip-6 -o compress=gzip   ## gzipとした時のデフォルトがgzip-6のため
# zfs create NVMe/gzip-9 -o compress=gzip-9
# zfs create NVMe/lzjb -o compress=lzjb
# zfs create NVMe/zle -o compress=zle

圧縮率の比較

NCBI ntデータベース

まずは、NCBIのntデータベースで比較してみたいと思います。
ファイルサイズの合計は、NVMe/db(圧縮OFF)の通り21GBです。
それぞれの圧縮アルゴリズムによってUSEDのサイズが変わっていることがわかります。

# zfs list
NAME          USED  AVAIL  REFER  MOUNTPOINT
NVMe/db      21.0G  3.40T  21.0G  /NVMe/db
NVMe/gzip-1  14.0G  3.40T  14.0G  /NVMe/gzip-1
NVMe/gzip-6  13.8G  3.40T  13.8G  /NVMe/gzip-6
NVMe/gzip-9  13.8G  3.40T  13.8G  /NVMe/gzip-9
NVMe/lz4     14.9G  3.40T  14.9G  /NVMe/lz4
NVMe/lzjb    16.2G  3.40T  16.2G  /NVMe/lzjb
NVMe/zle     21.0G  3.40T  21.0G  /NVMe/zle

zfsのコマンドで圧縮率も取得できます。
gzip-Xの圧縮率が高く、次いでlz4, lzjbと続きますが、zleは何も圧縮されていません。

# zfs get compressratio -o name,value
NAME                                             VALUE
NVMe/db                                          1.00x
NVMe/gzip-1                                      1.49x
NVMe/gzip-6                                      1.51x
NVMe/gzip-9                                      1.52x
NVMe/lz4                                         1.41x
NVMe/lzjb                                        1.29x
NVMe/zle                                         1.00x

fastqファイル

次にfastqファイル(text形式)について比較を行いました。
比較に使用したfastqファイルは8.6GBのDRR081404.fastqです。

# ls -sh DRR081404.fastq 
8.6G DRR081404.fastq

上で作ったそれぞれのzfsの下にfastqという名前を付け加えたzfsを作成し、
そこにDRR081404.fastqをコピーします。

# zfs get compress -t filesystem |grep -e NAME -e fastq
NAME               PROPERTY     VALUE     SOURCE
NVMe/db/fastq      compression  off       default
NVMe/gzip-1/fastq  compression  gzip-1    inherited from NVMe/gzip-1
NVMe/gzip-6/fastq  compression  gzip      inherited from NVMe/gzip-6
NVMe/gzip-9/fastq  compression  gzip-9    inherited from NVMe/gzip-9
NVMe/lz4/fastq     compression  lz4       inherited from NVMe/lz4
NVMe/lzjb/fastq    compression  lzjb      inherited from NVMe/lzjb
NVMe/zle/fastq     compression  zle       inherited from NVMe/zle

コピー後のUSED使用量と圧縮率は以下の通りとなりました。
ntと比較すると全体的に圧縮率は上がっていますが(zleは除く)、gzip-X勢の伸びが顕著でした。
圧縮率だけを考えた場合、gzip-6,gzip-9に設定するのが良さそうです。

# zfs list |grep -e NAME -e fastq
NAME                USED  AVAIL  REFER  MOUNTPOINT
NVMe/db/fastq      8.57G  3.24T  8.57G  /NVMe/db/fastq
NVMe/gzip-1/fastq  3.77G  3.24T  3.77G  /NVMe/gzip-1/fastq
NVMe/gzip-6/fastq  3.46G  3.24T  3.46G  /NVMe/gzip-6/fastq
NVMe/gzip-9/fastq  3.43G  3.24T  3.43G  /NVMe/gzip-9/fastq
NVMe/lz4/fastq     5.66G  3.24T  5.66G  /NVMe/lz4/fastq
NVMe/lzjb/fastq    5.87G  3.24T  5.87G  /NVMe/lzjb/fastq
NVMe/zle/fastq     8.57G  3.24T  8.57G  /NVMe/zle/fastq

# zfs get compressratio -o name,value |grep -e NAME -e fastq
NAME                                                VALUE
NVMe/db/fastq                                       1.00x
NVMe/gzip-1/fastq                                   2.27x
NVMe/gzip-6/fastq                                   2.48x
NVMe/gzip-9/fastq                                   2.49x
NVMe/lz4/fastq                                      1.51x
NVMe/lzjb/fastq                                     1.45x
NVMe/zle/fastq                                      1.00x

アプリケーションの動作比較 

次にアプリケーションで実行速度の比較を行います。
以下のようなスクリプトを実行し、それぞれの圧縮アルゴリズム毎の実行時間の比較を行います。
fastq-dumpとbwaのindexはシングルスレッド、bwa memとsamtoolsは全16コアを使ったマルチスレッドオプションで実行しました。

[スクリプト抜粋]

#!/bin/bash

NP=`nproc`

## fastq-dump
spack load sra-toolkit
fastq-dump DRR081404.sra

## bwa index
spack load bwa
bwa index -a bwtsw -p chr1_index chr1.fa

## bwa mem
bwa mem -t ${NP} chr1_index DRR081404.fastq > DRR081404.sam

## samtools sam2bam
spack load samtools
samtools sort -@ ${NP} -O bam -o DRR081404.bam DRR081404.sam

実行時間比較(単位=秒)

Compress=off lz4(default) gzip-1 gzip-6 gzip-9 lzjb zle
fastq-dump (1thr) 97.84 95.73 95.56 95.79 93.44 97.14 97.18
bwa index (1thr) 210.41 210.9 215.64 214.71 236.12 224.54 221.92
bwa mem (16thr) 495.9 499.37 517.31 554.25 589.41 503.69 496.11
samtools sam2bam (16thr) 59.36 64.02 101.31 102.37 102.63 81.42 60.06

グラフ (compress=off を1.00として比較)

Single Threadで実行したfastq-dump, bwa indexの場合には性能上の大きなペナルティはありませんでしたが、
全コア計算に使用したbwa memとsamtoolsのsam2bamではCPUリソースの競合により性能上のペナルティが大きくなりました。
特にsamtoolsを実行したケースのgzipではその傾向が顕著に表れています。
上の圧縮率も含めて考えると、lz4のバランスの良さが際立っており、これがデフォルト設定になっているというのも納得できます。

まとめ

上記の結果を考えると
一般的なファイルサーバーやヘッドノードではデフォルト通りのlz4を、バックアップ専用のサーバーなどにはgzip-6, gzip-9を、というのが良い選択なのではないかと思います。

また、今回は触れませんでしたがzfsには重複排除(dedup)の機能もあり、x3からx4程度の重複排除が可能です。
圧縮機能と併用することでディスク占有率をかなり抑えることができるのですが、重複排除には膨大なメモリ容量が必要となるため実際にONにするケースは少ないですしお薦めもできないといった難点があります。

その他、現行のXeonの一部のチップセットにはQAT(Quick Assist Technology)という暗号化や圧縮を専用にて行うチップが載っているものがあります。
zfs on linuxも0.7以降でQATに対応しているため、CPUリソースを消費すること無く圧縮を利用できるようになることが期待できます。