【分析】Ceph数据一致性检查

来源:互联网 发布:腾讯股票数据接口 编辑:程序博客网 时间:2024/04/25 04:28

Scrub的过程大致如下:通过比较对象各个OSD上副本的元数据和数据,来完成源数据和数据的校验。

1.1.1  数据结构

Scrub操作相关的主要数据结构有两个,一个是Scrub控制结构——相当于一次Scrub曹组的上下文,控制一次PG的操作过程。另外是ScrubMap保存需要比较对象的各个副本的元数据和数据的摘要信息。

1.1.1.1     Scrubber

Scrubber结构体用于控制一个PGScrub过程

// -- scrub --

struct Scrubber {

  // metadata

  set<pg_shard_t>reserved_peers; // 资源预约的shard

  bool reserved,reserve_failed; //是否预约资源,预约是否失败

  epoch_tepoch_start;//开始Scrub操作的epoch

 

  // commonto both scrubs

  bool active;//Scrub是否开始

//当PG有snap_trim操作时,如果检查Scrubber处于active状态,说明正在进行Scrub操作,那么snap_trim操作暂停,设置queue_snap_trim的值为true。当PG完成Scrub任务后,如果queue_snap_trim的值为true,就把PG添加到相应的工作队列里,继续完成snap_trim操作

  bool queue_snap_trim;

  int waiting_on;//等待的副本计数

  set<pg_shard_t>waiting_on_whom;//得带的副本

  int shallow_errors;//轻度扫描的错误数

  int deep_errors;//深度扫描的错误数

  int fixed;//已经修复的对象数

  ScrubMapprimary_scrubmap;//主副本的ScrubMap

  map<pg_shard_t,ScrubMap> received_maps;//接收到的从副本的ScrubMap

  OpRequestRefactive_rep_scrub;

  utime_tscrub_reg_stamp;  // stamp we registered for

  // thisflag indicates whether we would like to do auto-repair of the PG or not

  bool auto_repair;//是否自动恢复

 

  // Mapsfrom objects with errors to missing/inconsistent peers

  map<hobject_t, set<pg_shard_t>>missing; //扫描出的缺失对象

  map<hobject_t, set<pg_shard_t>>inconsistent;//扫描出的不一致对象

 

  // Map fromobject with errors to good peers

  //如果所有副本对象中有不一致的对象,记录正确对象所在的osd

  map<hobject_t, list<pair<ScrubMap::object,pg_shard_t> >> authoritative;

 

  // Cleanedmap pending snap metadata scrub

  ScrubMapcleaned_meta_map;

 

  // digestupdates which we are waiting on

  int num_digest_updates_pending;

 

  // chunkyscrub

  hobject_tstart, end;

  eversion_tsubset_last_update;

 

  // chunkyscrub state

  enum State {

    INACTIVE,

    NEW_CHUNK,

    WAIT_PUSHES,

    WAIT_LAST_UPDATE,

    BUILD_MAP,

    WAIT_REPLICAS,

    COMPARE_MAPS,

    WAIT_DIGEST_UPDATES,

    FINISH,

  } state;

 

  std::unique_ptr<Scrub::Store>store;

  // deepscrub

  bool deep;//是否为深度扫描

  uint32_tseed;//计算CRC32校验码的种子

 

  list<Context*>callbacks;

  …

} scrubber;

 

1.1.1.2     ScrubMap

ScrubMap结构体保存准备校验的对象以及相应的校验信息

/*

 * summarizepg contents for purposes of a scrub

 */

struct ScrubMap {

  struct object {

    map<string,bufferptr>attrs;//对象的属性

    uint64_t size;//该对象的大小

    __u32omap_digest;         ///< omapcrc32c

    __u32digest;              ///< datacrc32c

    bool negative:1;

    bool digest_present:1;//是否计算了数据的校验码

    bool omap_digest_present:1;//是否有omap的校验码标志

    bool read_error:1;//读对象数据的错误标志

    bool stat_error:1;//调用stat获取对象元数据时的出错标志

    bool ec_hash_mismatch:1;//

    bool ec_size_mismatch:1;

 

    …

};

内部类object是用来保存对象需要的校验信息。

 

1.1.2  Scrub的控制流程的状态机

Scrub任务的由OSD的工作队列OpWq来完成,调用对应的处理函数pg->scrub(handle)来执行。最终调用PG::chunky_scrub函数控制scrub操作的状态转换和核心处理。

1. Scrubber的初始状态为INACTIVE。

(1) 设置scrubber的参数epoch_start

(2) 设置scrubber.active= true说明已经激活scrub

(3) 设置状态scrubber.status为NEW_CHUNK

(4) 设置scrubber.seed的类型,初始为-1

 

2. Scrubber的状态为NEW_CHUNK的处理。

(1) 通过函数objects_list_partial函数计算对象的边界,方便划界。

(2) 调用函数_range_available_for_scrub检查列表中的对象,是否存在被阻塞的对象,如果存在,则退出本次Scrub

(3) 根据pg_log计算start和end区间对象最大的更新版本号,更新至scrubber.subset_last_update

(4) 调用函数_request_scrub_map()向所有的副本发送消息,获取相应的ScrubMap的校验信息。

(5) 设置状态为WAIT_PUSHES

 

3. Scrubber的状态为WAIT_PUSHES的处理。

(1) 如果active_pushes的值为0,设置状态为WAIT_LAST_UPDATE进入下一个状态处理。

(2) 如果active_pushes的值不为0,说明该PG正在进行Recovery操作,设置done的值为true。在进入chunk_scrub时,PG应该处于CLEAN状态,不可能有Recovery操作(这里的Recovery应该是上次进行的chunky_scrub的修复操作)

 

4. Scrubber的状态为BUILD_MAP的处理。

(1) 调用函数build_scrub_map_chunk构造主OSD上对象的ScrubMap结构

(2) 如果构造成功,计数scrubber.waiting_on的值减1,并从队列中删除scrubber.waiting_on_whom,则相应的状态设置为WAIT_REPLICAS

 

4. Scrubber的状态为WAIT_REPLICAS的处理

(1) 若scrubber.waiting_on不为0,说明replica请求没有应答,设置done=true并退出等待;

(2) 否则,设置状态为COMPARE_MAPS

 

5. Scrubber的状态为COMPARE_MAPS的处理

(1) 调用函数scrub_compare_maps比较各副本的校验信息

(2) 将参数scrubber.start设置为srubber.end

(3) 调用参数requeue_ops,把由于Scrub而阻塞的读写操作重新加入操作队列里执行

(4) 设置状态为WAIT_DIGEST_UPDATES

 

6. Scrubber的状态为COMPARE_MAPS的处理

(1) 如果有scrubber.num_digest_updates_pending等待,等待更新数据的digest或者omap的digest

(2) 如果scrubber.end小于hobject_t::get_max(),本PG还存在没有完成Scrub操作的对象,设置状态scrubber.stat为NEW_CHUNK,继续把PG加入到osd->scrub_wq中

(3) 否则,设置状态为FINISH

 

6. Scrubber的状态为FINISH的处理

(1) 调用函数scrub_finish来设置相关的统计信息,并触发修复不一致的对象

(2) 设置状态为INACTIVE

 

调用函数build_scrub_map_chunk构造主OSD上对象的ScrubMap结构

(2) 如果构造成功,计数scrubber.waiting_on的值减1,并从队列中删除scrubber.waiting_on_whom,则相应的状态设置为WAIT_REPLICAS

 

1.1.3  构建ScrubMap

构建ScrubMap是由多个函数组成:

1. 调用函数build_scrub_map_chunk构建从start到end之间所有对象的校验信息并保存ScrubMap结构体中;

2. 调用函数_scan_snap扫描head对象保存的snap信息和snapset结构体中保存的该对象的snap信息是否一致,以前者保存的snap信息为准,修复snapset中保存的snap对象;

3. 调用函数be_scan_list构建ScrubMap结构体中对象的校验信息

4. 如果需要deep scrub,则调用be_deep_scrub进行深度扫描,获取omap和data的digest信息。

 

1.1.4  从副本处理

当从副本接收到主副本发送来的MOSDRepScrub类型消息时,用于获取对象的校验信息时,就调用函数replica_scrub来完成。

 

 

1.1.5  副本比较

当对象的主副本和从副本都完成了校验信息的构建,并保存在相应的结构体ScrubMap中,接下来,就是对比各个副本的校验信息来完成数据一致性检查。

首先通过对象自身的信息来选出一个权威的对象,然后用权威对象和其他对象来比较和检验。

 

 

1.1.6  结束Scrub

通过函数scrub_finish函数来结束scrub过程,处理流程如下:

1. 设置相关PG的状态和统计信息

2.修复scrubber中标记的missing和inconsistent对象;

3. 触发DoRecovery事件发送给PG的状态机。发起实际对象的修复操作。

 

2  参考文献

1. 百度百科——CAP原则

2. 摘自机械工业出版社《Ceph源码分析》