2009年2月22日日曜日

ZFSはストレージプール(zpool)のデバイス情報をツリー状にGUIDで管理する

ZFSをちまちまと触っていると疑問に思うことがあります。
ストレージプールの移行が妙に柔軟にできるようだが、デバイスの管理はどうやってるんだろう。
 
タイトルでネタばれはせっかちなので仕方ないとして、ZFSの話。
※ここの情報は ZFSの ver.4 ver.10 で確認、特にドキュメントないので変更の可能性は大? 間違ってたり変更があったら是非教えてください。
 
 

実際、ZFSの移行 "zpool export" したデバイスを適当なサーバにつないで "zpool import"すれば、物理デバイス(のパス)がなんであろうがZFSはストレージプールの情報を拾ってきて移行完遂してくれる。
ソースが公開されているので ZFSソースツアー を解読すればきっちりわかるんだろうが生憎と C言語 が読めん。

 
 

物理パス・論理パスと移行前に比べてデタラメでもきっちり自分のZFSを構成するデバイス(ファイル)群を認識する、どう考えても独自になにか付与しているんだろう。

で、どうなってるのか気になっていたところに見つけた情報が

[zfs] どこにも mount されていないのに zfs snapshot が取れない件 < < 気になるもの


 

zdb?そんなコマンド、ZFSの管理ドキュメントにのってないじゃないか、ZFSのデバッグ用らしいが。
 
 


zdb、ZFSデバッグ用のコマンドを使ってメタ情報をがっつり収集


とりあえずファイルをzpoolのデバイスとしてミラーで構築したZFSを作った。わかりやすいようにストレージプルのデバイスは mkfile で作ったファイルにした。
こんな感じだ
    Zpool名:mf01
    ミラー
  • /zdev/mfile01

  • /zdev/mfile02


 


 

で、 zdb を叩いてみる。
$zdb
mf01
version=10
name='mf01'
state=0
txg=4
pool_guid=8209644695030027085
hostid=500812174
hostname='hogehoge.example.com'
vdev_tree
type='root'
id=0
guid=8209644695030027085
children[0]
type='mirror'
id=0
guid=13660030613472834359
metaslab_array=14
metaslab_shift=21
ashift=9
asize=257425408
is_log=0
children[0]
type='file'
id=0
guid=9114859995283150354
path='/zdev/mfile01'
children[1]
type='file'
id=1
guid=8018218252628534999
path='/zdev/mfile02'


おやおやこいつは...
もう「謎は全て解けた」も同然だな。
 
 

guid だね、各デバイスにこのZFSメタ情報を書いておくんだろう。
インポート、ZFSを再構築する際は solaris(OS) が認識したブロックデバイスに対し、片っぱしからZFSのデバイスかどうか調べてguidからツリーに当てはまるようにしているんだろう。
 

guidの付与されるタイミングは ストレージプールに参加するタイミングだろう、それ以外考えられないしそうでないと意味がない。
 
 


検証としてデバイスのパスを変えてみる


ディレクトリを一個作って、zpoolを構成するデバイス(ファイル)のパスを変えてみる、プールは事前に "export" 済み。
 

$cp /zdev/mfile0* /zdev2
$mv /zdev2/mfile01 /zdev2/hogehoge01



これで "zdev2" というディレクトリに名前違いのデバイスコピーができた、"import" でみてみる。

$zpool import -d /zdev2
プール: mf01
ID: 8209644695030027085
状態: ONLINE
アクション: プールの名前または数値識別子を使用してプールをインポートできます。
構成:
 
mf01 ONLINE
mirror ONLINE
/zdev2/hogehoge01 ONLINE
/zdev2/mfile02 ONLINE

 

デバイス名が移行前と全然違うのにONLINEなのが分かる。
インポート後にまた "zdb" で見てみよう

mf01
version=10
name='mf01'
state=0
txg=496
pool_guid=8209644695030027085
hostid=500812174
hostname='hogehoge.example.com'
vdev_tree
type='root'
id=0
guid=8209644695030027085
children[0]
type='mirror'
id=0
guid=13660030613472834359
metaslab_array=14
metaslab_shift=21
ashift=9
asize=257425408
is_log=0
children[0]
type='file'
id=0
guid=9114859995283150354
path='/zdev2/hogehoge01'
children[1]
type='file'
id=1
guid=8018218252628534999
path='/zdev2/mfile02'


ファイル名を変えたデバイスについて、path 要素は更新・GUIDは変わらずと判るだろう。
 
 

ちょっとまとめ


ZFSは事前にエクスポートさえしておけば、ストレージプールを構成するデバイスを全部認識さえさせれば蘇る。としていいんじゃないかな。
 
生前と物理パス・論理パスすらも問わないのでとにかく認識させろ、ということだ。
 
多分エクスポートも不要だが、そこは安全性を考慮してのことで。
これでいろいろとすっきりした。
 
 
 


おまけ:guidだけ、というわけではない


基本的には guid を基準としてデバイスプールが再構築されるんだが、それだけじゃないよという例を。
 

raidz2 のプールを作って、それをエクスポートしてみる。

rz01 ONLINE
raidz2 ONLINE
/zdev/file01 ONLINE
/zdev/file02 ONLINE
/zdev/file03 ONLINE
/zdev/file04 ONLINE
/zdev/file05 ONLINE
/zdev/file06 ONLINE



で、これの "/zdev/file04" だけを "/zdev2/rzhoge04" とコピーして、 "/zdev2/" を対象にインポート調査をしてみよう。
 
あくまで "/zdev2/" のみなので、インポートコマンドは "rzhoge04" しか見ないはずだが...


$zpool import -d /zdev2
プール: rz01
ID: 15179283843329238703
状態: ONLINE
アクション: プールの名前または数値識別子を使用してプールをインポートできます。
構成:
 
rz01 ONLINE
raidz2 ONLINE
/zdev/file01 ONLINE
/zdev/file02 ONLINE
/zdev/file03 ONLINE
/zdev2/rzhoge04 ONLINE
/zdev/file05 ONLINE
/zdev/file06 ONLINE



他の構成要素 "file01-06" もすべてONLINE として認識される。
 

これは "import" がデバイスの認識をするにあたって、

  1. 見えるデバイスがZFSのデバイスか判断して、ZFSデバイスならGUIDをみる

  2. PATHで指定されいるデバイス(ファイル)が存在するか見て、あればGUIDを確認



という事をしているんだろう、周到だ。
 
ちなみに "file04" は存在しているが "rzhoge04" が優先されていることから、やっぱりGUIDを先に認識したものを優先するんだろう。
pathも意味がないわけではないということがわかった。
ついでにZFSのメタデータは全デバイスに保存されてるだろうということが確認できた。
 
 
 

おわりに


どうも zdb も デバイスの guid についても sunのドキュメントにそれらしき記述がない、国内のサイトにも全然情報がない。
アンドキュメンテッドな仕様というやつだったんだろうか、ソース見ればわかるから特に記述してないのか、よくわからないな。
 

その辺から本稿の初期タイトルは「ドキュメントでは教えてくれない、ZFSの秘密」だったんだが、事情もよく知らんし「なんだかびみょう」なのでネタばれ優先のタイトルにした。
 

全デバイスにメタデータ保存・GUID付与してそれを優先に管理というのは色々と理にかなっているなあと感心、「シンプル イズ ザ ベスト」だね。