最強の圧縮方式について調査
· 約6分
結論
結論から。
合計 34 GiB の大量のファイルを圧縮・展開したときの時間とサイズを調べた。
圧縮・アーカイブ作成
| 方式 | コマンド | real | user | sys | 圧縮後のサイズ |
|---|---|---|---|---|---|
| tar | tar cf large-pkg.tar large-pkg | 1m19.449s | 0m6.702s | 0m48.121s | 26 GiB |
| tar.gz | tar czf large-pkg.tar.gz large-pkg | 11m33.942s | 11m18.811s | 0m55.573s | 5.5 GiB |
| LZ4 | tar cf - large-pkg | lz4 > large-pkg.tar.lz4 | 3m33.187s | 0m53.958s | 2m57.122s | 8.6 GiB |
| zstd | tar cf - large-pkg | zstd -T0 -o large-pkg.tar.zst | 9m13.819s | 1m45.049s | 2m43.609s | 4.8 GiB |
| bzip2 | tar cf - large-pkg.1 | bzip2 > large-pkg.tar.bz2 | 37m22.743s | 28m40.329s | 3m31.000s | 4.3 GiB |
| xz | tar cf - large-pkg | xz > large-pkg.tar.xz | 125m31.447s | 124m10.523s | 5m18.330s | 3.3 GiB |
展開 (解凍)
| 方式 | コマンド | real | user | sys |
|---|---|---|---|---|
| tar | tar xf large-pkg.tar | 2m11.793s | 0m6.906s | 2m4.183s |
| tar.gz | tar xf large-pkg.tar.gz | 3m39.544s | 2m1.189s | 2m58.317s |
| tar.gz(gzip) | gzip -dc large-pkg.tar.gz | tar xf - | 3m40.416s | 2m0.272s | 3m0.043s |
| tar.gz(pigz) | pigz -dc large-pkg.tar.gz | tar xf - | 3m53.711s | 1m38.147s | 4m42.893s |
| LZ4 | lz4 -dc large-pkg.tar.lz4 | tar xf - | 4m46.576s | 0m32.174s | 4m36.055s |
| zstd | zstd -dc large-pkg.tar.zst | tar xf - | 3m46.419s | 0m46.533s | 3m34.668s |
| bzip2 | bzip2 -dc large-pkg.tar.bz2 | tar xf - | 11m31.287s | 9m52.644s | 4m17.974s |
| xz | xz -dc large-pkg.tar.xz | tar xf - | 8m11.527s | 3m45.562s | 7m15.109s |
小さく大量のファイルを用意
まず、小さく大量のファイルとして、node_modules を用いることとした。
package.json を以下のようにした。パッケージは適当なもの。
package.json
{
"name": "large-pkg",
"version": "1.0.0",
"description": "",
"author": "",
"type": "commonjs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": {
"async": "^3.2.6",
"axios": "^1.13.2",
"bcryptjs": "^3.0.3",
"bluebird": "^3.7.2",
"body-parser": "^2.2.2",
"chalk": "^5.6.2",
"chalk-template": "^1.1.2",
"cheerio": "^1.1.2",
"chokidar": "^5.0.0",
"commander": "^14.0.2",
"cookie": "^1.1.1",
"core-js": "^3.47.0",
"cors": "^2.8.5",
"debug": "^4.4.3",
"dotenv": "^17.2.3",
"express": "^5.2.1",
"fast-glob": "^3.3.3",
"form-data": "^4.0.5",
"glob": "^13.0.0",
"got": "^14.6.6",
"inquirer": "^13.2.0",
"jsonwebtoken": "^9.0.3",
"lodash": "^4.17.21",
"mime": "^4.1.0",
"minimist": "^1.2.8",
"mkdirp": "^3.0.1",
"mkdirp-classic": "^0.5.3",
"mongoose": "^9.1.4",
"ms": "^2.1.3",
"node-fetch": "^3.3.2",
"ora": "^9.0.0",
"passport": "^0.7.0",
"prop-types": "^15.8.1",
"qs": "^6.14.1",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"request": "^2.88.2",
"rimraf": "^6.1.2",
"semver": "^7.7.3",
"sharp": "^0.34.5",
"socket.io": "^4.8.3",
"supports-color": "^10.2.2",
"tslib": "^2.8.1",
"uuid": "^13.0.0",
"ws": "^8.19.0",
"xml2js": "^0.6.2",
"yargs": "^18.0.0"
},
"devDependencies": {
"@babel/cli": "^7.28.6",
"@babel/plugin-transform-runtime": "^7.28.5",
"@babel/preset-env": "^7.28.6",
"@babel/runtime": "^7.28.6",
"autoprefixer": "^10.4.23",
"ava": "^6.4.1",
"babel-core": "^6.26.3",
"babel-loader": "^10.0.0",
"chai": "^6.2.2",
"commitlint": "^20.3.1",
"concurrently": "^9.2.1",
"conventional-changelog": "^7.1.1",
"cross-env": "^10.1.0",
"css-loader": "^7.1.2",
"dotenv-expand": "^12.0.3",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.8",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.5",
"husky": "^9.1.7",
"jest": "^30.2.0",
"less": "^4.5.1",
"lint-staged": "^16.2.7",
"mocha": "^11.7.5",
"nodemon": "^3.1.11",
"playwright": "^1.57.0",
"pm2": "^6.0.14",
"postcss": "^8.5.6",
"prettier": "^3.8.0",
"puppeteer": "^24.35.0",
"rollup": "^4.55.1",
"rxjs": "^7.8.2",
"sass": "^1.97.2",
"semantic-release": "^25.0.2",
"sinon": "^21.0.1",
"style-loader": "^4.0.0",
"stylus": "^0.64.0",
"supertest": "^7.2.2",
"tailwindcss": "^4.1.18",
"ts-loader": "^9.5.4",
"ts-node": "^10.9.2",
"typescript": "^5.9.3",
"vite": "^7.3.1",
"vitest": "^4.0.17",
"webpack": "^5.104.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.3",
"zx": "^8.8.5"
}
}
ここから、以下のコマンドで node_modules を作成する。
npm i
容量を見てみよう。
$ du -h -d1
566M ./node_modules
567M .
これで、小さく大量のファイルが作成されたことがわかる。
node_modules をコピーしてさらに多くのファイルを作成する。
for i in {1..59}; do
echo "node_modules.${i} をコピー中..."
cp -r node_modules "node_modules.${i}"
done
容量を見てみよう。
$ du -h -d1
...
34G .
そこそこ大きい容量となった。
tarball
tarball にする速度を見てみる。
アーカイブ
$ time tar cf large-pkg.tar large-pkg
real 1m19.449s
user 0m6.702s
sys 0m48.121s
アーカイブ後、26 GiB
展開
$ time tar xf large-pkg.tar
real 2m11.793s
user 0m6.906s
sys 2m4.183s
アーカイブと展開はそこそこ速い。
tar.gz
次に、tar.gz で試す。
tar コマンドはアーカイブするコマンドで、gzip は単一のファイルを圧縮するコマンドだ。これを組み合わせて作成されたのが tar.gz ファイルである。 現在では tar コマンドのみで tar.gz ファイルの圧縮と展開が可能だ。(ほかの圧縮形式も同様)
圧縮
$ time tar czf large-pkg.tar.gz large-pkg
real 11m33.942s
user 11m18.811s
sys 0m55.573s
圧縮後: 5.5 GiB
展開
$ time tar xf large-pkg.tar.gz
real 3m39.544s
user 2m1.189s
sys 2m58.317s
tar と gzip で展開
$ time sh -c 'gzip -dc large-pkg.tar.gz | tar xf -'
real 3m40.416s
user 2m0.272s
sys 3m0.043s
速度はほぼ同じ。
並列で展開 (pigz)
$ time sh -c 'pigz -dc large-pkg.tar.gz | tar xf -'
real 3m53.711s
user 1m38.147s
sys 4m42.893s
あまり速度は変わんない。ファイルの読み書き速度がボトルネックとなっているようだ。
bzip2
圧縮
$ time sh -c 'tar cf - large-pkg.1 | bzip2 > large-pkg.tar.bz2'
real 37m22.743s
user 28m40.329s
sys 3m31.000s
圧縮後: 4.3 GiB
圧縮に時間がかかっているが、圧縮率はそこそこ良い。
展開
$ time sh -c 'bzip2 -dc large-pkg.tar.bz2 | tar xf -'
real 11m31.287s
user 9m52.644s
sys 4m17.974s
展開も時間はかかるが、展開率はそこそこ良い。
xz
圧縮
$ time sh -c 'tar cf - large-pkg | xz > large-pkg.tar.xz'
real 125m31.447s
user 124m10.523s
sys 5m18.330s
圧縮後: 3.3 GiB
圧縮率は極めて優秀だが、時間がかかりすぎる。
ネット回線が非常に遅く、ストレージ料金が高く、数年に1度使うようなレアケースではいいかも。
展開
$ time sh -c 'xz -dc large-pkg.tar.xz | tar xf -'
real 8m11.527s
user 3m45.562s
sys 7m15.109s
LZ4
圧縮
$ time sh -c 'tar cf - large-pkg | lz4 > large-pkg.tar.lz4'
real 3m33.187s
user 0m53.958s
sys 2m57.122s
展開
$ time sh -c 'lz4 -dc large-pkg.tar.lz4 | tar xf -'
real 4m46.576s
user 0m32.174s
sys 4m36.055s
zstd
Meta (旧 Facebook) が開発した高速の圧縮方式。
圧縮
$ time sh -c 'tar cf - large-pkg | zstd -T0 -o large-pkg.tar.zst'
/*stdin*\ : 18.57% (27492075520 => 5106239218 bytes, large-pkg.tar.zst)
real 9m13.819s
user 1m45.049s
sys 2m43.609s
展開
$ time sh -c 'zstd -dc large-pkg.tar.zst | tar xf -'
large-pkg.tar.zst : 27492075520 bytes
real 3m46.419s
user 0m46.533s
sys 3m34.668s
