Ceph源码解析:PG peering

news2025/1/22 21:02:39

集群中的设备异常(异常OSD的添加删除操作),会导致PG的各个副本间出现数据的不一致现象,这时就需要进行数据的恢复,让所有的副本都达到一致的状态。

一、OSD的故障和处理办法:

1. OSD的故障种类:

故障A:一个正常的OSD 因为所在的设备发生异常,导致OSD不能正常工作,这样OSD超过设定的时间 就会被 out出集群。

故障B: 一个正常的OSD因为所在的设备发生异常,导致OSD不能正常工作,但是在设定的时间内,它又可以正常的工作,这时会添加会集群中。

2. OSD的故障处理:

故障A:OSD上所有的PG,这些PG就会重新分配副本到其他OSD上。一个PG中包含的object数量是不限制的,这时会将PG中所有的object进行复制,可能会产生很大的数据复制。

故障B:OSD又重新回到PG当中去,这时需要判断一下,如果OSD能够进行增量恢复则进行增量恢复,否则进行全量恢复。(增量恢复:是指恢复OSD出现异常的期间,PG内发生变化的object。全量恢复:是指将PG内的全部object进行恢复,方法同故障A的处理)。

需要全量恢复的操作叫做backfill操作。需要增量恢复的操作叫做recovery操作。

二、概念解析:

1.osdmap:集群所有osd的集合,包括每个osd的ip & state(up 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.Epoch:osdmap的版本号,单调递增,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的集合为acting,pg_temp的集合为up。当然pg与pg_temp是不一样的,所以这时pg的集合变成了[3,1,2]/[1,2,3]。当OSD.3上的数据全部都恢复完成后,就变成了[3,1,2]/[3,1,2]。

9.pg_log:pg_log是用于恢复数据重要的结构,每个pg都有自己的log。对于pg的每一个object操作都记录在pg当中。

  • __s32 op; 操作的类型

  • hobject_t soid; 操作的对象

  • eversion_t version, prior_version, reverting_to; 操作的版本

三、peering具体流程

算法流程图:

                                  

152756_pm07_2460844

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经历以下主要过程:

           

2

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_epoch(history.last_epoch_clean 上次恢复数据完成的epoch)和end_epoch(history.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中的每一个interval,interval.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。

    map<pg_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_update<auth.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请求;

context<RecoveryMachine>().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(*context<RecoveryMachine>().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集合。

  • omissing:auth_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(*context<RecoveryMachine>().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, don't 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 (2):Ceph 的物理和逻辑结构 [Ceph Architecture] - SammyLiu - 博客园

作者:常涛  ceph 源代码分析 — peering 过程_ceph peering_Jack-changtao的博客-CSDN博客

感谢以上作者无私的分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/942866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jumpserver堡垒机一键安装

堡垒机简介 运维常见背黑锅场景 1、由于不明身份用户利用远程运维通道攻击服务器造成业务系统出现异常&#xff1a;但是运维人员无法明确攻击来源&#xff0c;那么领导很生气、后果很严重。 2、只有张三能管理的服务器&#xff0c;被李四登录过并且做了违规操作&#xff1a;…

新能源电驱动总成相关标准简介

新能源电驱动总成相关标准简介 电驱动系统标准体系是电动汽车标准体系中重要的组成部分&#xff0c;其制定和更新对于保障电动汽车的使用性能和安全性能具有非常重要的作用。 随着电动汽车行业的快速发展和普及&#xff0c;电驱动系统的重要性也越来越凸显。为了确保电动汽车的…

政府科技项目验收全流程分享

科技验收测试 &#xff08;验收申请→主管部门初审→科技厅审核→组织验收→归档备案→信用管理&#xff09;&#xff1a; &#xff08;一&#xff09;验收申请 项目承担单位通过省科技业务管理系统提交验收申请。 按期完成的项目&#xff0c;项目承担单位应当在项目合同书…

揭开波动性的神秘面纱:简要介绍预测市场走势

一、说明 本文是数据专家的体会&#xff0c;他之前写了一系列关于时间序列的文章&#xff0c;在这些文章之后&#xff0c;他想给出一个关于我们如何通过投资组合分析在潜在风险情况下将自己保持在安全区域的想法。文章专业性很强&#xff0c;但机器学习方面的工作还是有参考价值…

液体神经网络LLN:通过动态信息流彻底改变人工智能

巴乌米克泰吉 一、说明 在在人工智能领域&#xff0c;神经网络已被证明是解决复杂问题的非常强大的工具。多年来&#xff0c;研究人员不断寻求创新方法来提高其性能并扩展其能力。其中一种方法是液体神经网络&#xff08;LNN&#xff09;的概念&#xff0c;这是一个利用动态计算…

实验表明:人工智能生成的论文可在全美大多数大学的文社科类课程中获得及格成绩

两门A&#xff0c;一门A-&#xff0c;一门B&#xff0c;一门B-&#xff0c;一门及格。 对于一名哈佛大学的大一新生来说&#xff0c;这已经是一份相当不错的成绩单&#xff0c;合计3.57的GPA成绩也很可观。 Maya Bodnick 在哈佛大学的政治专业就读大一&#xff0c;上面提到的…

MyBatisPlus简单入门

1、简单介绍MyBatisPlus MyBatisPlus是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;完全去SQL化&#xff0c;封装好了大量的CRUD操作。甚至吧CRUD操作封装到了Service层&#xff0c;可以直接在Controller调用现成的CRUD服务层&#xff0c…

如何借助各个大模型的优点生成原创视频(真人人声)

第1步&#xff0c;借助天工AI搜索&#xff08;天工AI搜索 — 知识从这里开始 (tiangong.cn)&#xff09;&#xff0c;直接手机短信验证就可以使用&#xff0c;该大模型已经接入互联网&#xff0c;注意下图提问方式。 而且&#xff0c;细心的筒子已经发现&#xff0c;该回答可能…

Viobot硬件组成和接口

Viobot主要由主板、传感器板和外壳组成。具体尺寸可以在用户手册上面找到。 传感器板上面是双目摄像头和IMU&#xff0c;摄像头已经打了胶固定在外壳的前脸&#xff0c;由于涉及到传感器外参标定&#xff0c;所以不可自行拆卸。 LED补光灯版本&#xff1a; TOF版本&#xff1a…

Ceph入门到精通-Lunix性能分析工具汇总

出于对Linux操作系统的兴趣&#xff0c;以及对底层知识的强烈欲望&#xff0c;因此整理了这篇文章。本文也可以作为检验基础知识的指标&#xff0c;另外文章涵盖了一个系统的方方面面。如果没有完善的计算机系统知识&#xff0c;网络知识和操作系统知识&#xff0c;文档中的工具…

echarts笔记-上下左右部分显示比例(解决Y轴显示不全)

主要就是option里面的grid如下&#xff1a; grid: {top: 18%,left: 20%,//原来是10%&#xff0c;修改为20%right: 2%,bottom: 24%, },比如y轴显示不全就可以这样设置&#xff1a; grid: {left: 25%,//原来是10%&#xff0c;修改为20%right: 0%, },

vue2项目中表格的增删查改

我们在项目中经常会用到对于表格的增删查改操作&#xff0c;以下使用vue2elementui来实现表格的增删查改 表格的基本属性 基础表格如下:(其中需要注意的是当el-table元素中注入data对象数组后&#xff0c;在el-table-column中用prop属性来对应对象中的键名即可填入数据&#x…

Viobot基本功能使用及介绍

设备拿到手当然是要先试一下效果的&#xff0c;这部分可以参考本专栏的第一篇 Viobot开机指南。 接下来我们就从UI开始熟悉这个产品吧&#xff01; 1.状态 设备上电会自动运行它的程序&#xff0c;开启了一个服务器&#xff0c;上位机通过连接这个服务器连接到设备&#xff0c…

new操作符干了啥(手写new操作符)

new操作符干了啥&#xff08;手写new操作符&#xff09; 在JS中&#xff0c;new操作符用于创建一个新对象并调用一个函数来初始化对象&#xff0c;下面是手写实现new操作符的方法&#xff1a; // 传入构造函数 const myNew (constructor) > {// 1、创建一个空对象 {}cons…

QGIS 如何添加天地图

相信很多小伙伴在 QGIS 里面添加天地图的时候一定感觉很困惑,按照官网的操作申请 Key 之后,添加相对应的服务地址之后看不到地图或者地图不正常显示,今天我们就来解决这个问题 以下所有操作基于 QGIS 3.22 版本 申请 Key 1. 添加天地图的第一步需要申请 Key,首先要注册天…

US-DAS1、US-P2A单路及双路插头式比例放大器

US-P1、US-P2A、US-P2F插头式安装比例放大器控制不带电反馈的双路比例电磁铁的比例阀&#xff0c;如直动式或先导式比例方向阀的驱动控制。 工作电源24VDC标准&#xff1b; 兼容指令10V、4-20mA、0~10V、0~5V(电位器控制&#xff09;&#xff1b; 输出电流0~2A&#xff1b; …

web网站性能测试怎么做?常用指标有哪些

Web性能测试 一、网站web性能测试是什么意思&#xff1f;比如我们在打开一个网站的时候&#xff0c;网站打开时间很慢&#xff0c;或者总是打开失败&#xff0c;这都与网站性能有关系。那么网站性能测试就是通过各种自动化测试工具对系统的指标进行测试&#xff0c;通过模拟正…

记录--怎么实现一个3d翻书效果

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 本篇主要讨论以下两种翻书动画的实现&#xff1a; 第一种是整页翻转的效果&#xff1a; 这种整页翻转的效果主要是做rotateY的动画&#xff0c;并结合一些CSS的3d属性实现。 第二种折线翻转的效果&…

什么是软件测评,第三方软件测试收费和流程是怎样的?

一、软件测评的意义 软件测评是一种对软件功能、性能等一系列的测试&#xff0c;并出具相关的软件测试报告给用户&#xff0c;帮助软件企业完成退税、验收等需求。软件测评可以确定产品的质量是否安全稳定、是否对客户有帮助&#xff0c;或者软件产品的其他组合是否可以提供更…

电脑共享文件夹-实现手机和其他电脑的文件同步更新

一、首先是电脑和手机需要处于同一个路由器下 二、创建一个文件夹&#xff0c;随便命名 三、点击属性-共享-Everyone-添加&#xff08;设置读取/写入&#xff09;-最后点击共享 四、这里要注意&#xff0c;如果电脑之前没设置过共享文件夹会有一个弹窗&#xff0c;点第一个就好…