网站建设公司投诉电话,手机把网站做成软件有哪些,普通个人简历电子版免费,企业大黄页集群中的设备异常(异常OSD的添加删除操作)#xff0c;会导致PG的各个副本间出现数据的不一致现象#xff0c;这时就需要进行数据的恢复#xff0c;让所有的副本都达到一致的状态。
一、OSD的故障和处理办法#xff1a;
1. OSD的故障种类#xff1a;
故障A#xff1a;一…集群中的设备异常(异常OSD的添加删除操作)会导致PG的各个副本间出现数据的不一致现象这时就需要进行数据的恢复让所有的副本都达到一致的状态。
一、OSD的故障和处理办法
1. OSD的故障种类
故障A一个正常的OSD 因为所在的设备发生异常导致OSD不能正常工作这样OSD超过设定的时间 就会被 out出集群。
故障B 一个正常的OSD因为所在的设备发生异常导致OSD不能正常工作但是在设定的时间内它又可以正常的工作这时会添加会集群中。
2. OSD的故障处理
故障AOSD上所有的PG这些PG就会重新分配副本到其他OSD上。一个PG中包含的object数量是不限制的这时会将PG中所有的object进行复制可能会产生很大的数据复制。
故障BOSD又重新回到PG当中去这时需要判断一下如果OSD能够进行增量恢复则进行增量恢复否则进行全量恢复。增量恢复是指恢复OSD出现异常的期间PG内发生变化的object。全量恢复是指将PG内的全部object进行恢复方法同故障A的处理。
需要全量恢复的操作叫做backfill操作。需要增量恢复的操作叫做recovery操作。
二、概念解析
1.osdmap集群所有osd的集合包括每个osd的ip stateup or down
2.acting set up set每个pg都有这两个集合acting set中保存是该pg所有的副本所在OSD的集合比如acting[0,1,2]就表示这个pg的副本保存在OSD.0 、OSD.1、OSD.2中而且排在第一位的是OSD.0 表示这个OSD.0是PG的primary副本。在通常情况下 up set 与 acting set是相同的。区别不同之处需要先了解pg_temp。
3.Epochosdmap的版本号单调递增osdmap每变化一次加1
4.current_interval past interval一个epoch序列在这个序列内这个PG的acting set没有变化过,current是当前的序列past是指过去的interval。
last_epoch_started上次经过peering后的osdmap版本号epoch。
last_epoch_clean上次经过recovery或者backfill后的osdmap版本号epoch。
注peering结束后数据的恢复操作才刚开始所以last_epoch_started与last_epoch_clean可能存在不同。
例如:
ceph 系统当前的epoch值为20 pg1.0 的 acting set 和 up set 都为[0,1,2] osd.3失效导致了osd map变化epoch变为 21 osd.5失效导致了osd map变化epoch变为 22 osd.6失效导致了osd map变化epoch变为 23
上述三次epoch的变化都不会改变pg1.0的acting set和up set osd.2失效导致了osd map变化epoch变为 24
此时导致pg1.0的acting set 和 up set变为 [0,1,8]若此时 peering过程成功完成则last_epoch_started 为24 osd.12失效导致了osd map变化epoch变为 25
此时如果pg1.0完成了recovery处于clean状态last_epoch_clean就为25 osd13失效导致了osd map变化epoch变为 26
epoch 序列 21,22,23,23 就为pg1.0的past interval
epoch 序列 24,25,26就为 pg1.0的current interval
5.authoritative history完整的pg log操作序列
6.last epoch start上次peering完成的epoch
7.up_thru一个past interval内第一次完成peering的epoch
8.pg_temp : 假设当一个PG的副本数量不够时这时的副本情况为acting/up [1,2]/[1,2]。这时添加一个OSD.3作为PG的副本。经过crush的计算发现这个OSD.3应该为当前PG的primary但是呢这OSD.3上面还没有PG的数据所以无法承担primary所以需要申请一个pg_temp这个pg_temp就还采用OSD.1作为primary此时pg的集合为actingpg_temp的集合为up。当然pg与pg_temp是不一样的所以这时pg的集合变成了[3,1,2]/[1,2,3]。当OSD.3上的数据全部都恢复完成后就变成了[3,1,2]/[3,1,2]。
9.pg_logpg_log是用于恢复数据重要的结构每个pg都有自己的log。对于pg的每一个object操作都记录在pg当中。 __s32 op; 操作的类型 hobject_t soid; 操作的对象 eversion_t version, prior_version, reverting_to; 操作的版本
三、peering具体流程
算法流程图 Peering互为副本的三个(此处为设置的副本个数通常设置为3)pg的元数据达到一致的过程。官方解释如下 the process of bringing all of the OSDs that store a Placement Group (PG) into agreement about the state of all of the objects (and their metadata) in that PG. Note that agreeing on the state does not mean that they all have the latest contents. primary PG和raplica PG 互为副本的三个pg中有一个主另外两个为辅其中为主的称为primary PG其他两个都称为replica PG。
1、peering过程的影响
故障osd重新上线后primary PG和replica PG会进入不同的处理流程。primary PG会先进入peering状态在这个状态的pg暂停处理IO请求在生产环境中表现为集群部分IO不响应甚至某些云主机因为等待IO造成应用无法正常处理。下面就peering过程的主要操作结合源码进行分析。
2、peering过程分析
pg是由boost::statechart实现的状态机peering经历以下主要过程 1、GetInfo:
1.1、选取一个epoch区间对区间内的每个epoch计算其对应的acting set、acting primary、up set、up primary将相同的结果作为一个interval pg-generate_past_intervals(); 调用generate_past_intervals()函数生成past_interval序列。首先确定查找interval的start_epochhistory.last_epoch_clean 上次恢复数据完成的epoch和end_epochhistory.same_interval_since 最近一次interval的起始epoch。确定了start_epoch和end_epoch之后循环这个两个版本间的所有osdmap确定pg成员变化的区间interval。 1.2、判断每个interval将up状态的osd加入到prior set同时将当前的acting set和up set加入到prior set pg-build_prior(prior_set); 据past_interval生成prior set集合。确定prior set集合如果处于当前的acting和up集合中的成员循环遍历past_interval中的每一个intervalinterval.last info.history.last_epoch_started、! interval.acting.empty()、interval.maybe_went_rw在该interval中的acting集合中并且在集群中仍然是up状态的。 1.3、向prior_set中的每个up状态的osd发送Query INFO请求并等待接收应答将接收到的请求保存到peer_info中 context RecoveryMachine ().send_query( peer, pg_query_t(pg_query_t::INFO, it-shard, pg-pg_whoami.shard, pg-info.history, pg-get_osdmap()-get_epoch())); 根据priorset 集合开始获取集合中的所有osd的info。这里会向所有的osd发送请求info的req(PG::RecoveryState::GetInfo::get_infos())。发送请求后等待回复。 1.4、收到最后一个应答后状态机post event到GotInfo状态如果在此期间有一个接收请求的osd down掉这个PG的状态将持续等待直到对应的osd恢复 boost::statechart::result PG::RecoveryState::GetInfo::react(const MNotifyRec infoevt) 回复处理函数。主要调用了pg-proc_replica_info进行处理1.将info放入peerinfo数组中。2.合并history记录。 在这里会等待所有的副本都回复info信息。进入下一个状态GetLog。 2、GetLog
2.1、遍历peer_info查找best info将其作为authoritative log将acting set/peer_info中将处于complete状态的pg以及up set的所有pg存入acting_backfill pg-choose_acting(auth_log_shard, context Peering ().history_les_bound) 通过pg-choose_acting(auth_log_shard)选择acting集合和auth_osd. choose_acting中主要进行了两项重要的措施 find_best_info查找一个最优的osd。在 find_best_info中查找最优的osd时判断的条件的优先级有三个最大的last_update、最小的log_tail、当前的primary。 mappg_shard_t, pg_info_t::const_iterator auth_log_shard find_best_info(all_info, history_les_bound); calc_replicated_acting 选择参与peering、recovering的osd集合。 up集合中的成员。所有的成员都是加入到acting_backfilling中如果是incomplete状态的成员或者 日志衔接不上的成员(cur.last_updateauth.log_tail)则添加到backfill中否则添加到want成员中。 acting集合中的成员该组内的成员不会添加到backfill中所以只需要判断 如果状态是complete并且 日志能够衔接的上则添加到want和acting_backfilling中。 其他prior中的osd成员 处理同acting一致。 经过这一步可知acting_backfilling的成员可用日志恢复数据或者帮助恢复数据的成员backfill的成员只能通过其他的osd上pg的数据进行全量拷贝恢复want的成员同样在acting_backfill中但是不同于backfill的成员。 calc_ec_acting。ceph有两种pool一种是副本类型pool一种是纠删码类型pool类似RAID。具体实现后续补充今天太晚了有空看代码补补。 2.2、如果计算出的authoritative log对应的pg是自身直接post event到GotLog否则向其所在的osd发送Query Log请求 contextRecoveryMachine().send_query( auth_log_shard, pg_query_t( pg_query_t::LOG, auth_log_shard.shard, pg-pg_whoami.shard, request_log_from, pg-info.history, pg-get_osdmap()-get_epoch())); 2.3、接收请求的osd应答并将获取的log merge到本地状态机post event到GetMissing如果收不到应答状态将持续等待 boost::statechart::result PG::RecoveryState::GetLog::react(const GotLog ) { dout(10) leaving GetLog dendl; PG *pg context RecoveryMachine ().pg; if (msg) { dout(10) processing master log dendl; pg-proc_master_log(*contextRecoveryMachine().get_cur_transaction(), msg-info, msg-log, msg-missing, auth_log_shard);//log处理函数 } pg-start_flush( context RecoveryMachine ().get_cur_transaction(), context RecoveryMachine ().get_on_applied_context_list(), context RecoveryMachine ().get_on_safe_context_list()); return transit GetMissing ();//跳转到GetMissing } void PG::proc_master_log( ObjectStore::Transaction t, pg_info_t oinfo, pg_log_t olog, pg_missing_t omissing, pg_shard_t from) { dout(10) proc_master_log for osd. from : olog omissing dendl; assert(!is_peered() is_primary()); // merge log into our own log to build master log. no need to // make any adjustments to their missing map; we are taking their // log to be authoritative (i.e., their entries are by definitely // non-divergent). merge_log(t, oinfo, olog, from);//该函数对log进行合并形成一个权威顺序完整的一个log。包括日志前后的修补而且最重要的是修补的过程中统计了本地副本中需要恢复object的情况missing.add_next_event(ne)。这里已经开始统计missing结构了。 peer_info[from] oinfo;//保存来自best_log的oinfo到本地的peer-info数组中。 dout(10) peer osd. from now oinfo omissing dendl; might_have_unfound.insert(from); // See doc/dev/osd_internals/last_epoch_started if (oinfo.last_epoch_started info.last_epoch_started) { info.last_epoch_started oinfo.last_epoch_started; dirty_info true; } if (info.history.merge(oinfo.history)) //对history信息进行合并。 dirty_info true; assert(cct-_conf-osd_find_best_info_ignore_history_les || info.last_epoch_started info.history.last_epoch_started); peer_missing[from].swap(omissing);//将missing结构统计到本地的peer_missing结构中。 } auth_log一个是auth_log的合并最大最权威的log恢复数据要根据这里进行。 missing另外就是合并log过程中发现本地副本需要恢复的object集合。 omissingauth_osd需要进行恢复的object集合。 3、GetMissing
3.1、遍历acting_backfill向与primary pg log有交集的pg所在的osd发送Query Log请求将剩余没有交集的pg放入peer_missing生成missing set用于后续recovery context RecoveryMachine ().send_query( *i, pg_query_t( pg_query_t::LOG, i-shard, pg-pg_whoami.shard, since, pg-info.history, pg-get_osdmap()-get_epoch())); 3.2、将收到的每一个应答merge到本地如果在此期间有osd down掉这个PG的状态将持续等待收到所有的应答后当前pg的状态机进入Activate状态peering过程结束 boost::statechart::result PG::RecoveryState::GetMissing::react(const MLogRec logevt) { PG *pg context RecoveryMachine ().pg; peer_missing_requested.erase(logevt.from); pg-proc_replica_log(*contextRecoveryMachine().get_cur_transaction(), logevt.msg-info, logevt.msg-log, logevt.msg-missing, logevt.from);//接收到其他osd发回的log信息并且进行处理。在proc_replica_log中对peer_log进行修剪丢弃那些不完整不可用的log。整理接收到的oinfo到peerinfo中omissing到peer_missing中。直接来到active状态。 if (peer_missing_requested.empty()) { if (pg-need_up_thru) { dout(10) still need up_thru update before going active dendl; post_event(NeedUpThru()); } else { dout(10) Got last missing, dont need missing posting Activate dendl; post_event(Activate(pg-get_osdmap()-get_epoch())); } } return discard_event(); } 3、总结
从以上分析来看整个peering过程主要分为三个阶段GetInfo - GetLog - GetMissing首先向prior set、acting set、up set中的每个osd请求pg infos, 选出authoritative log对应的pg其次向authoritative log所在的osd请求authoritative log最后获取recovery过程需要的missing set
peering时间的长短并不可控主要是在于请求的osd是否能够及时响应如果这个阶段某个osd down掉很可能导致部分pg一直处在peering状态即所有分布到这个pg上的IO都会阻塞。 此文仅讲述了peering过程peering之后还会进行recovery操作recovery操作由处理线程直接调用函数void OSD::do_recovery(PG *pg, ThreadPool::TPHandle handle)进行后续再总结总结recovery过程和PG的状态机。
先附两张PG状态机的类型以及流程图 参考资料
作者一只小江 http://my.oschina.net/u/2460844/blog/596895
作者王松波 https://www.ustack.com/blog/ceph%EF%BC%8Dpg-peering/
作者刘世民Sammy Liu 理解 OpenStack Ceph 2Ceph 的物理和逻辑结构 [Ceph Architecture] - SammyLiu - 博客园
作者常涛 ceph 源代码分析 — peering 过程_ceph peering_Jack-changtao的博客-CSDN博客
感谢以上作者无私的分享。