Rgw 利用multisite的bucket Sync Disable特性实现集群扩容
一. 前言
ceph 号称可以无限度的扩容,但是扩容带来的代价非常大,PG分裂,主机的添加等造成的数据重新平衡,会导致大量的数据迁移,影响业务的稳定,甚至是暂时的不可用
二. 扩容的几个方案
1.单个集群中直接扩展osd,通过增加PG达到扩容的目的,这种方案在集群数量不大的情况下可以采取,因为意味着需要迁移大量的数据。
2.通过crush规则,将新加入的osd组成一个独立的role,指定role新建pool,然后将bucket的placement 指定为新建的pool的方式可以进行扩容,这个方案不会有数据的迁移,但是主要麻烦的地方是客户端需要再请求的时候指定placement。
3.有没有更优秀的方案呢? 有的,以多个小集群的方式进行扩容,集群之间没有关联性,客户端记录指定集群写入,这一个方案比第二种方案的优势在于多个小集群,可以提升高可用性,缺点跟第二种一样需要记录写入的集群,而且需要在每个集群都创建相同的用户元数据信息,当小集群多的时候管理会比较麻烦,这也是我们当前线上环境使用的方案
4.我们知道rgw multisize 可以实现异地多活,zone 与zone之间会同步data和metadata,但是这里有个特性就是,用户可以手动的禁止bucket数据的data同步,只同步metadata,这个时候我们就可以利用这个特性进行扩容了。
三. 扩容的整体架构思想
这里要实践的方案是第四种扩容方案,通过 bucket sync diable特性禁止zone之间的bucket数据同步,而metadata同步不受限制来实现,这里感谢Ceph中国社区创始人之一:秦牧羊,这个方案是根据秦牧羊在2018年杭州沙龙《基于ceph构建PB级对象存储实践-JD金融》PPT的实践。(PPT可以在参考文档获取)
分享中的整个的实现架构如上,在HTTP路由层通过bucket名字将不同bucket请求转发到指定的zone。这里主要分析bucket sync disable这个特性。其他处理层,查阅一下PPT的实现,ceph层面主要有两个要注意的,就是multisite中metadata数据只能从master同步到其他zone,所以像用户的创建,bucket的权限设置等操作,需要在master zone去做
1. 测试bucket sync disable 特性
这里使用的是Rgw Multisite异地多活的方案实践这篇博文的环境,multisite的搭建这里就不多加描述了。
a) 在master zone新建一个bucket: test2
[root@df-vm-01 ~]# s3cmd mb s3://test2
b) bucket disable sync
[root@df-vm-02 ~]# radosgw-admin bucket sync disable --bucket=test2
c) 查看test1 和 test2 的同步状态
// bucket test1 [root@df-vm-02 ~]# radosgw-admin bucket sync status --bucket=test1 realm 2d40b603-356c-4730-a5f8-336260e3ed4c (movies) zonegroup 3f4b9246-be0d-4e4e-913a-9edf77d96f8d (gz) zone 71e02920-7412-44ea-adba-5426c9058397 (gz-zone1) bucket test1[71e02920-7412-44ea-adba-5426c9058397.104180.1] source zone 1d8df413-c398-4e2c-9646-a92f603d1d8e (gz-zone2) full sync: 0/1 shards incremental sync: 1/1 shards bucket is caught up with source // bucket test2 [root@df-vm-02 ~]# radosgw-admin bucket sync status --bucket=test2 realm 2d40b603-356c-4730-a5f8-336260e3ed4c (movies) zonegroup 3f4b9246-be0d-4e4e-913a-9edf77d96f8d (gz) zone 71e02920-7412-44ea-adba-5426c9058397 (gz-zone1) bucket test2[71e02920-7412-44ea-adba-5426c9058397.104185.1] Sync is disabled for bucket test2
可以看到这里bucket test2禁止了数据同步
d) 从master zone 上传数据到bucket test2
[root@df-vm-01 ~]# s3cmd put test.100M.gz s3://test2
这里查看一下test2 数据是否会同步
// master zone1 [root@df-vm-02 ~]# radosgw-admin bucket limit check { "bucket": "test2", "tenant": "", "num_objects": 1, "num_shards": 0, "objects_per_shard": 1, "fill_status": "OK" } // secondly zone [root@df-vm-05 ~]# radosgw-admin bucket limit check { "bucket": "test2", "tenant": "", "num_objects": 0, "num_shards": 0, "objects_per_shard": 0, "fill_status": "OK" }
可以看到,master zone 里面test2 bucket是有一个对象的,secondly zone 里面是没有的,disable sync 生效
2. disable|enable sync特性的实现方式
这里研究一下disable sync的这个特性,这个特性的来历是这样的,GitHub上有个developer提了一个需求,需要禁止指定的bucket同步的,最后自己实现了,提交了代码,最后官方合并了这个PR. PR地址 rgw multisite: feature of bucket sync enable/disable #15801
a) 实现的方式是在bucket info中添加flags,数据同步前检测flags,如果存在 disable_sync flag 就不同步这个bucket的数据。
查看一下,disable 前后,bucket info的变化
disable 前
######### 找到test2的元数据对象 ########## [root@df-vm-05 ~]# radosgw-admin metadata list bucket.instance [ "test1:71e02920-7412-44ea-adba-5426c9058397.104180.1", "test2:71e02920-7412-44ea-adba-5426c9058397.104185.1" ] ######## 查看test2元数据对象的信息 ####### [root@df-vm-05 ~]# radosgw-admin metadata get bucket.instance:test2:71e02920-7412-44ea-adba-5426c9058397.104185.1 { "key": "bucket.instance:test2:71e02920-7412-44ea-adba-5426c9058397.104185.1", "ver": { "tag": "_mfQunYdgIoWHKAUYntXiNDq", "ver": 1 }, "mtime": "2018-12-10 04:34:14.336351Z", "data": { "bucket_info": { "bucket": { "name": "test2", "marker": "71e02920-7412-44ea-adba-5426c9058397.104185.1", "bucket_id": "71e02920-7412-44ea-adba-5426c9058397.104185.1", "tenant": "", "explicit_placement": { "data_pool": "", "data_extra_pool": "", "index_pool": "" } }, "creation_time": "2018-12-10 04:34:14.302615Z", "owner": "tupu-user1", "flags": 0, // 注意这个flag "zonegroup": "3f4b9246-be0d-4e4e-913a-9edf77d96f8d", . . // 太长了省略掉 . } }
disable 后
################ bucket test2 禁止同步后 ########### [root@df-vm-05 ~]# radosgw-admin metadata get bucket.instance:test2:71e02920-7412-44ea-adba-5426c9058397.104185.1 { "key": "bucket.instance:test2:71e02920-7412-44ea-adba-5426c9058397.104185.1", "ver": { "tag": "_mfQunYdgIoWHKAUYntXiNDq", "ver": 2 }, "mtime": "2018-12-10 04:43:58.721170Z", "data": { "bucket_info": { "bucket": { "name": "test2", "marker": "71e02920-7412-44ea-adba-5426c9058397.104185.1", "bucket_id": "71e02920-7412-44ea-adba-5426c9058397.104185.1", "tenant": "", "explicit_placement": { "data_pool": "", "data_extra_pool": "", "index_pool": "" } }, "creation_time": "2018-12-10 04:34:14.302615Z", "owner": "tupu-user1", "flags": 8, // 注意这个flag "zonegroup": "3f4b9246-be0d-4e4e-913a-9edf77d96f8d", "placement_rule": "default-placement", . . // 太长了省略掉 . }
可以看到,disable前后flags 从0 变为了8
b). disable sync 整个过程中做了什么
从 radosgw-admin 入手,代码 ==https://github.com/ceph/ceph/blob/v12.2.8/src/rgw/rgw_admin.cc line 622-639==
if (prev_prev_cmd && strcmp(prev_prev_cmd, "bucket") == 0) { // 指令如果是bucket if (strcmp(prev_cmd, "sync") == 0) { // 指令如果是bucket sync if (strcmp(cmd, "status") == 0) return OPT_BUCKET_SYNC_STATUS; if (strcmp(cmd, "markers") == 0) return OPT_BUCKET_SYNC_MARKERS; if (strcmp(cmd, "init") == 0) return OPT_BUCKET_SYNC_INIT; if (strcmp(cmd, "run") == 0) return OPT_BUCKET_SYNC_RUN; if (strcmp(cmd, "disable") == 0) // 指令如果是bucket sync disable return OPT_BUCKET_SYNC_DISABLE; // 返回 OPT_BUCKET_SYNC_DISABLE if (strcmp(cmd, "enable") == 0) return OPT_BUCKET_SYNC_ENABLE; } else if ((strcmp(prev_cmd, "limit") == 0) && (strcmp(cmd, "check") == 0)) { return OPT_BUCKET_LIMIT_CHECK; }
从这里可以看到,检测到 disable 会返回 OPT_BUCKET_SYNC_DISABLE
==rgw_admin.cc line 1529 - 1533==
if (opt_cmd == OPT_BUCKET_SYNC_ENABLE) { bucket_info.flags &= ~BUCKET_DATASYNC_DISABLED; } else if (opt_cmd == OPT_BUCKET_SYNC_DISABLE) { // 如果选项返回为 OPT_BUCKET_SYNC_DISABLE bucket_info.flags |= BUCKET_DATASYNC_DISABLED; // flags 先跟BUCKET_DATASYNC_DISABLED做二进制或运算然后赋值给flags }
这里我们需要找到 BUCKET_DATASYNC_DISABLED 的值
代码 ==https://github.com/ceph/ceph/blob/v12.2.8/src/rgw/rgw_common.h line 1165 - 1170==
enum RGWBucketFlags { BUCKET_SUSPENDED = 0x1, BUCKET_VERSIONED = 0x2, BUCKET_VERSIONS_SUSPENDED = 0x4, BUCKET_DATASYNC_DISABLED = 0X8, // BUCKET_DATASYNC_DISABLED 等于 8 }; // line 1189 - 1203 struct RGWBucketInfo { enum BIShardsHashType { MOD = 0 }; rgw_bucket bucket; rgw_user owner; uint32_t flags; // bucket flag string zonegroup; ceph::real_time creation_time; string placement_rule; bool has_instance_obj; RGWObjVersionTracker objv_tracker; /* we don't need to serialize this, for runtime tracking */ obj_version ep_objv; /* entry point object version, for runtime tracking only */ RGWQuotaInfo quota;
到这里就很明确了,flags 8 就代表disable sync
四. 总结
整个扩容方案的思想是
- 通过多个小集群(zone)的设计,人为的控制数据落入集群中的位置
- 利用 multisite zone之间同步metadata的特性,让元数据同步到所有zone中,做到元数据的统一管理
- 利用 bucket sync disble 的特性,禁止data数据同步,达到扩容的目的