この記事はRookと仲間たち、クラウドネイティブなストレージの Advent Calendar 2020 4日目の記事です。
お久しぶりです。レッドハットでストレージを中心にクラウドインフラを生業にしている宇都宮です。
去年のアドベントカレンダーぶりかもしれませんね、今年もがんばってやってますので、ストレージ愛が五臓六腑に沁み渡るみなさんのブログを楽しんで下さいね!今日はRookのブログから閑話休題で、CephのMultiSiteについて書いていきます。
あとRookのTwitterアカウント、@japan_rookのフォローお願いしまーす!
サイト障害に耐えるためのサイト間レプリケーション
一般的にオブジェクトストレージサービスはサイト障害に耐えられるよう、バックグラウンドでサイト間レプリケーション等が行われていることが多いと思います。
正直オブジェクトストレージはブロックやファイルと違って、高いパフォーマンスや強い整合性が期待されない (誤解を恐れず言うと、期待してはいけない) ストレージサービスなので、同期のオーバーヘッドを気にすることなくレプリケーションできます。
KubernetesやOpenStack、Proxmox等のプラットフォームのバックエンドストレージとして使われることの多いCephですが、単体ではオブジェクトストレージとして使われているケースが多いです。
Cephでサイト障害に耐えるためのパターンは2つに大別されます。
Stretched Cluster
複数サイトで動くMON/OSD/RGW等のコンポーネントで、1つのCephクラスターを構成するクラスター間レプリケーション/ミラー
各サイトで動く複数のCephクラスター間で、データのレプリケーション/ミラーを構成する
一つ目のStretched Clusterは、運用対象が1つのクラスターなのでシンプルです。
writeの整合性はRADOSが担保するので各サイトActiveで使えるし、RPOも障害直前、RTOも限りなく0でしょう。
ただし、サイト間ネットワークの安定性が命になります。例えばサイト間ネットワークが途切れると、サイトを跨いでreplicated poolを組んでいると全サイトでOSDへの同期が完了できないためwriteが遅くなったり、MON同士の通信ができなくなってクラスター全体の構成が不安定になったりします。
どのサイトも普通に生きているのに、サービスに悪影響を及ぼすリスクがあるというわけです。
うまくCRUSH treeの設計を行うと回避できるかもしれませんが、そうすると構成は複雑になるので運用側が大変になります。
そういった観点からStretched Clusterは実践的には難しく、比較的近距離のサイト間でなら成立する可能性はある、というレベルと考えます。
HW/SDSを問わず、ストレージでサイト障害に対応する方法の多くは、二点目のようなクラスター間でのレプリケーションでしょう。
もちろんこれはこれで考慮点はあります。RPO、RTOはStretched Clusterより長くなるし、Active-ActiveとするかActive-Passiveとするかで切り替え/切り戻しの際にデータを整合性をどう担保するか、などでしょうか。
とは言え、サイト間ネットワークが途切れても、各サイトのクラスターは普通に動くのでサービスへの影響がStretched Clusterよりは俄然低いのは大きなメリットです。
もちろんCephでもクラスター間レプリケーションは可能です。ブロックストレージの場合は "RBD Mirror" と呼ばれる機能で、オブジェクトストレージの場合は、今回のトピックの "MultiSite" と呼ばれる機能です。
Ceph NanoでMultiSiteをやってみよう
Ceph MultiSiteはRGW(Rados Gateway)の機能です。複数のクラスターにあるRGW間でBucketなどを同期することができます。
どうなるものかお見せしたいのですが、Cephのクラスターを立てるのは割と大変です。ですので、今回はCeph Nanoを使ってお見せします。
Ceph Nanoについては去年書いたブログを見て下さい。
Ceph Nanoで2つのCephクラスターを立てて、その間でレプリケーションをするようにしてみます。
同じマシンの上にクラスターを作ってもよいのですが、下図のようなイメージで2つの違うマシンの上でそれぞれ作ってみます。
[root@master ~]$ ./cn cluster start cn1 -f huge 2020/12/03 12:41:16 Running cluster cn1 | image ceph/daemon | flavor huge {4GB Memory, 2 CPU} ... Endpoint: http://10.208.81.35:8000 Dashboard: http://10.208.81.35:5000 Access key: DFE06L7ZSW0CBRHYTIMJ Secret key: BNAi3vAhzyGb0rmnNrJkItQWhqADuydoUELLp7jt Working directory: /usr/share/ceph-nano
[root@secondary ~]$ ./cn cluster start cn2 -f huge 2020/12/03 12:41:36 Running cluster cn2 | image ceph/daemon | flavor huge {4GB Memory, 2 CPU} ... Endpoint: http://10.208.81.18:8000 Dashboard: http://10.208.81.18:5000 Access key: JRLYVCV1XMS0YDXK7AXH Secret key: ta0ikPv6CKj5qOfAyw23MH1aFpsn8AVZRGMQkjNQ Working directory: /usr/share/ceph-nano
Endpointとして8000番ポートが指定されています。
またAccess keyとSecret keyが表示されています。Ceph Nanoは立ち上げると自動的に"nano"というRGWユーザーを作りますが、表示されているのはこのユーザーのものです。 今回は"nano"ユーザーは使わないので、このkeyは無視してもらって大丈夫です。
とりあえずクラスターが2つできました。
Masterでzone, zonegroup, realmを設定
MultiSiteをする際にはzone, zonegroup, realmを設定する必要があります。
zoneはレプリケーションをする最小の単位で、クラスターに存在するRGWはどれか1つのzoneに所属します。zoneは1つのクラスターで作成され、zone内のRGWが管理するbucketはレプリケーションをする対象となります。
zonegroupは名前の通り複数のzoneを束ねたもので、zoneは1つのzonegroupに所属します。zonegroupはクラスターをまたいで組むことができ、クラスター間でzoneの情報を共有します。zonegroup内に存在するzoneの間で、bucketはレプリケーションされます。
realmはzonegroupを束ねるユニークなnamespaceです。
クラスターが複数ありそれぞれレプリケーションする先が異なったり、bucketごとにActive-ActiveとActive-Passiveを使い分けたり、比較的複雑なレプリケーション構成をとりたい場合は、zonegroupやrealmを複数作って制御することができます。 今回は下図のように最もシンプルなパターンで、2 zones -> 1 zonegroup -> 1 realm の関係でいきます。
それではMaster側のクラスターでzone, zonegroup, realmを設定します。包含関係から作成するのはrealmからです。
Ceph Nanoクラスターに入るには、cn cluster enter
で入ることができます。
[root@master cephnano]# ./cn cluster enter cn1 [root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin realm create --rgw-realm=rlm --default { "id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "name": "rlm", "current_period": "332fc423-02fe-427e-85b9-97ffe24f9197", "epoch": 1 } [root@ceph-nano-cn1-faa32aebf00b /]# [root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin zonegroup create --rgw-zonegroup=zg --endpoints=http://10.208.81.35:8000 --rgw-realm=rlm --master --default { "id": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "name": "zg", "api_name": "zg", "is_master": "true", "endpoints": [ "http://10.208.81.35:8000" ], "hostnames": [], "hostnames_s3website": [], "master_zone": "", "zones": [], "placement_targets": [], "default_placement": "", "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "sync_policy": { "groups": [] } } [root@ceph-nano-cn1-faa32aebf00b /]# [root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin zone create --rgw-zonegroup=zg --rgw-zone=z1 --endpoints=http://10.208.81.35:8000 --default { "id": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "name": "z1", "domain_root": "z1.rgw.meta:root", "control_pool": "z1.rgw.control", "gc_pool": "z1.rgw.log:gc", "lc_pool": "z1.rgw.log:lc", "log_pool": "z1.rgw.log", "intent_log_pool": "z1.rgw.log:intent", "usage_log_pool": "z1.rgw.log:usage", "roles_pool": "z1.rgw.meta:roles", "reshard_pool": "z1.rgw.log:reshard", "user_keys_pool": "z1.rgw.meta:users.keys", "user_email_pool": "z1.rgw.meta:users.email", "user_swift_pool": "z1.rgw.meta:users.swift", "user_uid_pool": "z1.rgw.meta:users.uid", "otp_pool": "z1.rgw.otp", "system_key": { "access_key": "", "secret_key": "" }, "placement_pools": [ { "key": "default-placement", "val": { "index_pool": "z1.rgw.buckets.index", "storage_classes": { "STANDARD": { "data_pool": "z1.rgw.buckets.data" } }, "data_extra_pool": "z1.rgw.buckets.non-ec", "index_type": 0 } } ], "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3" }
はい、できました。zonegroup create
とzone create
で--endpoint
のオプションがありますが、ここにRGWのエンドポイントを指定します。
また、Poolについては特段何も指定していませんが、RGWデフォルトのpoolを使っています。実際に使う場合は新規にpoolを切ると思うので、その場合はradosgw-admin zone placement
を使って指定します。
レプリケーション用のsystem userを作成
クラスターをまたいでRGW間でデータやrealm等の構成を共有するために、両者で共通のシステムユーザーが必要となります。
これはMaster側で作って、後でSecondaryからpullすることで共有されます。
このシステムユーザーの名前は何でもよいのですが、作られるAccess keyとSecret keyは重要なのでメモしておきましょう。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin user create --uid="syncuser" --display-name="sync user" --system { "user_id": "syncuser", "display_name": "sync user", "email": "", "suspended": 0, "max_buckets": 1000, "subusers": [], "keys": [ { "user": "syncuser", "access_key": "57ZYN8XHW9V03VYGEG9P", "secret_key": "BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS" } ], "swift_keys": [], "caps": [], "op_mask": "read, write, delete", "system": "true", "default_placement": "", "default_storage_class": "", "placement_tags": [], "bucket_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "user_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "temp_url_keys": [], "type": "rgw", "mfa_ids": [] }
このsyncuser
がMaster側のzoneを操作できるよう、先程作成したzoneにAccess keyとSecret keyの情報を追加します。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin zone modify --rgw-zone=z1 --access-key=57ZYN8XHW9V03VYGEG9P --secret=BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS { "id": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "name": "z1", "domain_root": "z1.rgw.meta:root", "control_pool": "z1.rgw.control", "gc_pool": "z1.rgw.log:gc", "lc_pool": "z1.rgw.log:lc", "log_pool": "z1.rgw.log", "intent_log_pool": "z1.rgw.log:intent", "usage_log_pool": "z1.rgw.log:usage", "roles_pool": "z1.rgw.meta:roles", "reshard_pool": "z1.rgw.log:reshard", "user_keys_pool": "z1.rgw.meta:users.keys", "user_email_pool": "z1.rgw.meta:users.email", "user_swift_pool": "z1.rgw.meta:users.swift", "user_uid_pool": "z1.rgw.meta:users.uid", "otp_pool": "z1.rgw.otp", "system_key": { "access_key": "57ZYN8XHW9V03VYGEG9P", "secret_key": "BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS" }, "placement_pools": [ { "key": "default-placement", "val": { "index_pool": "z1.rgw.buckets.index", "storage_classes": { "STANDARD": { "data_pool": "z1.rgw.buckets.data" } }, "data_extra_pool": "z1.rgw.buckets.non-ec", "index_type": 0 } } ], "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3" }
ここまでできたら概ねMaster側の作業は終わりです。最後にzoneやzonegroup等の構成変更をcommitするべくradosgw-admin period update --commit
をします。periodはrealmが持つ構成変更ログのようなものです。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin period update --commit { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "epoch": 1, "predecessor_uuid": "332fc423-02fe-427e-85b9-97ffe24f9197", "sync_status": [], "period_map": { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "zonegroups": [ { "id": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "name": "zg", "api_name": "zg", "is_master": "true", "endpoints": [ "http://10.208.81.35:8000" ], "hostnames": [], "hostnames_s3website": [], "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "zones": [ { "id": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "name": "z1", "endpoints": [ "http://10.208.81.35:8000" ], "log_meta": "false", "log_data": "false", "bucket_index_max_shards": 11, "read_only": "false", "tier_type": "", "sync_from_all": "true", "sync_from": [], "redirect_zone": "" } ], "placement_targets": [ { "name": "default-placement", "tags": [], "storage_classes": [ "STANDARD" ] } ], "default_placement": "default-placement", "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "sync_policy": { "groups": [] } } ], "short_zone_ids": [ { "key": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "val": 2054423084 } ] }, "master_zonegroup": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "period_config": { "bucket_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "user_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 } }, "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "realm_name": "rlm", "realm_epoch": 2 }
RGWをzone:z1
に所属させることをceph.confの[client.rgw]
セクションに追記して、RGWを再起動します。Ceph Nanoの場合はcn cluster restart
でクラスター再起動をします。
[root@ceph-nano-cn1-faa32aebf00b /]# vi /etc/ceph/ceph.conf [root@ceph-nano-cn1-faa32aebf00b /]# grep -A10 "client.rgw.ceph-nano-cn1" /etc/ceph/ceph.conf [client.rgw.ceph-nano-cn1-faa32aebf00b] rgw dns name = ceph-nano-cn1-faa32aebf00b rgw enable usage log = true rgw usage log tick interval = 1 rgw usage log flush threshold = 1 rgw usage max shards = 32 rgw usage max user shards = 1 log file = /var/log/ceph/client.rgw.ceph-nano-cn1-faa32aebf00b.log rgw frontends = beast endpoint=0.0.0.0:8000 rgw zone = z1 ←追記 [root@ceph-nano-cn1-faa32aebf00b /]# exit exit [root@master cephnano]# ./cn cluster restart cn1 2020/12/03 14:40:37 Restarting cluster cn1...
Secondaryでzone, zonegroup, realmの設定
次にSecondary側でzone, zonegroup, realmを設定します。realmとzonegroupはMasterからpullするだけなので簡単です。pullする時には、Master RGWのendpointとsyncuser
のAccess keyとSecret keyを使います。
[root@secondary cephnano]# ./cn cluster enter cn2 [root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin realm pull --url=http://10.208.81.35:8000 --access-key=57ZYN8XHW9V03VYGEG9P --secret=BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS { "id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "name": "rlm", "current_period": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "epoch": 2 } [root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin period pull --url=http://10.208.81.35:8000 --access-key=57ZYN8XHW9V03VYGEG9P --secret=BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "epoch": 2, "predecessor_uuid": "332fc423-02fe-427e-85b9-97ffe24f9197", "sync_status": [], "period_map": { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "zonegroups": [ { "id": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "name": "zg", "api_name": "zg", "is_master": "true", "endpoints": [ "http://10.208.81.35:8000" ], "hostnames": [], "hostnames_s3website": [], "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "zones": [ { "id": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "name": "z1", "endpoints": [ "http://10.208.81.35:8000" ], "log_meta": "false", "log_data": "false", "bucket_index_max_shards": 11, "read_only": "false", "tier_type": "", "sync_from_all": "true", "sync_from": [], "redirect_zone": "" } ], "placement_targets": [ { "name": "default-placement", "tags": [], "storage_classes": [ "STANDARD" ] } ], "default_placement": "default-placement", "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "sync_policy": { "groups": [] } } ], "short_zone_ids": [ { "key": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "val": 2054423084 } ] }, "master_zonegroup": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "period_config": { "bucket_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "user_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 } }, "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "realm_name": "rlm", "realm_epoch": 2 } [root@ceph-nano-cn2-faa32aebf00b /]# [root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin realm list { "default_info": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "realms": [ "rlm" ] } [root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin zonegroup list { "default_info": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "zonegroups": [ "zg", "default" ] }
radosgw-admin realm list
とradosgw-admin zonegroup list
の結果から、Masterから正しくrealmとzonegroupの情報をpullできていることが分かるはずです。
それではzoneを作成します。Masterと同じように作成しますが、Secondary RGWのエンドポイントを指定し、Access keyとSecret keyはsyncuser
のものを指定します。
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin zone create --rgw-zonegroup=zg --rgw-zone=z2 --endpoints=http://10.208.81.18:8000 --access-key=57ZYN8XHW9V03VYGEG9P --secret=BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS 2020-12-03T05:50:37.846+0000 7fb33d5c81c0 0 failed reading obj info from .rgw.root:zone_info.9b505afe-3229-4b80-8a69-ffbaea14ec25: (2) No such file or directory 2020-12-03T05:50:37.846+0000 7fb33d5c81c0 0 WARNING: could not read zone params for zone id=9b505afe-3229-4b80-8a69-ffbaea14ec25 name=z1 { "id": "ac746b19-c165-453e-abed-3e528c13377a", "name": "z2", "domain_root": "z2.rgw.meta:root", "control_pool": "z2.rgw.control", "gc_pool": "z2.rgw.log:gc", "lc_pool": "z2.rgw.log:lc", "log_pool": "z2.rgw.log", "intent_log_pool": "z2.rgw.log:intent", "usage_log_pool": "z2.rgw.log:usage", "roles_pool": "z2.rgw.meta:roles", "reshard_pool": "z2.rgw.log:reshard", "user_keys_pool": "z2.rgw.meta:users.keys", "user_email_pool": "z2.rgw.meta:users.email", "user_swift_pool": "z2.rgw.meta:users.swift", "user_uid_pool": "z2.rgw.meta:users.uid", "otp_pool": "z2.rgw.otp", "system_key": { "access_key": "57ZYN8XHW9V03VYGEG9P", "secret_key": "BhLuCDHkFRtdbJTvNJCVP7Powzu7aThdm7KDX9vS" }, "placement_pools": [ { "key": "default-placement", "val": { "index_pool": "z2.rgw.buckets.index", "storage_classes": { "STANDARD": { "data_pool": "z2.rgw.buckets.data" } }, "data_extra_pool": "z2.rgw.buckets.non-ec", "index_type": 0 } } ], "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3" }
zone構成が変わったのでperiodのupdateを行い、最後にMasterと同じように、zone:z2
の情報をceph.confに追記して、restartします。
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin period update --commit 2020-12-03T05:53:16.914+0000 7f961cc901c0 1 Cannot find zone id=ac746b19-c165-453e-abed-3e528c13377a (name=z2), switching to local zonegroup configuration Sending period to new master zone 9b505afe-3229-4b80-8a69-ffbaea14ec25 { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "epoch": 3, "predecessor_uuid": "332fc423-02fe-427e-85b9-97ffe24f9197", "sync_status": [], "period_map": { "id": "6f70ae90-de8a-47c3-8e77-2b58532728d5", "zonegroups": [ { "id": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "name": "zg", "api_name": "zg", "is_master": "true", "endpoints": [ "http://10.208.81.35:8000" ], "hostnames": [], "hostnames_s3website": [], "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "zones": [ { "id": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "name": "z1", "endpoints": [ "http://10.208.81.35:8000" ], "log_meta": "false", "log_data": "true", "bucket_index_max_shards": 11, "read_only": "false", "tier_type": "", "sync_from_all": "true", "sync_from": [], "redirect_zone": "" }, { "id": "ac746b19-c165-453e-abed-3e528c13377a", "name": "z2", "endpoints": [ "http://10.208.81.18:8000" ], "log_meta": "false", "log_data": "true", "bucket_index_max_shards": 11, "read_only": "false", "tier_type": "", "sync_from_all": "true", "sync_from": [], "redirect_zone": "" } ], "placement_targets": [ { "name": "default-placement", "tags": [], "storage_classes": [ "STANDARD" ] } ], "default_placement": "default-placement", "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "sync_policy": { "groups": [] } } ], "short_zone_ids": [ { "key": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "val": 2054423084 }, { "key": "ac746b19-c165-453e-abed-3e528c13377a", "val": 1074715361 } ] }, "master_zonegroup": "e2a4ab0d-a871-4aaa-af1e-7be3cd16615e", "master_zone": "9b505afe-3229-4b80-8a69-ffbaea14ec25", "period_config": { "bucket_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "user_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 } }, "realm_id": "e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3", "realm_name": "rlm", "realm_epoch": 2 } [root@ceph-nano-cn2-faa32aebf00b /]# [root@ceph-nano-cn2-faa32aebf00b /]# vi /etc/ceph/ceph.conf [root@ceph-nano-cn2-faa32aebf00b /]# grep -A10 "client.rgw.ceph-nano-cn2" /etc/ceph/ceph.conf [client.rgw.ceph-nano-cn2-faa32aebf00b] rgw dns name = ceph-nano-cn2-faa32aebf00b rgw enable usage log = true rgw usage log tick interval = 1 rgw usage log flush threshold = 1 rgw usage max shards = 32 rgw usage max user shards = 1 log file = /var/log/ceph/client.rgw.ceph-nano-cn2-faa32aebf00b.log rgw frontends = beast endpoint=0.0.0.0:8000 rgw zone = z2 [root@ceph-nano-cn2-faa32aebf00b /]# exit exit [root@secondary cephnano]# ./cn cluster restart cn2 2020/12/03 14:58:44 Restarting cluster cn2...
はい、お疲れさまでした。これでzone間のレプリケーションの設定ができました。MasterとSecondaryの両方に入って、radosgw-admin sync status
を実行してみると同期状況が確認できます。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin sync status realm e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3 (rlm) zonegroup e2a4ab0d-a871-4aaa-af1e-7be3cd16615e (zg) zone 9b505afe-3229-4b80-8a69-ffbaea14ec25 (z1) metadata sync no sync (zone is master) data sync source: ac746b19-c165-453e-abed-3e528c13377a (z2) syncing full sync: 0/128 shards incremental sync: 128/128 shards data is caught up with source
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin sync status realm e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3 (rlm) zonegroup e2a4ab0d-a871-4aaa-af1e-7be3cd16615e (zg) zone ac746b19-c165-453e-abed-3e528c13377a (z2) metadata sync syncing full sync: 0/64 shards incremental sync: 64/64 shards metadata is caught up with master data sync source: 9b505afe-3229-4b80-8a69-ffbaea14ec25 (z1) syncing full sync: 0/128 shards incremental sync: 128/128 shards data is caught up with source
この出力を見ると、それぞれ、data sync source
がお互いのzoneを指定しています。
つまりこれは、z1
側で保存されたオブジェクトはz2
へレプリケーションされ、z2
側で保存されたオブジェクトはz1
へレプリケーションされる、Active-Activeなレプリケーションを意味します。
S3 clientからオブジェクトを置いてみよう
それでは本当にレプリケーションが稼働するのか、クライアントからオブジェクトを保存してみます。
S3 client用のユーザーを作成する
Master側に、先程syncuser
を作ったのと同じように、testuser
というユーザーを作成します。今度はsystem userではないので、--system
オプションはつけません。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin user create --uid="testuser" --display-name="test user" { "user_id": "testuser", "display_name": "test user", "email": "", "suspended": 0, "max_buckets": 1000, "subusers": [], "keys": [ { "user": "testuser", "access_key": "WMJLX79PAZ3M24ZYACX1", "secret_key": "u4ePP8FxhmnHfs83TDQFSEWbC5VoflrnMe3JqExS" } ], "swift_keys": [], "caps": [], "op_mask": "read, write, delete", "default_placement": "", "default_storage_class": "", "placement_tags": [], "bucket_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "user_quota": { "enabled": false, "check_on_raw": false, "max_size": -1, "max_size_kb": 0, "max_objects": -1 }, "temp_url_keys": [], "type": "rgw", "mfa_ids": [] } [root@ceph-nano-cn1-faa32aebf00b /]# [root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin user list [ "syncuser", "testuser" ]
さて、testuser
が作られましたが、Secondaryの方でもradosgw-admin user list
を実行してみましょう。こちらにもtestuser
が同期されているはずです。
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin user list [ "syncuser", "testuser" ]
testuserのkeyを使ってS3 clientでオブジェクトを置く
おまたせしました、それではtestuser
のkeyを使ってbucketを作り、オブジェクトを置いてみます。
S3 clientはなんでもいいのですが、awscliを使ってローカルのファイルをs3 cp
します。
まずはMaster側のRGW(z1)のendpointを指定してbucketを作ります。
[root@s3c ~]# aws configure AWS Access Key ID []: WMJLX79PAZ3M24ZYACX1 AWS Secret Access Key []: u4ePP8FxhmnHfs83TDQFSEWbC5VoflrnMe3JqExS Default region name [None]: Default output format [None]: [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 mb s3://z1-bucket make_bucket: z1-bucket [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 ls 2020-12-03 15:45:23 z1-bucket
MasterとSecondaryの両方でbucketが確認できると思います。これはMaster側で作られたbucketがすぐにSecondaryに同期されているためです。
[root@ceph-nano-cn1-faa32aebf00b /]# radosgw-admin bucket list [ "z1-bucket" ]
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin bucket list [ "z1-bucket" ]
それでは何かしらMaster側にファイルを置いてみましょう。丁度いい具合にRHEL8のISOイメージがあるのでこれを置いてみます。
[root@s3c ~]# ll /mnt/share/rhel-8.2-x86_64-dvd.iso -rw-r--r--. 1 root root 8436842496 8月 12 12:36 /mnt/share/rhel-8.2-x86_64-dvd.iso [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 cp /mnt/share/rhel-8.2-x86_64-dvd.iso s3://z1-bucket/rhel8img upload: ../mnt/share/rhel-8.2-x86_64-dvd.iso to s3://z1-bucket/rhel8img [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 ls s3://z1-bucket 2020-12-03 15:56:44 8436842496 rhel8img [root@s3c ~]# [root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 ls s3://z1-bucket [root@s3c ~]# ...(転送終了後) [root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 ls s3://z1-bucket 2020-12-03 15:56:44 8436842496 rhel8img
s3 cp
が完了すると、すぐにMasterからSecondaryへの転送が始まります。
転送中はSecondaryに対してs3 ls
を実行してもオブジェクトは出てきません。
ブロックストレージのレプリケーションやファイルストレージのコピーとは違い、転送元のストレージに書かれたデータをブロック単位で次々に転送することはありません。転送元にオブジェクトを書き切ってから、転送先にレプリケーションを行います。
転送中のSecondaryマシンでiftopの出力が下の図です。1Gbpsで繋がっているのでMaster(.35)からSecondary(.18)へワイヤースピードに近い速度で転送しています。
転送中は、radosgw-admin sync status
の出力で、xx shards are recovering ; recovering shareds: [XX]
と表示されます。完全に同期したらdata is caught up with source
と表示されます。
[root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin sync status realm e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3 (rlm) zonegroup e2a4ab0d-a871-4aaa-af1e-7be3cd16615e (zg) zone ac746b19-c165-453e-abed-3e528c13377a (z2) metadata sync syncing full sync: 0/64 shards incremental sync: 64/64 shards metadata is caught up with master data sync source: 9b505afe-3229-4b80-8a69-ffbaea14ec25 (z1) syncing full sync: 0/128 shards incremental sync: 128/128 shards 1 shards are recovering recovering shards: [76] ... (同期完了後) ... [root@ceph-nano-cn2-faa32aebf00b /]# radosgw-admin sync status realm e1bd3bc0-9ef8-460a-8d24-cd69ba7e62e3 (rlm) zonegroup e2a4ab0d-a871-4aaa-af1e-7be3cd16615e (zg) zone ac746b19-c165-453e-abed-3e528c13377a (z2) metadata sync syncing full sync: 0/64 shards incremental sync: 64/64 shards metadata is caught up with master data sync source: 9b505afe-3229-4b80-8a69-ffbaea14ec25 (z1) syncing full sync: 0/128 shards incremental sync: 128/128 shards data is caught up with source
これでMaster->Secondaryのレプリケーションはうまくいっていることが分かりました。
それでは反対にSecondary->Masterのレプリケーションを試してみましょう。先程と同様にS3 clientからSeconaryにbucketを作成し、ファイルを置いてみます。
[root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 mb s3://z2-bucket make_bucket: z2-bucket [root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 ls 2020-12-03 15:45:23 z1-bucket 2020-12-03 16:07:00 z2-bucket [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 ls 2020-12-03 15:45:23 z1-bucket 2020-12-03 16:07:00 z2-bucket [root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 cp /mnt/share/rhel-8.2-x86_64-dvd.iso s3://z2-bucket/rhel8img_second upload: ../mnt/share/rhel-8.2-x86_64-dvd.iso to s3://z2-bucket/rhel8img_second [root@s3c ~]# aws --endpoint-url=http://10.208.81.18:8000 s3 ls s3://z2-bucket 2020-12-03 16:21:37 8436842496 rhel8img_second [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 ls s3://z2-bucket ...(転送終了後) [root@s3c ~]# aws --endpoint-url=http://10.208.81.35:8000 s3 ls s3://z2-bucket 2020-12-03 16:21:37 8436842496 rhel8img_second
Master->Secondaryと同じような感じですね。iftopの出力は先程とは反対に、Secondary(.18)からMaster(.35)に転送されている様子が見えます。
基本的にはMultiSiteはこんな感じです
今回はCeph Nanoを使って一番シンプルな構成でCeph MultiSiteを構成してみました。
通常のCephクラスターでも今回の作業と本質的には同じです。RGWの数が増えたり、poolのplacementの設定が変わるだけですので、構成すること自体はそんなに難しいことではありません。
一般的にサイト間レプリケーションでよくある問題は、転送スピードが出ない問題です。転送スピードはサイト間のネットワークに依存するところが大きいのですが、スペック上の帯域幅は分かっていても実際にどれくらいの速度が出るかは、やってみないと正直誰も分かりません。私はおろかネットワーク事業者さんも断言はできないでしょう。
ですので、CephでMultiSiteをやってみようと思っている方は、一旦Ceph Nanoを使ってどれくらいの転送ができるのかを試してみることをお勧めします。
というわけで、今回はここまで。