gmirror四方山(よもやま)話

[ 本ドキュメントは 2026年9月5日 現在の内容です ]
Update: 2026/9/6 20:56

ミラーストレージを構築する前に - 512e 問題

「これは詳細を省くが結論だけ言うと、"1MiBアライメントを取ればいい" と認識しておけ。」
どこぞの洋画のような台詞ですが。

セクター形式って気にしたことあります?

あなたの使っているディスクのセクター形式が 512e ならちょっと気をつけよう。
従来のセクターサイズは 512 byte だったが、4KB セクターをエミュレーションして 512 byte セクターと見せかける "512e 形式" がある。
この場合、4KB セクターの境界を跨ぐとパフォーマンスが非常に悪くなるので、パーティションを切る場合に 4KB 境界のアライメント調整が必要になる。

といっても難しいことではない。
ようは「パーティションを切るときに 4KB セクター単位 (境界) でパーティションを切る」だけで良いのだが、これは gpart の -a 4k オプションで簡単に4KB境界にアライメントさせられる。
ここでは「4KB セクターの境界問題があるのでうかつに境界を跨ぐようなパーティションの切り方をしないように」と憶えておけば良い。

ただ、最近では 4KiB アライメントよりも、SSD や VM の仮想ストレージなどを考慮した 1MiB 境界を対象とした 1MiB アライメントを採用していることが多いようである。
1MiB は 4KiB の整数倍なので、1MiB 境界に合わせておけば 4KiB のアライメントも同時に満たすことができる。

確認方法

非常に面倒臭い話ではあるが、一番確実なのはメーカーの仕様表を見て 512e 対応か否かを確認する。
というのも、OS のコマンドでも確認はできるが、値は OS から見えるセクターサイズなので、稀に物理セクターの情報を正しく取得できないこともある。
(stripesize が 0 なのに、実は 4KB セクターでした、みたいな)

ストレージが接続されているならば diskinfo コマンドで調べられる。

diskinfo -v [デバイス名]
Command:

% diskinfo -v ada1
ada1
        512             # sectorsize
        10737418240     # mediasize in bytes (10G)
        20971520        # mediasize in sectors
        0               # stripesize
        0               # stripeoffset
        22192           # Cylinders according to firmware.
        15              # Heads according to firmware.
        63              # Sectors according to firmware.
        VMware Virtual SATA Hard Drive  # Disk descr.
        01000000000000000001    # Disk ident.
        ahcich1         # Attachment
        No              # TRIM/UNMAP support
        Unknown         # Rotation rate in RPM
        Not_Zoned       # Zone Mode

sectorsize と stripesize に注目。
sectorsize が 512 で stripesize が 4096 の場合は 512e である可能性は高い。
ただし、これだけで 512e と断定はしない方が良い。

ミラーストレージを構築する前に - パーティションを切るか否か

「これは詳細を省くが結論だけ言うと、障害対応を楽にしたいなら生ディスク運用が一番だ。」
どこぞの洋画のような台詞ですが。(2度目

各構成のメリット・デメリット

共通仕様
  • [小さいディスク]+[大きいディスク] を [-小さいディスク] → [+大きいディスク] = [大きいディスク]+[大きいディスク] にしたら小さいディスクの容量のままだが、gmirror resize と growfs で伸長可能。小さいディスクが手に入らない場合は将来の容量増強も考えて、大きめのストレージをスペアディスクとして insert すると良い。
パーティション単位のミラー
  • ○:同一ストレージ上で「このパーティションはミラーするしない」を決められる(特殊すぎでは?
  • ○:使用中のパーティションが既にあるならばそのままミラー構成を組むことが可能
  • ×:障害復旧時に生きている側 (マスター) のパーティションサイズ以上のパーティションを作成する必要がある (=マスターのパーティションサイズを把握する必要有り)
ディスク単位のミラー
  • ○:パーティションを切らずにまるっと全部使用するので、パーティション開始位置に起因する 4KB アライメント問題を避けられる
  • ○:障害復旧時に(ちょっとは考えて欲しいが)何も考えずに「gmirror insert ミラー名 スペアデバイス名」するだけで完了
  • △:初めから生ディスク (Raw disk) 運用している場合は中身を壊さず利用可能。中身がパーティション構成だった場合は残念ですが…。

詳細説明

パーティション単位のミラー

「最近はパーティションを切ってパーティションごとにディスクアレイを構築するのがトレンド」という話はあるが、とりあえずこういうコマンドです。

Command:

% gmirror label -v mirror0 /dev/ada1p1

このように、パーティション単位でディスクアレイを構築すると、現在使用中のパーティションを殺さずにミラーを組むことはできるが、障害発生時にスペアデバイスを insert する前に、生きているディスクと同じパーティション構成のパーティションを作る必要がある。
障害対応という焦りと緊張がある中でその操作は結構シビアである(事前にデータを残している優秀な管理者ならこの限りではない)。

おっと、「ディスク突っ込んで gmirror insert mirror0 [スペアデバイス名] すればいいんじゃない?」と思ったそこの人。これをするとスペアストレージに生きているディスクの「パーティション部分だけ」がミラーされる (パーティション情報など、ディスク全体の構成情報はミラーされない) ので、ディスク全体としての構成が不整合を起こす。
データを残したままミラーを組めることは強力な利点ではあるが、障害対応時の余計なストレスと天秤である。

ディスク単位のミラー

前述のようなストレスから解放されたいならば、ディスク (ストレージ) 全体をミラー対象とした「生ディスク (Raw disk) 運用」が最適解である。
実際に以下のようなコマンドのみで、パーティション情報など他に気にする事なく復旧が可能なので非常にストレスフリー。

Command:

% gmirror insert mirror0 [スペアデバイス名]

ただし、ディスク単位のミラーは、対象のストレージがパーティション構成だった場合はデータを残したままミラーを組めないので注意が必要である。
逆に、初めから生ディスク運用していた場合はデータを残したままミラーを組むことができる。
パーティション構成ならディスク単位でのミラーができない理由は、「GPT パーティション」のセカンダリヘッダーと「gmirror」の末尾メタデータが衝突するためである。

データの書き戻しとリビルドタイミングについて

Q. リビルドは時間がかかるし、データの書き戻しも時間がかかる。どうにかして時間を節約できないか?
A. I/O 負荷に目をつむればデータの書き戻しとリビルドを同時進行しても良い。

手順的には

  1. ミラー構築(片方だけ)
  2. シングルユーザーモードで起動し、ミラーセットをマウント
  3. データの書き戻し開始(rsync など)
  4. ミラーセットにもう1つのストレージを insert
  5. ミラーセットのリビルド開始
  6. データの書き戻しが完了したら問題が無いことを確認し、必要に応じてサービスイン(マルチユーザーモード) ※この時点でリビルドは完了していない
となる。

リビルドとデータの書き戻しが同時進行するので I/O 負荷はかなりのものになるが、その分だけ時間短縮にはなる。

もし I/O 負荷を下げたい、かつリビルド中のサービスインが許容できるのであれば、

  1. ミラー構築(片方だけ)
  2. シングルユーザーモードで起動し、ミラーセットをマウント
  3. データの書き戻し開始(rsync など)
  4. データの書き戻しが完了したら問題が無いことを確認
  5. ミラーセットにもう1つのストレージを insert
  6. ミラーセットのリビルド開始
  7. 状況に応じてサービスイン(マルチユーザーモード)
というように、リビルド中でのサービスインも検討すると良い。

ミラーストレージを構築する

パーティション単位でミラーする場合の事前操作

新規HDDを使うなら以下のようにパーティションを作成する。
もしペアとなるストレージのサイズが違う場合は小さい方をマスターとすること。

Command:

# ada1 の初期化
% gpart destroy -F ada1
% gpart create -s gpt ada1
% gpart add -t freebsd-ufs -a 1m ada1

# 総セクター数を確認 (1MiB アライメント済み)
% gpart show -p ada1
=>      40  20971440    ada1  GPT  (10G)
        40      2008          - free -  (1.0M)
      2048  20967424  ada1p1  freebsd-ufs  (10G) ←今回のターゲット
  20969472      2008          - free -  (1.0M)

# ada2 の初期化
# ** [マスターのパーティションの総セクター数] = /dev/ada1p1 = 20967424
% gpart destroy -F ada2
% gpart create -s gpt ada2
% gpart add -t freebsd-ufs -a 1m -s [マスターのパーティションの総セクター数] ada2
※newfs はミラー組んでから。

以下、パーティションミラー/生ディスクミラー共通操作

/boot/loader.confに追加
Plain text:

geom_mirror_load="YES"
Command:

# gmirrorのカーネルモジュールロード
% sudo kldload geom_mirror.ko

#
# 以下は a / b どちらかを選ぶ。
#
# a. 生ディスクをミラーする場合 (ペアとなるストレージのサイズが違う場合は小さい方をマスターとする)
% sudo gmirror label -v mirror0 /dev/ada1
# b. 既にパーティションができている場合
% sudo gmirror label -v mirror0 /dev/ada1p1

# ** この時点ではミラー構成は 1本だけ。 **
% gmirror status
% gmirror list

# マウントする。
% sudo mount /dev/mirror/mirror0 /mnt
マウント後の確認と追加操作
Command:

# もう 1本つっこむ
# ** (b) の場合は ada2 に初めのディスクと同じ内容のパーティション (ada2p1) を作ること。 **
#
# a. 生ディスクをミラーする場合 (ペアとなるストレージのサイズが違う場合は小さい方をマスターとする)
% sudo gmirror insert -v mirror0 /dev/ada2
# b. 既にパーティションができている場合
% sudo gmirror insert -v mirror0 /dev/ada2p1

% gmirror status
% gmirror list

ストレージの伸長 - 小さいストレージは手に入りづらい/コスパ悪い

ドライブが死んだ!この人でなし!
もう 500GB なんて手に入らない・手に入れたくない!

とお考えのあなた!将来の容量増強も兼ねて大きめのディスクをスペアとして insert しましょう。

gmirror resize / growfs

空き容量については今は間に合っているが、小容量ストレージはコスパが悪く入手難。そして将来は空き容量が足りるかわからない、その時になって容量を増やすのは大変だ。
そこで、スペアとしてマスターとなるストレージよりも容量が大きいストレージを insert することで、将来の容量拡大に備える。

例えば A:10GB + B:10GB のミラーセットがあるとする。
ここで B:10GB が死んだ場合、新ストレージとして C:20GB を insert する。
すると A:10GB を元にして C:20GB にリビルドするが、C:20GB の先頭から A:10GB 分だけリビルドされるので、後半は空白地帯になる。
将来、空き容量が少なくなってきたら、A:10GB を deactivate して新しく D:20GB (もしくはそれ以上の容量) を insert する。
すると C:20GB を元にして D:20GB がリビルドされるが、C:20GB の中身は A:10GB なので、必然的に D:20GB も後半は空白地帯になる。

ここで gmirror resize / growfs の登場となる。

Command:

# 空いてる後半部分を伸長する
% sudo gmirror resize mirror0
# 既にパーティションができている場合
# Device is mounted read-write; resizing will result in temporary write suspension for /mnt.
# などと言われた場合はマウントしたままなので必ずアンマウントしてから実行すること
% sudo growfs /dev/mirror/mirror0
It's strongly recommended to make a backup before growing the file system.
OK to grow filesystem on /dev/mirror/mirror0 from 10GB to 20GB? [yes/no] yes
super-block backups (for fsck_ffs -b #) at:
 21767808, 23048256, 24328704, 25609152, 26889600, 28170048, 29450496,
 30730944, 32011392, 33291840, 34572288, 35852736, 37133184, 38413632,
 39694080, 40974528

これで空白地帯だった部分が伸長されて利用出来るようになる。
この時、もし D:20GB が C:20GB よりも大きい場合は、小さい方に合わせられることになる。
スペアディスクは出来れば容量を大きくした方が爽籟的には良くなるだろう。