ソースの表示以前のリビジョンバックリンク全て展開する/折り畳む文書の先頭へ Share via Share via... Twitter LinkedIn Facebook Pinterest Telegram WhatsApp Yammer Reddit Teams最近の変更Send via e-Mail印刷パーマリンク × RAIDZプールに追加したスペシャルvdevは削除できない OpenZFS 2.1.4時点で、冗長性レベルを問わずRAID-Zプールに追加したスペシャルvdevを削除することは出来ないようだ。恐らく、トップレベルvdev削除の制限に起因する仕様と思われる。 次のようなRAID-Z1とスペシャルvdevから成るプールがあるとする。 # zpool status ztank pool: ztank state: ONLINE config: NAME STATE READ WRITE CKSUM zdata ONLINE 0 0 0 raidz1-0 ONLINE 0 0 0 da1 ONLINE 0 0 0 da2 ONLINE 0 0 0 da3 ONLINE 0 0 0 special mirror-1 ONLINE 0 0 0 da4 ONLINE 0 0 0 da5 ONLINE 0 0 0 errors: No known data errors ここで、スペシャルvdevを削除しようとzpool removeすると、次のようにエラーとなる。 # zpool remove ztank mirror-1 cannot remove mirror-1: invalid config; all top-level vdevs must have the same sector size and not be raidz. トップレベルvdevのmirror-1を一気に削除するのがマズいのかと思い、次のように構成メンバを個別に削除してってもダメ。 # zpool detach ztank da5 # zpool remove ztank da4 cannot remove ..... なお、RAIDZ以外の構成なら特に制限なく削除可能で、同じトップレベルvdevであるslogやL2ARCの場合は、RAIDZでも(以前から)削除可能である。 家鯖でスペシャルvdevを本格運用すべく色々準備してたけど、削除できないのはちょっと厳しいなぁ…VMであらかじめ実験しといて良かったぜ……slog/L2ARCは削除できるんだから、将来的にできるようになるのかなぁ………スペシャルvdevの場合、明示的に本体プールの方にデータを書き戻す必要があって難しいのかなぁ………… 当面はpL2ARCを使うとするかー。 Special vdevが消失したプールとzpool -Fオプション プールのメタデータを丸っと引き受けるというZFSのSpecial vdevの特性から、対応する物理デバイスの故障などでSpecial vdevが死ぬと、プールそのものが使えなくなりそうってのは容易に想像ができる。 実際どうなるか仮想マシンベースで確認してみると、やはり使えなくなった。それもzpool listの結果にプール自体が出てこなくなるという、割と重篤な扱い。プール名を指定 or プール探索でインポートしようとすると、以下のようになってインポートできない。 # zpool import -a -N cannot import 'ztest': I/O error Destroy and re-create the pool from a backup source. 存在しないプールのインポートではcannot import 'znotexists': no such pool availableって感じなので、明らかに扱いが違う。 Special vdevが消失したプールの復旧は基本的に無理っぽい感じ。 一応man zpool-importを見てみると、(いつの間にか)プール回復に関するオプション-F, -X, -Tが追加されていた。それぞれの効果を抄訳してみた。 -F インポート不可能なプールのための回復モード。最後のわずかなトランザクションを破棄することで、プールがインポート可能状態への復帰を試みます。このオプションを使うことで、損傷を受けたすべてのプールが回復するとは限りません。成功した場合、破棄されたトランザクションに関連するデータは、回復不能なほどに失われます。プールがインポート可能またはインポート済みの場合、このオプションは無視されます。 -n 回復オプション(-F)と共に使用します。インポート不可能なプールが再びインポート可能になるかどうかを判定しますが、実際にプール回復は行いません。プール回復モードの詳細は、上記の-Fオプションをご覧ください。 -X 回復オプション(-F)と共に使用します。有効なtxgを見つけるための非常手段を取るか否かを指定します。これは、もはや一貫性が保証されていないtxgへ、プールがロールバックされることを許可します。矛盾したtxgでインポートされたプールは修復不能なチェックサムエラーを含むかもしれません。プール回復モードの詳細は、上記の-Fオプションをご覧ください。警告:このオプションはプールの健全性に対し極めて危険な可能性があり、最終手段として用いるべきです。 -T ロールバックに使用するtxgを指定します。暗黙的に-FXオプションを含みます。プール回復モードの詳細は、上記の-Xオプションをご覧ください。警告:このオプションはプールの健全性に対し極めて危険な可能性があり、最終手段として用いるべきです。 -F < -X < -Tの順で強力(危険)になる雰囲気。で、それぞれを指定して、先のSpecial vdevが無くなったプールのインポートを試みたのが以下。 # zpool import -F ztest cannot import 'ztest': I/O error Destroy and re-create the pool from a backup source. # zpool import -FX ztest cannot import 'ztest': one or more devices is currently unavailable # zpool import -T ztest invalid txg value usage: import [-d dir] [-D] import [-o mntopts] [-o property=value] ... [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] [-R root] [-F [-n]] -a import [-o mntopts] [-o property=value] ... [-d dir | -c cachefile] [-D] [-l] [-f] [-m] [-N] [-R root] [-F [-n]] [--rewind-to-checkpoint] <pool | id> [newpool] -Tはtxgを指定してやらないとダメな予感。usageにもmanにもそれらしいことは書いてないんだけど…実際にどんな値を指定したらいいのか皆目見当もつかない。 その後、Special vdev用の仮想ディスクを戻してみると、問題なくプールのインポートができた。ただし自動インポートはされず、手動で行う必要があるようだ。(上記の-Fとかでプールを操作したためかもしれないが未確認。)scrubで健全性に問題がないことも確認。 そんなわけでSpecial vdevの冗長性には十分気を付ける必要がありそうだ。 ZFSのSpecial vdevを試してみる 階層化ストレージのZFS版ともいえるSpecial vdevとSpecial Allocation Classについて、1年程前に当サイトでも解説した。いつか試そうと思いつつ延び延びになっていたが、いよいよ導入の機運が高まってきたので簡単にテストした。 コマンド まずはコマンドの確認から。以下、da0p1をノーマルvdev(プール本体のストレージ)、da6p1をスペシャルvdevとする。 スペシャルvdev付きプールを作る。vdevタイプとしてspecialを指定し、その後にスペシャルvdevに割り当てるデバイスを指定する。 # zpool create -O atime=off ztest da0p1 special da6p1 $ zpool status ztest pool: ztest state: ONLINE config: NAME STATE READ WRITE CKSUM ztest ONLINE 0 0 0 da0p1 ONLINE 0 0 0 special da6p1 ONLINE 0 0 0 既存のプールにスペシャルvdevを追加する場合はzpool addで同様に指定する。 # zpool add ztest special da6p1 スペシャルvdevの削除。これはL2ARCやslogの削除なんかと一緒。 # sudo zpool remove ztest da6p1 OpenZFS 2.1.4の時点において、RAIDZプールに追加したスペシャルvdevは削除できないので注意!!(トップレベルvdev削除の制限事項)。 スペシャルvdevデバイスの増減(zpool attach/detach)は可能だが、いざzpool removeしようとするとinvalid config; all top-level vdevs must have the same sector size and not be raidz.エラーとなり削除できない。 slogやL2ARCは削除できるのにどうして…… ただし、remove後にスペシャルvdevからノーマルvdevへ、データの退避が行われる。 $ zpool status ztest pool: ztest state: ONLINE remove: Evacuation of /dev/da6p1 in progress since Wed Feb 23 16:50:17 2022 2.77G copied out of 13.5G at 142M/s, 20.54% done, 0h1m to go config: NAME STATE READ WRITE CKSUM ztest ONLINE 0 0 0 da0p1 ONLINE 0 0 0 special da6p1 ONLINE 0 0 0 $ zpool iostat -v ztest capacity operations bandwidth pool alloc free read write read write ---------- ----- ----- ----- ----- ----- ----- ztest 14.4G 9.13T 16 68 215M 220M da0p1 932M 9.09T 0 68 0 220M special - - - - - - da6p1 13.5G 36.0G 16 0 215M 0 ---------- ----- ----- ----- ----- ----- ----- 退避が完了するとプールからデバイスが除去される。 $ zpool status ztest pool: ztest state: ONLINE remove: Removal of vdev 1 copied 13.5G in 0h1m, completed on Wed Feb 23 16:51:31 2022 27.4K memory used for removed device mappings config: NAME STATE READ WRITE CKSUM ztest ONLINE 0 0 0 da0p1 ONLINE 0 0 0 スペシャルvdevは標準でメタデータのみを格納する設定となっている。小ブロックデータの格納を有効にするには、ファイルシステム毎のプロパティspecial_small_blocksを0以外の2の冪数に設定する。 # zfs set special_small_blocks=64k ztest/R/pictures $ zfs get -r special_small_blocks ztest NAME PROPERTY VALUE SOURCE ztest special_small_blocks 0 default ztest/R special_small_blocks 0 default ztest/R/pictures special_small_blocks 64K local スペシャルvdevが使われてるかどうかはzpool iostat -vで確認できる。書き込み中に見てみると、しっかりスペシャルvdevも使われていることがわかる。 capacity operations bandwidth pool alloc free read write read write ---------- ----- ----- ----- ----- ----- ----- ztest 11.7G 9.13T 0 1.36K 0 213M da0p1 11.4G 9.08T 0 215 0 207M special - - - - - - da6p1 277M 49.2G 0 1.15K 0 6.22M ---------- ----- ----- ----- ----- ----- ----- テスト スペシャルvdevの有無、special_small_blocksのサイズ、レコードサイズの違いで簡単にテストを行う。 テスト環境 テストデータ 72208ファイル、10.3GiB(平均ファイルサイズ:150KiB) Special vdevの効果が出やすいであろう、大量の小サイズの画像ファイル群 テストマシン OS: FreeBSD 13.0-RELEASE-p6 on Proxmox VE 7.1 CPU: 4 vCPU (Xeon E5-2680v4. オーバーコミットなし) RAM: 32GB HDD: コピー元: 単体 (仮想ディスク50GB/実態はU.2 SSD) コピー先: 単体 (10TB 7200RPM SATA HDD×1) コピー先のプールのスペシャルvdevの有無によって、以下の項目を測定する。 コピー元→コピー先へのファイルコピー所要時間(rsync -aX src dst/) コピー先でファイルの全走査にかかる時間(find dst > /dev/null) コピー先でファイルの全読込にかかる時間(find dst -print0 | xargs -0 cat) ARCの影響を避けるため、プールは都度作成し、rsync後はマシンを再起動する。その後、ファイル走査→全読込の順で実行する。 テスト結果 仮想マシン上での実行のため、結果にはノイズが多く含まれていることに注意。 recsize special_small_blocks コピー時間(秒) ファイル走査時間(秒) ファイル読込時間(秒) スペシャルvdev使用量(MiB) 備考 128k - 284 17.8 539 - Special vdevなし 0 281 2.5 493 319 メタデータのみSpecial vdevを利用 4k - - - 320 sdev容量のみ測定 8k - - - 321 16k - - - 322 32k - - - 336 64k 279 2.6 433 684 128k 280 2.8 203 13824 全データがSpecial vdevに行く 1M - 280 17.6 400 - Special vdevなし 0 285 2.5 358 34 4k - - - 35 sdev容量のみ測定 8k - - - 36 16k - - - 37 32k - - - 52 64k 274 2.7 352 400 128k 276 2.8 286 3102 ※special_small_blocks=4k~32kは後から測定したため、スペシャルvdevの容量のみ。グラフには加えていない。1MBずつ増えてて本当かよ?と思ったが、再度試しても同じだったので間違ってるわけではなさそう。 スペシャルvdevの有無でファイルコピー(書き込み。赤線)時間に有意な差は見られなかった。ただし、これはコピー元の読み込みで律速してる可能性が否定できない。コピー先の書き込み状況をiostatを眺めてみると間欠動作となっていた。 ファイルの全走査はスペシャルvdevがあると劇的に高速化されるようだ。iostatを見てみると、スペシャルvdevで読み込み処理が走っており、SSD上のメタデータが使わているものと思われる。期待通りの挙動ですな。 ファイルの全読込も、スペシャルvdevに保存されているデータ量に応じて短縮されており、こちらも想定通り。recsize=128kでspecial_small_blocks=128kとすると、全データがスペシャルvdevに保存されるというのも期待通りの結果だった(special_small_blocksで指定されたサイズ以下のレコードのデータがスペシャルvdevに保存される仕様。)iostatを見てみると、見事に全てスペシャルvdevに書き込まれていることが分かる。 capacity operations bandwidth pool alloc free read write read write ---------- ----- ----- ----- ----- ----- ----- ztest 13.2G 9.13T 0 2.21K 0 236M da0p1 0 9.09T 0 3 0 15.2K special - - - - - - da6p1 13.2G 36.3G 0 2.20K 0 235M ---------- ----- ----- ----- ----- ----- ----- 少し意外だったのは、special_small_blocksが0、すなわちメタデータのみをスペシャルvdevに保存した場合でも、ファイル読込性能が向上したという点。今回は小さな大量のファイルが対象だったため、読込み処理におけるメタデータの処理割合が多かったのが要因だろう。 また、スペシャルvdevと直接は関係ないが、レコードサイズでメタデータサイズが大きく変化するというのは新たな発見だった。全くの推測だが、おそらくレコードごとに生成されるチェックサムの総量が影響しているのだろう。10.3GiBを128kiBレコードで割ると約84000レコードで、それぞれにfletcher4(4バイト)のチェックサムが付くと、合計330MiBとなる。同様に1MiBレコードでは41MiBとなり、これらはメタデータのみをスペシャルvdevに保存した際の容量とおおむね一致する。 さらに1MiBレコードではファイル読込が明らかに速くなっており、圧縮率の観点等も考慮すると積極的に128KiB以上のレコードサイズを使っていくのが良さそう。 special_small_blocksの設定をどうするかは悩ましいところ。扱うデータの種類やワークフローはもとより、TXG関連の設定やその時々の負荷量などで、書き込みがスペシャルvdev行きとなるかどうかが変わってくると思われ、見積もるのが難しい。今回は64k/128kの2パターンしか見なかったが、運用においては、より小さな設定値も検討に値するだろう。むしろ、とりあえず4kあたりから始めて様子を見るのがいいのかもしれない。 → 気になったので4k~32kを追試したけど、32k以下は殆ど効果がなさそう。スペシャルvdevの運用としては、容量が見積もりやすいメタデータのみとするか、ある程度余裕を持たせて64kで始めるの2択になるかも。 メタデータだけでもスペシャルvdevの効果は期待できそうなので、SSDに余裕があるならL2ARCよりも優先的に割り当てて良さそうに思う。 ZFS圧縮のLZ4とZStandardを簡易比較(zstdがよさげ) ZFSerの皆様におかれましては、OpenZFS 2.0で圧縮アルゴリズムにZStandardが追加されたのは周知の事実だろう。compressionの値としてzstd-Nとzstd-fast-Nが指定できるようになったが、設定値と圧縮率の関係性は以下のとおり。 (速度重視)← 設定値 →(圧縮重視) zstd-fast-1000 ~ zstd-fast-1 / zstd-1 ~ zstd-19 zstdとzstd-fastで数値の関係性が逆転しているように見えるが(というか設定値上はそういう風にしか見えないのだが)、zstd-fastの方は負数を表しており、-1000が最小でスーパー速度重視ということなので一貫性が取れている。 ZStandardはLZ4より圧縮率が高く、それに応じて処理負荷も若干高いとされている。実際のところどんなものか、簡易的にテストした。 個人的にアーカイブ用途に使いたいので、圧縮率重視ってことでzstdのみが対象。だいぶてきとーな実験なので、あくまで傾向を掴むもの程度で見て欲しい。 ZFSの主要開発者の1人、Allan Judeによる真っ当なベンチマークも参照されたし。 テスト環境 テスト環境は以下のとおり。 テストデータ 12675ファイル、503GiB(平均ファイルサイズ:40.6MiB) OS・アプリのISOイメージ、zip、インストーラexe、Macのdmg、appバンドルなど圧縮が効きにくいデータが多数 テストマシン OS: FreeBSD 13.0-RELEASE-p6 on Proxmox VE 7.1 CPU: 4 vCPU (Xeon E5-2680v4. オーバーコミットなし) RAM: 64GB HDD: コピー元: RAID-Z2 (16TB 7200RPM SATA HDD×5) コピー先: 単体 (10TB 7200RPM SATA HDD×1) テストデータをコピー元のRAID-Z2プールから、テスト用のコピー先プールにrsyncでコピーする。cpじゃなくてrsyncなのは、終了時に転送速度を表示してくれて便利だからってだけで、他意はない。 圧縮アルゴリズム別のファイルシステムを作ってはコピーしての繰り返しで、途中プールの作り直しやファイルシステム削除はしてないので、HDDの外周/内周の転送速度差がテストに影響していることに注意。 加えて、仮想マシン上での実行だったり、テスト中もファイルサーバとして普通にアクセスしたり(といっても負荷をかけないよう自粛はしたけど)と、結果には様々なノイズが混入している点にも注意。 テスト結果 各圧縮方法ごとの圧縮後容量、圧縮率(無圧縮時を100%とした時の割合)、転送速度を下表にまとめる。 パターン 圧縮方法 容量(GiB) 圧縮率(%) 速度(MiB/s) 備考 1 lz4 483.6 96.3 115.8 2 zstd-3 477.3 95.0 115.0 数値なしのzstdを指定した場合に使われる値 3 zstd-7 476.5 94.8 111.0 ここで2~3を削除 4 zstd-15 476.3 94.8 100.4 5 zstd-19 475.3 94.6 24.5 6 gzip-9 478.8 95.3 71.6 7 zstd-3 477.3 95.0 112.0 HDDの外周/内周の影響確認用 8 lz4 483.6 96.3 109.4 〃 9 off 502.4 100.0 108.9 無圧縮。基準値 パターン1~3実行後、一応、HDDの内外周差を気にしてパターン1,2のデータは削除している。 パターン9が基準値。無圧縮で最内周に書き込んでいるので、これより遅いかどうかで、圧縮処理がボトルネックになっているかの目安になるかなと。書き込み先がHDD 1台のプールなので、そこで律速されてる感があるけど、まぁ実際の使われ方に近い環境ってことで大目に見てください。 グラフで表したのが下図。 まず言えることはzstd-3のバランスの良さ。LZ4と遜色ない速度にもかかわらず、圧縮率は有意に高い。さすが、compress=zstdとした時に使われるレベルだけある。gzip-9より縮むのに大分速いってのは特筆すべき。 圧縮率最重視のzstd-19が当然ながら最も縮むが、速度が大分厳しい感じ。少なくとも今回のテストデータでは、処理時間に見合うだけの効果が得られているとは言い難い。仮に最新CPUで速度が10倍になったとしても、250MB/s程度でボトルネックとなる可能性が高く使いどころが難しそう。費用対効果が高いのはzstd-7、状況によってはzstd-15もなくはないかな。 recordsizeによる圧縮率の変化 ついでに、圧縮はrecordsizeが大きいほど効果的とされているので、その影響も軽く測定。 LZ4とZStandardのそれぞれで、レコードサイズを512kから1Mに変更した時の圧縮後容量の差分を求めたのが下表。 圧縮方法 recsize 圧縮後容量(MiB) 128kとの差分(MiB) 無圧縮容量に占める削減割合 lz4 128k 495251.3 - - 512k 495145.0 -106.3 -0.02% 1M 495251.4 +0.1 +0.00% zstd-7 128k 490354.9 - - 512k 488842.4 -1512.5 -0.29% 1M 487907.2 -2447.7 -0.48% なぜかLZ4のレコードサイズ1MBの時は圧縮率が下がってるけど、概ねレコードサイズが大きくなるほど圧縮率も向上するようだ。割合で見ると微々たるものだが、レコードサイズを変えるだけで恩恵が得られるのはありがたい。実のところ、レコードサイズを大きくすると実データに占めるメタデータ割合(ハッシュの量)が減り、プール容量的にはこちらの影響の方が大きかったりする(参考:ZFSのSpecial vdevを試してみる) とりあえず、互換性を気にしなくていい環境では、lz4の代わりに積極的にzstdを使っていくのが良さそう。可能な限りrecordsizeも大きくしていこう(ただし、FreeBSDはレコードサイズが128k超のファイルシステムからブート出来ない点には注意が必要。) 空き容量0でZFSが壊れた?Input/Output errorが発生→再起動で直った 不注意でProxmox VEのZFSプールを使い切り、空き容量がゼロという状態になってしまった。すべてのデータセットのAVAILが0という本物のゼロである。VMのディスクがthinで図らずもオーバーコミット状態となっており、VM内で物理容量以上のファイルコピーを行ってしまったのが原因。当然ながらVMは固まるわ、PVEもWebコンソールから何もできないわで超焦った…。 幸い物理コンソールは生きていたので、不要なZVOLを消して事なきを得たと思いきや、ファイル操作をするとInput/output errorが起きるようになってしまった。 root@myserver:/etc/pve/nodes/myserver/qemu-server# touch test touch: cannot touch 'test': Input/output error ファイル/ディレクトリの作成、削除がダメ。既存ファイルの読み込みは問題なさそうで、書き込み系がダメっぽい。それもすべての場所でダメというわけではなく、ルートディレクトリ直下は大丈夫だったりする。同じデータセットなのに。 もちろんzpool scrubでエラーが出ないことは確認済み。というわけで実に厄介というかヤバい状況なのであーる。どうすんのこれ… 関係しそうなバグチケ報告もあるにはある。 silent corruption gives input/output error but cannot be detected with scrub, experienced on 0.7.5 and 0.8.3 versions · Issue #10697 · openzfs/zfs · GitHub silent corruption for thousands files gives input/output error but cannot be detected with scrub - at least for openzfs 2.0.0 · Issue #11443 · openzfs/zfs · GitHub が、ほとんど関係ない気がしなくもない。うちはサイレントじゃないし。実は静かに壊れてて今回ので発現した可能性もあるが、ほんの数日前にVM追加してるしちょっと考えにくい。FreeBSDの方では何だかんだ10年ほどZFSを使っているが、データが壊れたのはそれなりに原因が分かっている2回しかない(1回目、2回目)。 容量ゼロをトリガーにLinux側とZFS側で何らかの齟齬が発生し、容量の回復がLinux側に伝わってないとかが原因なら再起動で直りそうなものの、シャットダウンしたが最後、完全に壊れてPVEが立ち上がらなくなる可能性もありそうで恐ろしい。この記事も書いているメイン環境は、そのPVE上で動いているのでPVEの死=メイン環境の死なので慎重にならざるを得ない。 (2021-11-24 追記) 意を決してPVEマシンを再起動してみたら、Input/output errorは出なくなった。何事もなかったようにVMも動いている。 ZFSではCoWの関係上、一般的に空き容量がプール容量の10~20%1)を切ると危険水域とされている。予めプール全体にquotaをかけておけば、今回のようなヤベェ自体は予防できるだろう。 1) 昨今の2桁テラバイト級のプールなら5%程度でも良さそうだが start.txt 最終更新: 2022-07-27 15:26by Decomo