带你读《存储漫谈Ceph原理与实践》第三章接入层3.2对象存储RGW(五)

3.2.5   元数据/数据同步

CephRGW的多数据中心(Multisite)机制用于实现多个 Ceph  对象存储集群之间的元数据、数据同步。

1.  元数据同步

 

(1)多数据中心简介

Ceph 的多数据中心有如下几个概念:Realm、ZoneGroup、Zone,如图 3-31所示。

 


 

 带你读《存储漫谈Ceph原理与实践》第三章接入层3.2对象存储RGW(五)

 

 

图 3-31 多数据中、示意

 

每个 Realm 都为一个独立的命名空间,桶名在所在命名空间内是唯一的,即一旦在某个 Realm下创建了桶A,则 A这个名字就被使用了,在该 Realm 下其他人就无法创建出名字为A的桶。

一个 Realm下可以有多个 ZoneGroup。顾名思义,每个ZoneGroup可以对应多个Zone,即 ZoneGroup是一组 Zone的集合,Zone之间同步数据和元数据。

 

通常一个 Zone为多台服务器组成的一个 Ceph集群,由一组 RGW 对外提供服务,一个集群上部署多个 RGW网关,以对请求进行负载均衡。

在一个 Realm下的多个 ZoneGroup中, 必须有一个 MasterZoneGroup,MasterZoneGroup中必须有一个 MasterZone,在 MasterZoneGroup下的 MasterZone中执行用户的创建、删除、修改操作会记录一些日志信息(MDlog),这些日志信息被克隆到其他 ZoneGroup下的 Zone中,其他Zone中的 RGW网关依照日志信息从 MasterZoneGroup 下的 MasterZone 中已配置的 endpoints 拉取元数据信息并执行相应操作。

在 Ceph的配置中有以下几个参数与多数据中心机制相关,分别为 rgw_realm、rgw_zonegroup、rgw_zone。一旦设置好这 3 个参数并启动 RGW网关,RGW就会默认到.rgw.root下寻找相应的 Realm、ZoneGroup、Zone 信息,如果无法找到则启动失败。用户也可以通过修改参数rgw_realm_root_pool、rgw_zonegroup_root_pool、rgw_zone_root_pool 的配置值,来告诉RGW网关到指定的存储池下读取 Realm、ZoneGroup、Zone 等信息。默认情况下,一个Realm下的不同ZoneGroup之间只会进行元数据同步,元数据包括

用户信息、bucket、bucket.instance信息。RGW实例在启动时,会启动 RGWMetaSync-

ProcessorThread 线程进行多数据中心元数据的同步服务。

一个新的ZoneGroup加入已存在的Realm 时,会执行全量同步,完成全量同步后就会进入增量同步阶段。在此阶段,新加入的 ZoneGroup下的Zone内的 RGW网关每隔 20s

通过 INCREMENTAL_INTERVAL参数配置到 MasterZoneGroup中拉取日志信息MDlog。在增量同步阶段,每隔 20s执行如下动作。

1)  查询请求带上 marker参数发送到MasterZoneGroup,查询是否有新增的MDlog,如果有,则拉取新增的MDlog到本地集群;

2)  读取保存在本集群的新增的 MDlog并处理,按照 MDlog记录信息发送读取元数据请求到 MasterZoneGroup;

3)保存从 MasterZoneGroup 读取到的元数据信息到本地集群;4)更新 marker参数。

(2) MDLog简介

Mdlog为 MasterZoneGroup上的RGW网关记录, 日志信息记录在 Log池下的meta.log.PERIOD.SHARD_ID对象的 OMAP上,shard_id默认为 0~31。

以下命令可查询第 0个 shard上的 omapkey,key为 1_开头,后面带记录 Log的时间戳。

 

#rados -p zgp2-z1.rgw.log listomapkeys meta.log.315d0473-9ff8-4828-83fd-96fdc36ed618.01_1598684563.695864_0.1

 

也可以使用radosgw-admin命令查看MDlog日志信息的状态,状态信息中有marker和 last_update的时间信息,marker记录上次同步的位置,last_update记录上次同步的时间。

 

#radosgw-admin mdlog status[

{

"marker": "1_1598768113.971442_11.1""last_update":"2020-08-3006:15:13.971442Z"

}

]

 

status信息保存在 Log池下的 RADOS 对象中,可通过如下命令进行查询。

 

 

#rados -p zgp2-z1.rgw.log lsmdlog.sync-status.shard.0mdlog.sync-status

 

当主数据中心没有元数据更新记录到MDlog时,以下是从主数据中心拉取 MDlog请求时没有新 MDlog返回的请求和响应。

 

GET/admin/log?type=metadata&id=0&period=315d0473-9ff8-4828-83fd-

96fdc36ed618&max-entries=100&marker=当前的 marker&rgwx-zonegroup=7085627f-27f8-

4779-9552-ebdd13c265e2HTTP/1.1

 

HTTP/1.1200 OK

Content-Length:44

 

{

"marker":""

"entries": []"truncated":false

}

 

当主数据中心有元数据更新记录到MDlog时,以下是从主数据中心拉取 MDlog请求时有新 MDlog返回的请求和响应。

 

GET/admin/log?type=metadata&id=0&period=315d0473-9ff8-4828-83fd-

96fdc36ed618&max-entries=100&marker当前的marker&rgwx-zonegroup=7085627f-27f8-

4779-9552-ebdd13c265e2HTTP/1.1

 

HTTP/1.1200 OK

Content-Length:598

 

{

"marker":"1_1598774754.303770_13.1"

"entries":[

{

 

...

}


"timestamp":"2020-08-3008:05:54.234410256Z"

"section":"user"

"data": {

"status": {

"status":"write"

 

如果从主数据中心拉取 MDlog请求时有新的 MDlog返回,发起拉取请求的 RGW则进入 MDlog的处理流程,即发送新的获取元数据请求到 MasterZoneGroup去拉取新的信息覆盖本地旧的元数据信息。如下为在MasterZoneGroup中创建一个用户后,非MasterZoneGroup向 MasterZoneGroup的网关发起的拉取用户信息的请求。

GET/admin/metadata/user/user001?key=user001&rgwx-zonegroup=abcHTTP/1.1

 

HTTP/1.1200 OK

Content-Length:713

 

{

"data": {


...


"default_storage_class": """keys": [

{



}

]

...

}


"access_key":""

"secret_key":""

"user":"user001"


 

拉取到新的用户信息写入本地集群后,更新marker参数,这样在下一个20s时带上该 Marker参数,就会只返回本Zone没有的 MDlog,对处理过的 MDlog就不会返回,从而实现了元数据的增量更新。

RGW 进程只有同时满足如下条件,才会进行MDlog的记录。

◆  rgw_zonegroup为 MasterZoneGroup。

◆  当前的ZoneGroup内的Zone个数多于1个或者当前Realm下的ZoneGroup多于1个。

(3)  示例:非主数据中心创建桶

用户信息在 MasterZoneGroup中创建后通过MDlog的方式同步到其他 ZoneGroup下所有的 Zone中,例如非 MasterZoneGroup下的某个RGW 网关接收到创建桶的请求,该 RGW网关会将请求转发到 MasterZoneGroup的网关处理。

 

voidRGWCreateBucket::execute()

{

...

if (!store->svc.zone->is_meta_master()) {JSONParserjp;

op_ret=forward_request_to_master(s NULLstore in_data&jp);

...

}

 

如果主数据中心创建失败例如主数据中心没有该用户,该用户在非MasterZoneGroup中创建,则创建桶失败。因此所有用户必须在MasterZoneGroup中创建,并通过 MDlog同步到其他数据中心,用户的修改和删除也必须在 MasterZoneGroup执行。如果 MasterZoneGroup成功返回转发创建桶的请求,则继续执行剩余的创建桶流程,将 bucketinfo保存到本数据中心的RADOS。MasterZoneGroup接收到该创建桶的请求后,其下的RGW也会执行 RGWCreateBucket::execute()。由于它是主数据中心,同时也会记录 MDlog,在元数据同步线程中 MDlog会克隆到其他ZoneGroup,所有的ZoneGroup下都会保存该 bucketinfo信息,例如 MasterZoneGroup为 beijing1,创建桶的请求发到ZoneGroup为beijing2的 RGW网关,这个请求会被beijing2 的RGW网关转发到 beijng1的RGW网关,同时 MDlog信息会被同步到beijing2、guangzhou1、hunan1等所有 ZoneGroup。在创建好桶之后,如果向这个桶上传数据,则需要将上传数据请求发到ZoneGroup为beijing2的 RGW网关。如果上传请求发到ZoneGroup 为guangzhou1的 RGW网关,guangzhou1的 RGW网关会返回301 状态码,表明请求所访问的桶不在本数据中心。

对于其他桶的元数据操作,大部分的请求会被转发到MasterZoneGroup,例如删除桶、设置桶的静态网站、设置桶的多版本控制、设置桶的桶策略、设置桶的   ACL、设置桶的生命周期规则、设置桶的跨域访问配置等。

2.  数据同步

 

Ceph 的数据同步是指在多数据中心不同Zone 之间同步用户上传的文件数据。

可以将实体数据的同步分为 个部分:记录日志、数据更新通知以及数据更新。下面分别介绍。

(1)记录日志

在对数据进行操作时比如上传、删除等操作,RGW会记录一些日志信息,为之后的实体数据同步服务。日志主要分两部分。

◆ bucketindexlog:在更新 bucketindex、设置 olh(objectlogicalhead,对象逻辑头)时会记录该日志,包含了对象、操作类型等信息;

◆  datalog:记录发生变化的 bucketshard 等信息。

在进行同步时,依据 datalog,可以知道哪些 bucketshard 发生了数据的变化。而通过bucketindexlog,则可以对对应的对象进行操作。比如,indexlog中记录的是add操作,就会从 SourceZone 获取具体的对象,如果是 remove 操作,就会把相应的对象删除。

(2)数据更新通知

与元数据同步类似,实体数据的同步同样拥有一个线程周期性地进行数据更新通知。

◆  初始化

实体数据的更新通知由 RGWDataNotifier线程负责。它的初始化以及启动都是在RGWRados的初始化函数中。

data_notifier = new RGWDataNotifier(this);data_notifier->start();

 

◆  运行

在被启动之后,每隔一段时间(由 rgw_md_notify_interval_msec配置,默认 200ms)

会进行数据更新通知,将记录在datalog中发生变化的 shard发送到其他 Zone。其他Zone在接收到更新通知后,会唤醒相应的数据同步线程。

(3)数据更新

为了与不同的 Zone进行实体数据的同步,RGW 会启动单独的同步线程。

◆  初始化

数据同步线程的初始化,同样在 RGW 的初始化中,数据同步线程可能会有多个。对于需要进行数据同步的Zone,都会启动一个线程来专门负责从该Zone 获取同步数据。

◆  运行

同步线程启动之后,会开始调用 RGWDataSyncProcessorThread的 process来对数据进行处理,其主要流程如下。

1)  从 RADOS中读取 datasyncstatus,以及各个 Logshard的 syncmarker。如果是第一次同步,RADOS 中还不存在这些信息,会先对 status 进行初始化。

2)  datasyncstatus共 有 3种 状 态, 即 StateInit、StateBuildingFullSyncMaps、StateSync。依据状态的不同,会执行不同的操作。

a)StateInit:该状态下,会执行一些同步的初始化操作,例如,往LogPool 中写入sync_status对象,从远端获取各个 Logshard的 syncmarker写入LogPool,将 sync_status设置为 StateBuildingFullSyncMaps等。

b)StateBuildingFullSyncMaps:该状态下,会从远端获取所有的 bucket 信息。之后,会以 bucket  shard为单位,将所有需要同步的bucketshard写入 OMAP中,并更新 Logshard的同步 marker,最后将状态置为StateSync。

c)StateSync:该状态即为正常的同步状态,在进行同步时,以 Logshard为单位,对每一个 Logshard进行数据同步操作。

3)  在对某个 Logshard进行数据同步时,依据Logshard的 syncmarker来判断执行全量还是增量同步。同样,在执行过一次全量同步后,之后执行的就是增量同步了。

4)  在每一个 Logshard中,包含了多个条目,每一个条目是一个bucketshard信息。对 Logshard的同步,实际上就是遍历并同步这些bucketshard。

5) 同步 bucketshard过程中有不同的状态。依据不同的状态,来依次执行初始化、全量同步以及增量同步。同样,初始化与全量同步只会执行一次,之后便是增量同步。为   了同步 bucketshard,RGW会从对端Zone的RGW获取该bucketshard的bucketindexlog,并依据这些 Log,最终决定是从远端获取实体对象,还是从本地删除对象,或者进行其他的操作,此时才会涉及真正的实体数据的操作。

(4)删除日志

如果不删除日志,则随着时间的增加,日志会越来越大。因此,RGW每隔一段时间都会删除已经同步完成的数据日志。间隔时间由rgw_sync_log_trim_interval确定,默认是1200s。在进行日志删除时,需要从各个 Zone获取数据同步状态信息,并根据这些信息, 判断出哪些日志已经被同步完成了,并将其从RADOS中删除。

(5)总结

从实体数据同步过程中可以看到涉及多种同步状态的判断。之所以有这么多的状态,   是因为 RGW 在进行数据同步时,将其在逻辑上分成了多个层级。我们可以将同步的层级分成如下4个层次。

1)Zone级别

该层级表示了与某个 Zone 的同步状态,表征该层级的同步状态由下面的结构给出。

struct rgw_data_sync_info {enum SyncState {StateInit = 0

StateBuildingFullSyncMaps=1

StateSync = 2

};

uint16_t state;uint32_tnum_shards;

rgw_data_sync_info():state((int)StateInit)num_shards(0){}

}

 

2)Logshard级别

记录数据变化时会将日志分成多个   Log,从而在数据量较大时,获得较好的性能。下面是表示 Logshard层级的同步状态结构。

struct rgw_data_sync_marker {enum SyncState {

FullSync = 0

IncrementalSync= 1

};

uint16_t state;stringmarker;

string next_step_marker;uint64_t total_entries;uint64_tpos;

real_timetimestamp;

rgw_data_sync_marker():state(FullSync)total_entries(0)pos(0){}

}

 

3)bucketshard级别

默认情况下,bucketshard大小为 0。但为了让单个容器可以承载更多的对象,不得不以牺牲 list对象的性能为代价,增大bucketshard的值。目前在线上环境中,该值通常都不配置为 0。因此,我们可以认为,每个bucket实际上都存在多个 shard,各自承载着部分对象。而在同步过程中,每一个 bucketshard都归属于某个 Logshard。对于logshard的同步,实际上就是对其下的各个 bucketshard进行同步。

4)对象级别

在每一个 bucketshard中都保存了很多对象, 同步 bucketshard,就是同步其下面的这些对象。该层级涉及对实体数据的操作,并且也是同步过程中的最底层(不考虑RADOS),没有专门的结构来保存同步信息。

3.  小结

 

因为 Multisite是一个Zone层面的功能处理机制,所以默认情况下是 Zone级的数据同步,即配置了Multisite之后,整个 Zone中的数据都会被同步处理。

整个Zone 层面的数据同步,操作粒度过于粗糙,在很多场景下都是非常不适用的。当前,CephRGW还支持通过bucketsyncenable/disable来启用/禁用存储桶级的数据同步,操作粒度更细,灵活度也更高。

上一篇:初始设置时如何给交换机(模块)设密码


下一篇:Javascript评估用户输入密码的强度