2017年12月22日金曜日

XZをマルチスレッドで圧縮・展開

もう、多くの人がweb上で紹介しているが、xzのver5.2以降はマルチスレッド圧縮に対応している。
実は私も、今年になって、Zesty(17.04)用のxz-utils,liblzma-devパッケージをXenial(16.04)にインストールして使っている。
私は無理やりこのUbuntu packageページからバイナリパッケージを落としてきて、インストールしたがもっといい方法が紹介されていた。

xzをマルチスレッドにしたら爆速になった

aptの設定を書き換えて、一部のパッケージのみZestyのものが優先されるようにしている。これが正しいやり方だろう。
私は、自家製xzランダムアクセスアプリのためにliblzma-devも使っているので、/etc/apt/preferences.d/xzを以下のようにした。
Package: *
Pin: release n=xenial
Pin-priority: 501

Package: xz-utils liblzma5 liblzma-dev
Pin: release n=zesty
Pin-Priority: 502
(2018/01/20 追記: Zestyはリポジトリ上から無くなった。そのため、この手法は使えなくなった。)

さらに、xzイメージをマウントするためにnbdkitやnbd-clientもZestyのものを使っているので、以下の内容で/etc/apt/preferences.d/nbdを作った。
Package: *
Pin: release n=xenial
Pin-priority: 501

Package: nbd-server nbd-client nbdkit nbdkit-plugin-*
Pin: release n=zesty
Pin-Priority: 502
(2018/01/20 追記: Zestyはリポジトリ上から無くなった。そのため、この手法は使えなくなった。)

圧縮をマルチスレッドで行うのは、多くのページで紹介されているように、xzのオプションに"-T"でスレッド数指定すればいい。
"-T0"を指定すると自動でCPU数になるので、馬鹿の一つ覚え的に使うなら、"-T0"が良いだろう。
古い方の圧縮イメージのマウントでも少し触れたが、私は、圧縮プリセットレベルをあえて0、ブロックサイズを1MiBに指定している。(しばしば、プリセットレベルを"0e"にすることもある)
すなわち、以下のようなコマンドになる。
xz -0e --block-size=1MiB xxxxx
プリセットレベルを上げても圧縮レートの向上はわずかだ。それでいて必要な時間はぐっと長くなる。
処理能力にもよるが、自分にあった使い方を探すのが良い。


ここでも少し書いたが、現時点でxz-utilsでは、圧縮はマルチスレッドで行えるが、展開はマルチスレッドではできない。
圧縮のほうが時間がかかるので、圧縮が高速化されるだけでもありがたい事だが、人間の欲望は際限がない。できれば展開も爆速にしたい。

自家製のxzランダムアクセスアプリは、展開もマルチスレッドで行える。
ソース: xzrd-171219.tar.xz (ビルド方法は、圧縮データをランダムアクセスしよう を参照)
これを使って、大きな.tar.xzを展開するなら、以下のようにする。
xzrd -c0 -v0 xxxxxxxx.tar.xz | tar -xvf -
(tarの"v"オプションを省くと、展開中のファイル名が抑制されてさらに高速化する)

ただし、このアプリは元々ランダムアクセス用に作ったので、パイプで展開処理できない。別の言い方をすると、圧縮データを標準入力から入れる事はできない。
すなわち、以下のような使い方はできない。
ssh user@host "tar -C work/ -xf - dddd/ | xz -T0 -0ecv --block-size=1MiB" | xzrd -c0 -v0 | tar -cvf -
ERROR: Need xz file.    <=== エラーになる。
これについては、本家での開発を待とう。

xz-file-format.txtの"2. Overall Structure of .xz File"を読むと、
2. Overall Structure of .xz File

        A standalone .xz files consist of one or more Streams which may
        have Stream Padding between or after them:

            +========+================+========+================+
            | Stream | Stream Padding | Stream | Stream Padding | ...
            +========+================+========+================+

        The sizes of Stream and Stream Padding are always multiples
        of four bytes, thus the size of every valid .xz file MUST be
        a multiple of four bytes.

        While a typical file contains only one Stream and no Stream
        Padding, a decoder handling standalone .xz files SHOULD support
        files that have more than one Stream or Stream Padding.

        In contrast to standalone .xz files, when the .xz file format
        is used as an internal part of some other file format or
        communication protocol, it usually is expected that the decoder
        stops after the first Stream, and doesn't look for Stream
        Padding or possibly other Streams.
真ん中のあたり、
        While a typical file contains only one Stream and no Stream
        Padding, a decoder handling standalone .xz files SHOULD support
        files that have more than one Stream or Stream Padding.
これを自分なりに日本語にすると、
        一般的なファイルは、1つのストリームだけでストリームパディングが
        無いとはいえ、スタンドアロン.xzファイルを扱うデコーダは、1つ以上の
        ストリームやストリームパディングを持つファイルをサポートしなければ
        ならない。
となっている(以前の訳から少し直した)。
xzrdのようなデコーダは、複数のストリームに対応しなければならないのだ。
しかし、現時点でxzrdは、複数のストリームに対応していない。

これについては、早急に対応しようと思っている。
2017/12/23 追記 RFC-2119 をよく読んだら、"SHOULD"は、「する必要がある。」「やるべきだ。」ぐらいの意味で、「しなければならない。」という意味ではない。本当におっちょこちょいだな。
2018/01/20 追記 Zesty Zapus(Ubuntu 17.04)は、リポジトリ上から無くなったようだ。そのため、Zestyのもので置き換えることはできなくなった。どうしても新しい物を使うなら、ArtfulやBionicのもので置き換えるか、ソースからビルドする必要がある。xz関連はBionicのものでもinstallできるが、ndb関連は依存関係が解決できず、installできない。
気が向いたら、詳しく調べるかもしれない。

0 件のコメント:

コメントを投稿