はじめに
普段はVMwareやLinuxなどのインフラ環境を触っているのですが、仕事でProxmox上のCephを構築する機会がありました。
手順通りに動かすこと自体はできたんですが、いざVMのディスクとして使いはじめてから「あれ、これって中で何が起きてるんだ?」という疑問が出てきて。特にOSDが複数台あるのに、どうやってどのOSDに書き込むか決めてるのかが全然わからなくて気になっていました。
そこで自分なりに調べてみたのですが、完全に理解できたとは言い難いので、「こう理解したけど合ってる?」くらいの温度感で読んでもらえると助かります。
今回構築したのはProxmox上のCeph
Ceph単体ではなく、Proxmox VEに統合されたCephです。
ProxmoxはWebUIからOSDの追加やPool作成をGUIでできるので、手順通りにやればわりとすんなり動きます。ただ、UIが整いすぎていて「なぜこの設定が必要なのか」を考えずに進められてしまうんですよね。構築が終わったあと、ceph statusを眺めながら「MONって何個いるんだ?」「PGってなんだ?」と疑問が次々と出てきました。
今回はその疑問を起点に調べたことをまとめます。RBDをProxmoxのストレージとして登録してVMディスクに使うまでの手順は別の記事にしたいと思っています。
そもそもCephとは?
汎用のx86サーバー群をネットワークで束ねて、巨大な一つのストレージプールを作るOSSの分散ストレージです。以下の3種類のストレージを単一クラスタで提供できるらしいです。
| ストレージ種別 | 用途 |
|---|---|
| ブロックストレージ(RBD) | 仮想マシンのディスク等 |
| オブジェクトストレージ(RGW) | S3互換API経由でのデータ保存 |
| ファイルシステム(CephFS) | 共有ファイルシステム |
今回使ったのはRBDだけで、RGWやCephFSは正直まだよくわかっていません。
AWS S3/EBSとどう違うのか
「S3互換API」という言葉が出てきたので気になって調べてみたのですが、そもそも比較の仕方が難しくて最初は混乱しました。「AWSはサービスで、Cephは基盤」という話はよく出てくるんですが、技術的にどう違うのかが知りたくて。
調べた範囲だと、一番大きな違いはデータの保存先をどうやって決めるかのようです。
S3はデータの所在を中央のメタデータ管理層が把握していて、クライアントのリクエストをそこへルーティングしているらしいです。Cephは後述するCRUSHアルゴリズムでクライアント自身が保存先を計算して直接OSDに書きに行くとのこと。この差がスケールしやすさに効いてくるようなのですが、そこの詳細はまだ追いきれていません。
あとCephはレプリカ数やFault Domainの設定(ホスト単位で分離するかラック単位にするか等)を自分で決められるようです。柔軟な分、設計が必要で、ProxmoxのUIでデフォルトのまま作ったPoolがどういう設定になっているのかも、後で確認しようと思っています。
Cephの内部構造
Cephを構成する主なデーモンは以下のとおりです。ceph statusの出力を見ながら「このmon、mgr、osdってそれぞれ何をしているんだ」と思って調べました。
| デーモン | 役割 |
|---|---|
| OSD(Object Storage Daemon) | 実際にデータを保存する。原則1ディスク = 1 OSD。OSD同士が直接通信してレプリケーションや障害復旧を自律的に行う |
| MON(Monitor) | クラスタの「状態マップ」を管理する。どのOSDが生きているかを監視するが、データのやり取りには介在しない |
| MGR(Manager) | パフォーマンス指標や空き容量を収集し、外部ダッシュボード等に提供する |
| MDS(Metadata Server) | CephFSを使う場合のみ必要。ファイルシステムのメタデータを管理する |
MONがデータの読み書きに介在しないというのが最初ピンとこなくて、「じゃあMONって何のためにいるんだ」と思ったんですが、クラスタ全体の状態を把握して管理するのがMONで、実際のデータはOSD同士でやり取りするという役割分担らしいです。
CRUSHアルゴリズム
調べていて一番「へえ」となったのがこれです。
一般的なストレージは「どのデータがどのディスクにあるか」を中央のコントローラーが管理しています。データ量が増えるとその検索がボトルネックになるそうで、Cephはそれを解決するために中央管理をやめたらしいです。
代わりにどうするかというと、クライアント側がCRUSHアルゴリズムで保存先OSDを計算して、直接書きに行く仕組みになっているとのこと。
クライアント → CRUSHで保存先を計算 → 対象OSDに直接アクセス
ノードを追加するたびにCRUSHマップが更新されてデータが再配置されるので、台数を増やすほど性能と容量が伸びていく設計らしいです。実際にノードを追加したときのリバランスがどんな挙動をするのかは、まだ見たことがないので気になっています。
CRUSHマップの書き方やチューニングは調べてみたものの、正直まだ全然わかっていないです。
書き込みはこういう流れ(たぶん)
調べた範囲ではおおむねこういう流れのようです。
1. クライアントがMONからCluster Mapを取得する
2. CRUSHアルゴリズムで書き込み先のPrimary OSDを計算する
3. Primary OSDにデータを書き込む
4. Primary OSDがReplica OSDへコピーする
5. 全レプリカへの書き込み完了後、クライアントにACKを返す
「たぶん」とつけたのは、ProxmoxのUIからVMディスクの書き込みをしたときにこの流れが本当に起きているのかを実際のログで確認できていないからです。ceph osd perfとかで見えるのかな、と思っているのですが、そこはまだ試せていません。
まとめというか今後やりたいこと
- OSD・MON・MGRの役割分担と、CRUSHによる計算でボトルネックなくスケールする設計、というのが今回の収穫
- CRUSHマップとPlacement Groupはまだほぼわかっていない
- ProxmoxのデフォルトPool設定が実際どういう値になっているか確認したい
- ノードをわざと落としてリバランスとOSDの自律復旧をログで見てみたい
「動かすことはできた」から「中で何が起きているかわかる」までの距離がまだまだ遠いなと感じています。