Ceph RGW multisite代码实现
multisite代码中大量使用了Boost的协程,在了解协程的使用方法后,整体代码结构还是比较清晰的。
协程实现
rgw中的协程库使用的是boost库,boost库中corotuine实现原理是由基类保存函数当前执行位置,每次运行时根据switch判断要执行的位置,具体可参考asio/coroutine.hpp
。
一次同步操作是由多个RGWCoroutine
实例完成,每个RGWCoroutine
作为一个基础的op由一个RGWCoroutineStack
管理,一个stack内会有多个op,但只有最新加入的op能获得执行机会,op执行完成后会被移除出stack队列,进而stack中下一个op获得执行机会。一个RGWCoroutineManager
实例分层管理多个stack集合,最新层stack集合中的每个stack都有同等运行机会,一次RGWCoroutineManger::run()
方法会新建一层stack集合,直到集合中的所有stack(即stack中的全部op)执行完毕后返回。一个op调用另一个op有两种方式:call
和spawn
。call
方法在当前op隶属的stack上加入新的op,直到新op执行完后才会继续执行自己的代码;spawn
方法会将新的op放到新建的stack中,新stack会被放到manager的当前层(最新层),从而两个op能并发执行(由于stack是顺序遍历的,所以两个op也是顺序执行的)。
rgw中的协程设计每个coroutine op都要实现自己的
operate()
方法,manager在遍历stack list时会调用RGWCoroutine::operate()
,一般情况下operate()
方法结束时会调用set_cr_error()
或set_cr_done()
表示op已经完成,但对于RGWMetaSyncShardCR
等op,operate()
返回时并没有设置完成标志,因此这个op会一直执行(重复被调用operate()
方法),其parent也会一直处于waiting_for_child状态。
同步实现
multisite的功能是实现一个zone group内多个zone的数据同步。这里的数据被分成了两类:
- meta data同步。包括bucket相关对象和user相关对象(user.uid namespace 下的uid信息和root namespace下的bucket以及bucket-instance信息),位于
.rgw.meta
pool中。元数据同步可以类比为手动在本地zone创建bucket和user。 - data同步。即每个bucket下的对象。data数据同步可以类比为手动在本地上传/删除bucket下的对象。
启动rgw 实例时在RGWRados::initialize()
中会启动相关的同步组件。对于meta data,每个rgw启动一个单独线程来执行同步,而对于data数据的同步,由于每个zone都需要向其他所有zone进行同步,因此会启动n-1个同步线程,每个线程负责本地到另外一个zone的同步。
meta data的同步
目的: 将rgw.meta
pool下的bucket对象,bucket-instance对象以及uid对象拷贝到本地,且为每个bucket创建shard对象。
辅助结构:
.rgw.log pool
中的mdlog.sync-status
对象存储本zone当前的元数据同步状态。
.rgw.log pool
中的mdlog.sync-status.<shard>
对象存储每个shard当前同步进度(用marker表示)。
.rgw.log pool
中的meta.full-sync.index.<shard>
对象用omap来存储从master zone的.rgw.meta
pool拉取的数据(pool下的对象名, full-sync时使用)
.rgw.log pool
中的meta.log.<period>.<shardid>
对象用omap来存储元数据操作log,比如创建bucket时,master zone的对象上会增加一条log记录,slave zone从master zone来获取这些记录,从而得到需要从master拉取的数据的列表(bucket名字),然后对bucket元数据做同步。这种同步方式属于incremental-sync。
代码实现
metasync流程RGWRemoteMetaLog::run_sync()data的同步
目的:将每个bucket下的对象拷贝到本地bucket下
辅助结构:
.rgw.log pool
中的datalog.sync-status.<zone>
对象存储本zone到目标zone当前的数据同步状态。
.rgw.log pool
中的datalog.sync-status.<zone>.<shard>
对象存储本zone到目标zone当前的数据同步进度。
.rgw.log pool
中的data.full-sync.index.<zone>.<shard>
对象的omap用来存储从目标zone的拉取的bucket-info信息
.rgw.log pool
中的data_log.<shard>
对象的omap中存放对象操作日志。当对bucket进行对象操作时,会在omap上新建一条"1_"+<timestamp> 开头的日志,表明这个bucket被修改过,增量同步时会根据这些日志判断出哪些bucket被更改过,进而再针对每个bucket进行同步。
.rgw.log pool
中的bucket.sync-status.<src-zone>:<[tenant/][bucket-name:][bucket-id:][bucket-shard]>使用xattr存放对应bucket的同步状态
bucket shard对象omap中0x80+"0_"命名空间下的key记录了此bucket的对象操作日志,用于增量同步时使用。
代码实现:
data数据同步 一个bucket的同步过程注意:
当zone之间的sync 网络不可用时,每个zone是可以本地操作上传和删除对象的。在网络恢复后,各个zone最后存在的版本将是modify-time最新的那次上传的版本。网络故障期间如果有个别zone执行了del操作,即使操作时间是最新的,此次del操作最终会被其他put操作覆盖掉。如果多个put操作的modify-time相同且文件内容不同,则按照short_zone_id
大小比较(代码实现见obj_time_weight::operator<
)。