Ceph Recovery分析
来源:互联网 发布:双十一淘宝实时营业额 编辑:程序博客网 时间:2024/06/04 17:42
当PG完成了Peering过程后,处于Active状态的PG就已经可以对外提供服务了。如果该PG的各个副本上有不一致的对象,就需要进行修复。Ceph的修复过程有两种:Recovery和Backfill,
这里我们讨论Recovery的过程。Peering的过程在代码实现上是通过Boost状态机在各种状态下触发各种事件来执行相应的行为。PG完成Peering过程后,就处于activate状态,
如果需要Recovery,就产生DoRecovery事件,触发修复操作。
2.相关变量及函数
整个recovery过程比较复杂,我将代码中比较常见的一些变量和函数进行补充说明,以后逐渐完善
- peer_missing:每个osd需要恢复的object集合 ,保存在peer_missing结构中。
- needs_recovery_map:本次recovery过程所有需要恢复的object,保存在needs_recovery_map中。
- missing_loc:这些需要恢复的object可以从哪些osd上拉取数据,保存在 missing_loc结构中。
- clone_overlap:保存本次clone对象和上次clone对象(或者head对象)的overlap的部分,也就是重叠的部分。
head对象:也就是对象的原始对象,该对象可以进行写操作。
snap对象:对某个对象做快照后,通过cow机制copy出来的快照对象只能读,不能写。
- snap_seq或者seq:快照序号,每次做snapshot操作系统都分配一个相应快照序号,该快照序号在后面的写操作中发挥重要作用。
- snapdir对象:当head对象被删除后,仍然有snap和clone对象,系统自动创建一个snapdir对象,来保存SnapSet信息
- ObjectContext可以说是对象在内存中的一个管理类,保存了一个对象的上下文信息
RecoveryHandle: 同一组消息中恢复多个对象的一个结构体。
- clone_overlap:写操作导致的和最新的克隆对象重叠的部分
- interval_set:区间集合,一般由多对(start,len)区间集合构成。
- insert,intersection_of,union_of,用于对interval_set类型变量进行插入,求交集,并集。
- encode:ceph中的序列化基本步骤:选获取源目标的大小,将大小先序列化到bufferlist中(整型除外), 然后再把真实数据追加到bufferlist中
- decode: 反序列化。
3.线程池与工作队列
线程池ThreadPool的实现符合生产者-消费者模型,这个模型解除生产者消费者间的耦合关系,生产者可以专注处理制造产品的逻辑而不用关心产品的消费。Thread类是ThreadPool中的消费者,
它封装pthread API函数,对外提供Thread::entry()作为线程的入口函数。Thread只是对消费者的抽象,WorkThread才是ThreadPool的具体消费者,
它实现Thread接口函数,设置线程的入口函数为ThreadPool的worker()方法。WorkQueue_类在ThreadPool中代表产品接口,对外表现为一个队列,队列中存储待处理的数据元素。
消费者WorkThread对它的处理主要分成三个步骤:首先调用_void_dequeue()方法获取队列元素,然后通过_void_process()方法处理元素,最后使用_void_process_finish()方法进行收尾工作。
具体调用过程可以参看WorkTread的线程入口函数,也就是ThreadPool::work()方法。
4. Ceph PGQueable
PGQueable类使用了boost的variant类型去定义了成员变量 qvariant,variant类型支持多种方式访问,其中一种就是通过访问者模式来访问。
使用的boost库中的结构:boost::variant boost::static_visitor boost::optional boost::apply_visitor。
内部结构体 RunVis继承了boost::static_visitor,实现一个variant实例的访问器,且重载了不同类型的函数调用方法"()"
比如Recovery过程实现的重载操作符函数为:void PGQueueable::RunVis::operator()(const PGRecovery &op),该函数通过调用do_recovery()方法,进入到Recovery过程。
5.Bufferlist及序列化
Ceph中bufferlist的设计还是有些复杂的,其中包含三个主要的内buffer::raw(bufferraw)、 buffer::ptr(bufferptr)和buffer::list(bufferlist)。这三个类都定义在common/buffer.h 中,
都是buffer类的内部类,而buffer类本身没有任何内容,只起到了一个命名空间的作用。
这三个类的职责各有不同:
buffer::raw:对应一段真实的物理内存,负责维护这段物理内存的引用计数nref和释放操作。
buffer::ptr:对应Ceph中的一段被使用的内存,也就是某个bufferraw的一部分或者全部。
buffer::list:表示一个ptr的列表(std::list),相当于将N个ptr构成一个更大的虚拟的连续内存。
常用集合数据类型的序列化已经由Ceph实现,位于include/encoding.h中,包括以下集合类型:
- pair, triple
- list, set, vector, map, multimap
- hash_map, hash_set
- deque
- 在类型内部现实encode方法,
- 将类型内部的encode方法重定义为全局方法。
6.Recovery 流程
状态机进入Recoverying状态,将PGRecovery Op入ShardOpWq队列,当线程池中的线程取出一个任务出来后,
其工作队列的线程池的处理函数
process()
调用qi->run(osd, pg, tp_handle)函数,而该run函数实际上封装了boost::apply_visitor()方法,该方法可以获取原始的PGRecovery对象,
由于该对象重载了()操作符,该操作符会调用do_recovery()方法来执行实际的数据修复操作。接着调用ReplicatedPG::start_recovery_ops()开始recovery操作。
- 获取主osd上的missing 统计结果。
- 获取主osd上缺失并且需要恢复的object数量。
- 获取定位缺失数据中 缺少数据源的object数量。
- 如果 主osd上丢失的object 数量 与 无法定位数据源的object数量相同。也就是主osd上丢失的object暂时无法恢复。
- 开始先恢复replicas osd上的数据。
- 直到 replicas osd上数据全都恢复完毕,或者无数据可以恢复时。
- 开始进行 primary osd上的数据恢复。
- 如果前面两项都进行了数据恢复,但是仍然有object没有被恢复,则再次恢复replicas上缺失的object。
上面进行了三次恢复的操作,第一次恢复replicas副本,第二次恢复primary 副本,第三次恢复replicas副本。
如上所述start_recovery_ops函数会调用recovery_primary及recovery_replicas来修复主从副本。recovery_primary会检查所有OSD是否拥有该版本的对象,
如果有就加入到missing_loc记录该版本的位置信息,由后续修复继续来完成。同时会调用pgbackend->run_recovery_op()将PullOp信息或者PushOp信息封装的消息通过
send_push或者send_pulles发送给相关的OSD。当主OSD把对象推送给缺失该对象的从OSD后,从OSD将上述接受到的PUshOP信息通过调用函数handle_push来实现
数据写入工作,从而来完成该对象的修复。当主OSD给从OSD发起拉取对象的请求来修复自己缺失的对象时,将上述接受到的PullOp信息通过调用函数handle_pulls来进行对象的修复。
整个rocovery过程的流程图大致如下三幅图所示:
- Ceph Recovery分析
- ceph recovery 参数调研
- 记录一次ceph recovery经历
- recovery分析
- Recovery分析
- Ceph 源代码分析 -librados
- ceph 故障分析(backfill_toofull)
- Ceph OSD日志分析
- ceph osdmap crush 分析
- Ceph BackoffThrottle分析
- ceph总体架构分析
- Ceph配置参数分析
- ceph osd heartbeat 分析
- 【分析】Ceph:RGW基本原理
- 【分析】Ceph系统架构
- 【分析】Ceph数据一致性检查
- 【分析】Ceph数据一致性检查
- 【分析】Ceph数据一致性检查
- 【Kafka源码】Kafka启动过程
- ActiveMQ入门到精通4-消息持久化到Mysql
- mysql中文乱码解决
- 浅谈oracle树状结构层级查询
- EasyDarwin搭建rtsp服务器
- Ceph Recovery分析
- lightoj 1018
- 储存过程中创建uuid方法
- Gson教程五(译):Sets的映射
- 顺序栈与链式栈的实现
- vue Input
- 上传本地项目到GitLab
- 对刷机包的system.img修改,然后重新打包
- 微信H5支付,获取用户真实ip