Proxmox VE + Ceph:OSD を consumer SSD から enterprise SAS SSD へ無停止で入れ替える

consumer SSD が引き起こす BLUESTORE_SLOW_OP_ALERT を根治するため、稼働中の VM を止めずに OSD を enterprise SAS SSD へ総入れ替えした話。移行手順と、作業中にハマった Ceph の挙動(CRUSH weight・mclock・autoscaler)を紹介します。

導入背景

convivialnet 自前の Proxmox VE クラスタ(3 ノード、Ceph 19.2.3 Squid)で、OSD に consumer SSD(WD Green SSD / SanDisk SSD PLUS)を使っていたところ、以下の警告が恒常的に出ていた。

health: HEALTH_WARN
        6 OSD(s) experiencing slow operations in BlueStore
        1 OSD(s) experiencing stalled read in db device of BlueFS

SMART 上は全本 Reallocated_Sector_Ct=0 で物理的には健全だが、Ceph の BlueStore は WAL やメタデータの書き込みに O_DSYNC(同期書き込み)を多用する。DRAM キャッシュと PLP(Power Loss Protection)を持たない consumer SSD は、書き込みのたびに NAND への焼き込み完了を待つためスループットが低く、これが slow op として顕在化していた。

根本解決のため、ヤフオクで調達した HGST HUSMM814(enterprise 12G SAS SSD・PLP 付き) へ全面移行することにした。中古品だが SMART の摩耗指標(Percentage used endurance)は全本 3〜6% と低く、enterprise SSD の耐久性の高さを改めて実感した。

構成

項目 内容
Hypervisor Proxmox VE 9.1.4
Ceph 19.2.3 (Squid)
ノード構成 3 ノード(hv-pve01/02/03)
旧 OSD WD Green SSD / SanDisk SSD PLUS 2 本/ノード(計 6 本・2TB)
新 OSD HGST HUSMM814 3 本/ノード(計 9 本・400GB)
pool 設定 replicated, size=3, min_size=2, failure-domain=host
実データ 約 480 GiB

移行前後の OSD 構成(各 host 共通):

[Before]  host pve01            [After]  host pve01
          ├ osd.0  consumer 2TB          ├ osd.6  HGST 400G
          └ osd.1  consumer 2TB          ├ osd.7  HGST 400G
                                         └ osd.8  HGST 400G
          (pve02 / pve03 も同様)         (pve02 / pve03 も同様)

移行手順

新 OSD をすべて投入してから旧 OSD を一括 out する。これによりデータ移動を「旧 → 新」の一回に集約できる。failure-domain=hostsize=3 のため、移行中も各 PG の冗長性は維持される。

flowchart LR
  A["新OSD作成<br/>pveceph osd create"] --> B["旧OSD out<br/>ceph osd out"]
  B --> C["リバランス待機<br/>active+clean まで"]
  C --> D["CRUSH weight 0<br/>crush reweight 0"]
  D --> E["safe-to-destroy 確認"]
  E --> F["purge"]

1. 新 OSD の作成

各ノードで対象デバイスをシリアルで照合してから OSD 化する(lsblk -dno NAME,SERIAL で確認)。

pveceph osd create /dev/sdX

2. 旧 OSD の out

ceph osd out 0 1 2 3 4 5

in な OSD が新 OSD のみになり、データの再配置が始まる。

3. リバランスの待機

ceph -s で全 PG が active+clean、misplaced が 0 になるまで待つ。Squid の既定 osd_mclock_profile = balanced は client I/O を優先して recovery を絞るため、移行中は high_recovery_ops に切り替えると速度が出る。

ceph config set osd osd_mclock_profile high_recovery_ops
# 完了後に戻す
ceph config rm osd osd_mclock_profile

4. CRUSH weight の 0 化

out だけでは CRUSH の配置計算から除外されない(後述)。drain 後に CRUSH weight を 0 にする。

for i in 0 1 2 3 4 5; do ceph osd crush reweight osd.$i 0; done

5. safe-to-destroy の確認と purge

ceph osd safe-to-destroy osd.0 osd.1 osd.2 osd.3 osd.4 osd.5
systemctl stop ceph-osd@N          # 対象 OSD のあるノードで
ceph osd purge N --yes-i-really-mean-it

6. 検証

ceph -s              # HEALTH_OK
ceph health detail   # slow op / stalled read アラートが消えていること
ceph osd tree        # 新 OSD のみ・各 host に均等

移行前後の性能比較

移行完了後、空いた consumer SSD を別 device class(cheapssd)の Ceph プール drivepool として再構成し、HGST の vmpool と実測比較した。各プールに RBD イメージ(replica 3)を作成し、fio で計測している。

指標 vmpool(HGST・PLP 有) drivepool(consumer SSD・PLP 無)
4K randwrite IOPS(avg) 14,425 479(初動 1,804 → 131 へ急落)
4K randwrite BW 56.4 MB/s 1.9 MB/s
4K randwrite latency avg / max 1.1 ms / 54 ms 33 ms / 565 ms
4MB seq write BW 747 MB/s 58.7 MB/s(最大 latency 7.5 s)
4K randread IOPS(avg) 45,720 — ※

※ drivepool の read はサンプル不足のため参考値外。

consumer SSD の 4K ランダムライトは計測開始 1 秒目こそ約 1,800 IOPS のバーストを示すが、その後 131 IOPS まで急落し平均 479 IOPS に留まった。SLC write cache を使い切った後に NAND 直書きへフォールバックする典型的なパターンで、BlueStore の O_DSYNC が継続する負荷ではこれがそのまま slow op になる。enterprise SSD との差は約 30 倍だった。

ハマりどころ

out しても safe-to-destroy にならない

ceph osd out で reweight を 0 にしても、CRUSH weight(配置計算上の重み)は残る。旧 OSD(2TB, weight 1.819)が新 OSD(400GB, weight 0.364)より weight が大きいため、CRUSH が配置計算で旧 OSD を優先的に選んでしまい、reweight=0 で弾かれ続けて 3 つ目の replica が埋まらない状態になった。

PG    UP          ACTING
4.1   [14,10]p14  [14,10,0]p14   # UP が 2 つ、ACTING 末尾に旧 osd.0 が残る

ceph osd crush reweight 0 で配置計算から完全に除外すると解消した。out(一時退避)と crush reweight 0(構成変更)は別レイヤーなので、複数 OSD を long-term で out する場合は crush reweight まで必要になる。

リバランスが終わらない

新 OSD 追加に伴い autoscaler が pg_num を段階的に引き上げた(vmpool: 32 → 256)。PG が split されるたびに misplaced が増えるため「減っているのに終わらない」ように見えた。ceph osd pool autoscale-statusNEW PG_NUM 列が空になれば pg_num は確定なので、それ以降は単調に減少する。

balancer は止めない

移行中に upmap balancer を停止したところ、out した OSD からの退避が止まって remapped が固定された。balancer は退避にも寄与しているため、移行中は on のままにしておく必要がある。

おわりに

consumer SSD で Ceph を組むと slow op が出やすい。enterprise SSD(PLP 付き)への換装で HEALTH_OK になり、4K randwrite IOPS は約 30 倍改善した。ヤフオクの中古 enterprise SSD でも摩耗が低ければ十分実用的で、コストパフォーマンスは高い。

この記事の著者

ゆっぷりん