zstdコマンドの使い方|圧縮・解凍からtar.zst・gzip比較まで

コマンドリファレンス

zstd(Zstandard)は、Meta(旧 Facebook)の Yann Collet 氏が開発した可逆圧縮ツールです。gzip と同等以上の圧縮率を保ちながら、解凍が圧倒的に速いのが最大の特徴で、RFC 8878 として標準化されています。

この記事では基本的な使い方に加えて、実際に 73MiB のアクセスログを gzip / xz / bzip2 と圧縮し比べた実測値と、公式ドキュメントに書かれていない「ハマりどころ」を、すべて手元の Ubuntu 24.04 + zstd 1.5.5 で検証した結果として掲載します。

  1. 構文(Syntax)
  2. 「zstd: command not found」と表示されるときのインストール方法
    1. Debian / Ubuntu 系
    2. RHEL / CentOS 系
    3. Fedora / RHEL 8 以降
  3. zstd コマンドの主なオプション
  4. 実行例(圧縮)
    1. ファイルを圧縮する
    2. 圧縮レベルを指定する
    3. 圧縮後に元ファイルを削除する
    4. 出力先ファイル名を指定する
    5. パイプで受け取って圧縮する
  5. 実行例(解凍)
    1. 解凍する
    2. 解凍せずに中身を見る
    3. 中身の情報を確認する
    4. 壊れていないか検証する
  6. 実測:gzip / xz / bzip2 と比べてどれくらい速いのか
  7. -T0 で全コアを使う(マルチスレッド圧縮)
  8. tar と組み合わせて .tar.zst を作る
    1. 圧縮する(GNU tar 1.31 以降)
    2. 展開する
    3. 圧縮レベルやスレッド数を指定する
    4. 古い tar で .tar.zst を展開する
  9. 実務レシピ:logrotate で zstd 圧縮する
  10. つまずきポイントと対処
    1. 1. gzip と違い、元ファイルが消えない
    2. 2. -22 を指定しても、–ultra がないと黙ってレベル19になる
    3. 3. cron で実行すると「already exists」で止まる
    4. 4. zstd -l で元のサイズが空欄になる
    5. 5. –long を付けても必ず縮むわけではない
  11. .gz / .zst / .xz / .zip の違い
  12. よくある質問(FAQ)
    1. Q. 圧縮レベルはいくつにすればよいですか?
    2. Q. gzip から zstd に乗り換えて大丈夫ですか?
    3. Q. pzstd と zstd -T0 はどちらを使うべきですか?
    4. Q. 圧縮したまま中身を検索できますか?
    5. Q. 解凍したデータが元と同じか確認できますか?
  13. 関連コマンド
  14. 備考
  15. 参考
  16. 関連記事

構文(Syntax)

zstd [オプション] ファイル名          # 圧縮(file → file.zst)
zstd -d [オプション] ファイル名.zst   # 解凍(file.zst → file)
unzstd ファイル名.zst                # 解凍(zstd -d と同じ)
zstdcat ファイル名.zst               # 解凍せず標準出力に表示

「zstd: command not found」と表示されるときのインストール方法

最近のディストリビューションでは標準で入っていることが多いですが、入っていない場合は以下でインストールします。

Debian / Ubuntu 系

sudo apt update
sudo apt install -y zstd

RHEL / CentOS 系

sudo yum install -y zstd

Fedora / RHEL 8 以降

sudo dnf install -y zstd

インストールできたかは zstd --version で確認します。

$ zstd --version
*** Zstandard CLI (64-bit) v1.5.5, by Yann Collet ***

Ubuntu / Debian の zstd パッケージには、マルチスレッド版の pzstd、解凍用の unzstd、閲覧用の zstdcat、検索用の zstdgrep も同梱されます。

zstd コマンドの主なオプション

オプション説明使用例
-d解凍するzstd -d access.log.zst
-1-19圧縮レベル(既定は -3zstd -10 access.log
--ultra -20-22超高圧縮モード(--ultra が必須)zstd --ultra -22 access.log
-T Nスレッド数を指定(-T0 で全コア)zstd -19 -T0 access.log
-k元ファイルを残す(既定でオンzstd -k access.log
--rm圧縮成功後に元ファイルを削除zstd --rm access.log
-o FILE出力先ファイル名を指定zstd access.log -o backup.zst
-c標準出力へ書き出す(パイプ用)zstd -c access.log > a.zst
-f確認なしで上書きzstd -f access.log
-t圧縮ファイルの整合性を検証zstd -t backup.tar.zst
-l中身の情報を表示(解凍しない)zstd -l backup.tar.zst
--adaptI/O 速度に応じてレベルを自動調整zstd --adapt -T0 -c big.log > a.zst
-q進捗表示を抑制(cron 向け)zstd -q access.log

実行例(圧縮)

ファイルを圧縮する

zstd access.log

access.log.zst が作られます。gzip と違い、元の access.log はそのまま残ります。この違いは後述の「つまずきポイント」で詳しく説明します。

圧縮レベルを指定する

zstd -10 access.log          # 既定(-3)より高圧縮
zstd -19 -T0 access.log      # 最高圧縮+全コア使用
zstd --ultra -22 access.log  # 20以上は --ultra が必要

圧縮後に元ファイルを削除する

zstd --rm access.log

出力先ファイル名を指定する

zstd access.log -o /backup/access-20260815.zst

パイプで受け取って圧縮する

mysqldump -u root -p mydb | zstd -19 -T0 > mydb.sql.zst

ダンプを一時ファイルに落とさず直接圧縮できるため、ディスクの空きが少ないサーバーで有効です。詳しくは mysqldump コマンドの記事も参考にしてください。

実行例(解凍)

解凍する

zstd -d access.log.zst
# または
unzstd access.log.zst

実行すると、拡張子 .zst を取り除いた access.log が復元されます。

$ zstd -d small.log.zst
small.log.zst       : 200000 bytes

解凍せずに中身を見る

zstdcat access.log.zst | less
zstdcat access.log.zst | tail -100
zstdgrep ' 500 ' access.log.zst    # 圧縮したまま grep できる

圧縮したログをディスクに展開せず調査できるので、容量が逼迫しているサーバーで重宝します。

中身の情報を確認する

$ zstd -l small.log.zst
Frames  Skips  Compressed  Uncompressed  Ratio  Check  Filename
     1      0    18.7 KiB       195 KiB  10.457  XXH64  small.log.zst

壊れていないか検証する

$ zstd -t backup.tar.zst
backup.tar.zst      : 77199360 bytes
$ echo $?
0

zstd は XXH64 チェックサムを内蔵しているため、破損を確実に検出できます。実際に圧縮ファイルの途中 4 バイトを書き換えて試すと、次のように終了ステータス 1 で失敗します。

$ zstd -t broken.zst
broken.zst : Decoding error (36) : Data corruption detected
$ echo $?
1

終了ステータスで判定できるので、バックアップスクリプトに検証ステップを組み込めます。

if zstd -q -t backup.tar.zst; then
  echo "バックアップは正常です"
else
  echo "バックアップが破損しています" >&2
  exit 1
fi

実測:gzip / xz / bzip2 と比べてどれくらい速いのか

「zstd は速い」とよく言われますが、実際の差を確かめるため、Nginx 形式のアクセスログ 73.42MiB(40 万行)を各ツールで圧縮・解凍して計測しました。

検証環境: Ubuntu 24.04.4 LTS / 6 コア / zstd 1.5.5 / gzip・xz・bzip2 はディストリ標準版。時間は /usr/bin/time による実時間、いずれも 1 スレッド(-T0 なし)での測定です。

コマンド圧縮時間解凍時間圧縮後サイズ圧縮率
zstd -10.13 秒0.05 秒6.44 MiB11.4 倍
zstd -3(既定)0.17 秒0.05 秒6.29 MiB11.7 倍
gzip -6(既定)0.87 秒0.26 秒6.09 MiB12.1 倍
gzip -91.66 秒0.26 秒5.76 MiB12.7 倍
zstd -101.56 秒0.04 秒5.00 MiB14.7 倍
bzip2 -913.94 秒1.57 秒3.28 MiB22.4 倍
xz -618.82 秒0.25 秒4.45 MiB16.5 倍
zstd -1955.94 秒0.05 秒4.33 MiB17.0 倍

この結果から読み取れることを整理します。

  • 解凍速度は zstd が圧倒的。レベルに関係なく約 0.05 秒で、gzip の 0.26 秒に対して約 5 倍速くbzip2 の 1.57 秒に対しては約 30 倍速い結果でした。「1 回圧縮して何度も読む」ログやバックアップでは、この差がそのまま作業時間の差になります。
  • zstd -10gzip -9 の上位互換に近い。圧縮時間はほぼ同じ(1.56 秒 対 1.66 秒)で、サイズは 5.00MiB 対 5.76MiB と zstd の方が小さく、解凍は 6 倍以上速いという結果です。gzip -9 を使っている場面は zstd -10 に置き換えて損がありません。
  • 既定値どうし(zstd -3gzip -6)ならサイズはほぼ互角で、速度だけが 5 倍違う。サイズは 6.29MiB 対 6.09MiB とわずかに gzip 有利ですが、圧縮時間は 0.17 秒 対 0.87 秒です。
  • zstd -19xz -6 より小さく、解凍は 5 倍速い。ただし圧縮に 55.94 秒かかり xz -6 の 3 倍です。後述の -T0 を付けると 25.89 秒まで縮みます。
  • 圧縮率だけを見れば bzip2 が最も小さい。今回のような繰り返しの多い構造化テキストでは bzip2 のアルゴリズム(BWT)が有利に働きます。zstd は「最小サイズ」ではなく「速度と圧縮率のバランス」で選ぶツールだと理解しておくと判断を誤りません。

なお、圧縮率はデータの性質で大きく変わります。上の数値はログのような繰り返しの多いテキストでの結果であり、JPEG や MP4 のような圧縮済みファイルではどのツールもほとんど縮みません。手元のデータで判断したい場合は zstd -b(内蔵ベンチマーク)が使えます。

zstd -b1 -e19 access.log    # レベル1〜19を自動で計測

-T0 で全コアを使う(マルチスレッド圧縮)

zstd は圧縮のマルチスレッド化に対応しており、-T0 を付けるだけで利用可能な全コアを使います。同じ 73.42MiB のログを 6 コアで計測した結果が以下です。

コマンド圧縮時間圧縮後サイズ
zstd -101.57 秒5,246,512 バイト
zstd -10 -T00.69 秒(2.3 倍速)5,246,512 バイト(同一)
zstd -1955.84 秒4,538,157 バイト
zstd -19 -T025.89 秒(2.2 倍速)4,538,157 バイト(同一)

注目したいのは圧縮後サイズが 1 バイトも変わっていない点です。-T0 は圧縮結果を犠牲にせず時間だけを短縮するため、バッチ処理では基本的に付けておいて構いません。

ただし本番サーバーで全コアを占有すると他のプロセスに影響します。コア数を明示して加減するのが安全です。

zstd -19 -T2 access.log              # 2スレッドだけ使う
nice -n 19 zstd -19 -T0 access.log   # 優先度を下げて全コア使う

解凍はマルチスレッド化されないため、-T0 を付けても解凍は速くなりません(元々十分速いため実用上の問題はありません)。

tar と組み合わせて .tar.zst を作る

zstd 単体では複数ファイルをまとめられないため、ディレクトリを圧縮するときは tar と組み合わせます。

圧縮する(GNU tar 1.31 以降)

tar --zstd -cf backup.tar.zst /var/www/html/

展開する

tar --zstd -xf backup.tar.zst
tar --zstd -tf backup.tar.zst    # 展開せず中身の一覧を見る

圧縮レベルやスレッド数を指定する

--zstd は既定レベル(-3)で動くため、レベルや -T0 を効かせたい場合は -I で圧縮コマンドごと渡します。

tar -I 'zstd -19 -T0' -cf backup.tar.zst /var/www/html/

実際に同じディレクトリで比べると、--zstd では 6,615,380 バイト、-I 'zstd -19 -T0' では 4,552,222 バイトと、約 31% 小さくなりました。クォートで囲むことを忘れないでください。囲まないと -19 が tar のオプションとして解釈されます。

古い tar で .tar.zst を展開する

GNU tar 1.30 以前や macOS 標準の BSD tar では --zstd が使えません。その場合はパイプでつなぎます。

zstd -dc backup.tar.zst | tar -xf -

圧縮する場合も同様です。

tar -cf - /var/www/html/ | zstd -19 -T0 > backup.tar.zst

tar のバージョンは tar --version で確認できます。

実務レシピ:logrotate で zstd 圧縮する

logrotate は既定で gzip を使いますが、compresscmd を差し替えると zstd を使えます。以下は実際に動作確認した設定です。

/var/log/myapp/app.log {
    daily
    rotate 4
    missingok
    compress
    compresscmd /usr/bin/zstd
    compressoptions -19 -T0
    compressext .zst
    uncompresscmd /usr/bin/unzstd
}

設定を書いたら、-d(デバッグ、実際には変更しない)で確認してから -f で強制実行してテストします。

logrotate -d /etc/logrotate.d/myapp     # 動作確認のみ
logrotate -f /etc/logrotate.d/myapp     # 強制実行

logrotate 3.21.0 で検証したところ、約 2.9MiB のログが app.log.1.zst として 183KiB まで圧縮されました。--rm を書かなくても、ローテート元のファイルは logrotate 自身が削除します。

注意:compressoptions の値をクォートで囲んではいけません。次のように書くと失敗します。

# NG: クォートすると1つの引数として渡されてしまう
compressoptions "-19 -T0"
error: Compressing program wrote following message to stderr when compressing log
  /var/log/myapp/app.log.1:
Incorrect parameters
error: failed to compress log /var/log/myapp/app.log.1

Incorrect parameters というメッセージだけでは原因がわかりにくいですが、クォートを外せば解決します。ログ運用全体の設計は logrotate の記事定期バックアップの記事もあわせて確認してください。

つまずきポイントと対処

1. gzip と違い、元ファイルが消えない

もっとも間違えやすい違いです。同じファイルを両方で圧縮すると挙動がはっきり分かれます。

$ cp access.log a.log; cp access.log b.log
$ gzip a.log        # gzip は元ファイルを削除する
$ zstd -q b.log     # zstd は元ファイルを残す
$ ls a.log a.log.gz b.log b.log.zst
ls: cannot access 'a.log': No such file or directory
a.log.gz
b.log
b.log.zst

gzip のつもりでバッチを組むと、ディスクを空けるために圧縮したのに元ファイルが残って容量が減らないという事故になります。削除したい場合は明示的に --rm を付けてください。

zstd --rm access.log

2. -22 を指定しても、–ultra がないと黙ってレベル19になる

レベル 20 以上には --ultra が必要ですが、付け忘れてもエラーにはならず、警告を出してレベル 19 に下げられます。終了ステータスも 0 です。

$ zstd -22 -c access.log > out.zst
Warning : compression level higher than max, reduced to 19
$ echo $?
0

実際に出力を比べると、-22--ultra なし)と -19 はバイト単位で完全に一致しました。

-22(--ultraなし): 4,538,157 バイト
-19               : 4,538,157 バイト  ← 完全一致
--ultra -22       : 4,392,987 バイト  ← こちらが本来のレベル22

スクリプトでは警告が -q2>/dev/null で消えてしまうため、最高圧縮のつもりが実は 19 だったと気づきにくい点に注意してください。レベル 20 以上を使うときは必ず --ultra をセットで書きます。

3. cron で実行すると「already exists」で止まる

出力先がすでに存在すると、zstd は上書き確認を求めます。端末がない cron では確認できず、終了ステータス 1 で失敗します。

$ zstd access.log -o backup.zst
zstd: backup.zst already exists; overwrite (y/n) ? Not overwritten
$ echo $?
1

定期実行するスクリプトでは -f(強制上書き)と -q(進捗抑制)を付けておくのが安全です。

zstd -q -f -19 -T0 access.log -o /backup/access.zst

4. zstd -l で元のサイズが空欄になる

パイプ経由で作った .zst は、圧縮時に元サイズが確定していないためヘッダーに記録されません。その結果 zstd -l の Uncompressed 欄と Ratio 欄が空になります。tar --zstd で作った書庫も同様です。

$ cat small.log | zstd -q > pipe.log.zst
$ zstd -l pipe.log.zst
Frames  Skips  Compressed  Uncompressed  Ratio  Check  Filename
     1      0    18.2 KiB                       XXH64  pipe.log.zst

元サイズを記録したい場合は --stream-size であらかじめ渡します。

$ cat small.log | zstd -q --stream-size=$(stat -c%s small.log) > pipe2.log.zst
$ zstd -l pipe2.log.zst
Frames  Skips  Compressed  Uncompressed  Ratio  Check  Filename
     1      0    18.7 KiB       195 KiB  10.457  XXH64  pipe2.log.zst

なお、サイズが空欄でもデータそのものは正常です。zstd -t での検証や解凍には影響しません。

5. –long を付けても必ず縮むわけではない

遠く離れた重複を検出する --long は、巨大な VM イメージなどで効果がありますが、今回のアクセスログでは逆にわずかに増えました。

zstd -10 -T0              : 5,246,512 バイト
zstd -10 -T0 --long=27    : 5,291,995 バイト  ← むしろ増えた

--long は解凍時にも同じだけのメモリ(--long=27 で約 128MB)を要求します。効果を実測してから採用してください。

.gz / .zst / .xz / .zip の違い

形式コマンド特徴複数ファイル主な用途
.zstzstd / unzstd解凍が非常に速い。速度と圧縮率のバランス型✗(tar と併用)ログ圧縮、バックアップ、配布物
.gzgzip / gunzipどこでも動く事実上の標準。互換性は最高✗(tar と併用)ログ圧縮、パイプ処理
.xzxz / unxz高圧縮だが圧縮が遅い✗(tar と併用)ソース配布、長期保管
.zipzip / unzip複数ファイルを 1 つにまとめられるWindows 連携、ファイル配布

使い分けの目安は次のとおりです。

  • 自分のサーバー内で完結するログ圧縮・バックアップ → zstd
  • 相手の環境が不明なファイル受け渡し → gzip.tar.gz
  • Windows ユーザーとやりとりする → zip

zstd は比較的新しい形式のため、古い環境ではコマンドが入っていないことがあります。社外に配布するファイルは .tar.gz にしておくほうが安全です。

よくある質問(FAQ)

Q. 圧縮レベルはいくつにすればよいですか?

用途で決めます。リアルタイム処理やパイプ中継なら既定の -3、日次のログ圧縮なら -10 -T0(今回の計測で 0.69 秒・5.00MiB)、月次アーカイブなど時間をかけてよい場面なら -19 -T0 が目安です。-19-10 の 37 倍の時間がかかって 13% しか縮まないため、常用は勧めません。

Q. gzip から zstd に乗り換えて大丈夫ですか?

自分が管理するサーバー内で圧縮・解凍が完結するなら問題ありません。ただし .zst を扱えない古い環境や、外部にファイルを渡す場面では gzip のほうが確実です。既存の .gz ファイルはそのまま読めるので、新しく作るものから順に切り替えるのが安全です。

Q. pzstd と zstd -T0 はどちらを使うべきですか?

pzstd は zstd 本体がマルチスレッドに対応する前に作られた別実装です。現在は zstd -T0 で同等のことができるため、新しく書くスクリプトでは zstd -T0 を使ってください。

Q. 圧縮したまま中身を検索できますか?

できます。zstdgrep を使えば解凍せずに grep できます。ディスクの空きがないサーバーでの調査に有効です。

zstdgrep 'error' app.log.zst
zstdgrep -c ' 500 ' access.log.zst    # 該当行数を数える

Q. 解凍したデータが元と同じか確認できますか?

md5sum で突き合わせれば確認できます。実際に 73.42MiB のログをパイプ経由で圧縮・解凍したところ、ハッシュは一致しました。

$ md5sum access.log | cut -d' ' -f1
7824f7eaf48dfd18208cd16d332da8a7
$ cat access.log | zstd -q -T0 -19 > dump.zst
$ zstdcat dump.zst | md5sum | cut -d' ' -f1
7824f7eaf48dfd18208cd16d332da8a7

関連コマンド

備考

  • 本記事の計測値は Ubuntu 24.04.4 LTS / 6 コア / zstd 1.5.5 での実測です。圧縮率・所要時間はデータの性質と CPU 性能で大きく変わるため、目安として参照してください。
  • JPEG・MP4・すでに圧縮済みの書庫はほとんど縮みません。効果が高いのはテキスト・ログ・ソースコード・データベースダンプです。
  • 圧縮レベルを上げても解凍速度はほぼ変わりません。高いレベルのコストは圧縮時間とメモリにだけ現れます。

参考

Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント