PG 的状态机和peering过程

news2024/11/25 4:23:26

首先来解释下什么是pg peering过程?

当最初建立PG之后,那么需要同步这个pg上所有osd中的pg状态。在这个同步状态的过程叫做peering过程。同样当启动osd的时候,这个osd上所有的pg都要进行peering过程,同步pg的状态。peering过程结束后进入pg的Active状态,如果需要进行数据恢复则进行数据的恢复工作。

那么从PG的创建或者扫描开始,PG就开始设置了自己的初始状态,到最后的完全同步,这期间使用一个叫做state_machine的机制进行标记和处理,然后加上事件机制进行通信。最后达到active+clean。

下面是一个pg的所有状态,pg的状态管理全部都交给一个叫做recoverymachine的成员来管理,pg的所有的状态是一个类似树形的结构,每个状态可能存在子状态,子状态还可能存在子状态如下图。

pg的状态变化是一套状态机,根据不同的状态接收到不同的事件进行相互的转化。

一、PG状态变化的时机:

a.创建pg后,会经过一系列的PG的状态变化,由Initial最后演化成Active+clean状态。

b.就是osd启动后,会进行PG扫描,扫描后会重新在本osd上建立PG,然后在经过一系列的pg状态变化,最后达到clean状态。

c.当其他osd启动后,如果和本osd处于同一个PG内,会收到pg成员变化事件,处理该事件则本osd上的pg状态也会重新被设置,再次经历状态变化,最后达到平衡的clean状态。

二、pg的状态演化过程

下面经过一个pg状态变化的过程说起,这个过程叫做PG的peering过程。peering的过程其实就是pg状态从初始状态然后到active+clean的变化过程。一个osd启动之后,上面的pg开始工作,状态为initial,这时进行比对所有osd上的pglog和pg_info,对pg的所有信息进行同步,选举primary osd和replica osd,peering过程结束,然后把peering的结果交给recovering,有recovering过程进行数据的恢复工作(如下图)。primary osd与replica osd经过一系列的状态事件的交互,最后达到active状态。

 

三、pg状态变化实例讲解

3.1 pg状态的管理结构:

1)pg在创建或者扫描时都会重新的把pg的结构创建起来,上一节在pg创建的时候已经说了,由monitor 会发送事件给osd,osd会处理事件,并且完成pg的创建工作。这里和故障恢复有密不可分的关系,下一节讲述数据的故障恢复。 

2)创建pg的时候会初始化一个叫做recovery_state的成员,该成员就是用来控制pg的状态变化和处理事件的机制。recover_state中存在一个成员叫做recovery_machie,该成员继承了boost::statechart::state_machine状态机,该状态机就是用来处理状态变化的。 

pg与state_machine的关系如下图。

该途中表明了几个数据结构之间的关系。

3.2 数据的pg状态变化过程

3.2.1  NULL -> initial

1).来看一下申请PG的时候 对PG结构的初始化。在PG进行初始化的时候就对recoverystate(this)。

2075:recoverystate的构造函数。

2078:对于machine进行初始化。这时初始化machine的状态为Initial状态。

3.2.2  initial  -> reset -> Started

2).创建PG之后,就要对PG的发送一系列的事件了,首先是创建事件,调取函数handle_create()。在handle_create中主要发送了两个事件。

5758:handle_create()处理函数。

5761:申请一个 Initialize d的事件evt。

5762:本端的recoverystate处理该事件。handle_event中调用machine. process_event ()。交由状态机进行处理。当状态为Initial的machine遇见Initialize事件会转化状态为reset状态。因为在initial状态里定义了,如果收到了Initialize事件则将状态转化为reset。

1567:定义了如果在Initial状态的时候,收到了Initialize事件,则转化为Reset状态。

目前是已经为Reset的状态了。带着这个状态再回到handle_create中。

5763:这里定义了第二个事件 ActMap 的evt2.

5764:通过recoverystate.handle_event()再次交给machine。但是这时machine的状态已经变成了Reset了,由Reset状态开始处理Actmap事件。在reset的事件处理函数中boost::statechart::result PG::RecoveryState::Reset::react(const ActMap&),最后将状态转化为了Started。transit< Started >()。然后来看Started状态,转化成该状态后又继续处理状态,在定义Started的时候默认设置了一个子状态start。

3.2.3 Started(start) ->Started( primary(Peering(GetInfo)))

3).来看一下当进入start时是怎么来处理的。

6010:开始处理进入start状态后的处理。

6016:找到对应处理的PG。

6017:如果当前的osd在本pg里是 primary。

6020:向本状态发送事件MakePrimary()事件。

6022:如果当前的osd在本pg里是replica。

6025:向本状态发送事件MakeStray。

4).接下来看看start状态如何来处理MakePrimary和MakeStray的事件吧,下面来看。

1653:如果接受到MakePrimary事件,则将状态start转化为Primary状态。

1654:如果接受到Makestray事件,则将状态start转化为stray状态。

接下来按着Primary osd的流程走。在进入Primary状态之后,在Primary状态存在一个子状态叫做Peering状态。并且Peering也同样存在一个子状态叫做GetInfo。在GetInfo的函数PG::RecoveryState::GetInfo::GetInfo()中做了哪些事情。

7375:创建当前pg的OSD集合。为数据的恢复做准备。下一节数据恢复时会讲述。

7379:发送请求到所有的副本osd中,请求pg_info信息,发送事件MQuery& query,query的类型是pg_query_t::INFO。然后发送的请求都会记录在peer_info_request队列中。

7381:如果想其他的osd发送的查询pg_info事件,那一定会添加到peer_info_request队列中,所以这里就不为空,然后就结束了。此时状态就到这里,目前是GetInfo的状态。等待replica osd获取pg_info结束后,再将结果通过事件发送给primary osd。

3.2.4   GetInfo->GetLog

5).当primary osd接到事件MNotifyRec& infoevt,然后对该事件展开处理。在GetInfo的状态下处理该事件,在处理该事件的时候会对拉取的pginfo进行处理,最后如果所有的副本都成功的将信息返回了,则会本端再次发起事件post_event(GotInfo());当GetInfo状态收到事件GotInfo(),则会转换状态为GetLog。现在交给了GetLog状态来继续处理,在进入GetLog中,做了如下的操作。

7621:这里要进行选择acting。包括了选择auth_osd、primary选择,副本选择(计算backfill osd,recover osd)。

7635:判断auth是不是正在处理的本osd上,如果是自己的话,那自己本身就是最全的log,所以不需要拉取log。

7637:因为不用拉取其他osd上的log,所以这里直接发送Gotlog事件,说明不需要拉取log,可以进入下一个状态了。

7673:由于自己本事auth osd,所以不是最全的log,所以要从其他osd上拉取log,这里准备事件g_query_t::LOG,发送到目标auth osd上拉取。

3.2.4   GetLog->GetMissing

6).本端使用handle_pg_query 处理g_query_t::LOG,将其封装成为MOSDPGLog消息,该消息发送到目标auth osd后,有auth osd解封消息,并且构造PG::MLogRec事件,发送给auth_osd处理,在auth_osd上形成MQuery& query 交给pg的state_machine处理,处理该事件,pg->fulfill_log(),获取本地log,然后通过消息MOSDPGLog发还给primary osd。这时primary 接到auth_osd发送过来的消息,并且消息携带auth_log的信息。在primary解析成为MLogRec 信息。这时primary osd的状态为GetLog,开始处理MLogRec 事件。直接出发post_event(GotLog())事件,当GetLog接收到Gotlog事件的时候,先要合并proc_master_log(),然后转换状态为GetMissing状态。

GetMissing的处理,在GetMissing中开始拉取所有副本的log信息,发送事件,等待所有的副本将自己的log和missing准备好发送给primary osd。这时primary osd处于GetMissing状态处理MLogRec事件,处理时proc_replica_log(),合并副本的log。

7974:当接受的log事件时候,将peer_missing_requested 队列中对应osd的计数删除。这个队列方便统计哪些osd没有及时的反馈消息。

7975:接收事件后,开始处理事件,proc_replica_log()合并副本的INFO,log,missing等信息。

7978:判断是否需要更新up_thru。

7983:如果需要更新up_thru。则发送NeedupThru事件。

7989:如果不需要更新up_thru,则发送Activate()事件。

3.2.6 GetMissing->Active(Activating)

7). 假设这里发送了Activate()事件,GetMissing状态会对Activate事件直接将状态转化为Active状态,在进入Active后会调用PG::activate的处理。在Activete的处理中有两件事儿.。a.准备事务的回调准备工作,申请注册C_PG_ActivateCommitted。b.准备想其他的osd发送合并后的log,将权威的log封装成MOSDPGLog,发送给副本,然后提交事务。

这时其他osd副本接收到MOSDPGLog事件,将解释为本地的MLogRec,副本osd的pg状态为stray,接收到MLogRec事件后。主要做的有三件事儿:a.合并接收到的log到本地log中,b.准备发送事件Activate,c.转化到状态ReplicaActive。最后由ReplicaActive状态处理事件Activate。这时同样会调用PG::activate()处理。这里主要准备了两件事儿,1.准备申请注册事务的回调处理函数C_PG_ActivateCommitted,2.准备进行数据恢复时的各种状态设置。完成后提交事务操作,等待事务完成。

目前,有两件事儿需要说明一下,primary osd提交了事务等待C_PG_ActivateCommitted处理,replica osd同样提交了事务等待C_PG_ActivateCommitted处理。接下来就来看看这个里边做了哪些工作。

primary osd处理完成后,提交事务回调进入_activate_committed中,

2109:如果这时判断本osd是主osd。

2117:判断是不是所有的osd都返回了提交了结果。

2119:如果是primary osd,并且所有的replica都提交了结果,则进行all_activated_and_committed()处理。

2125:如果不是primary osd,而是replica osd这时就要告诉primary osd,我已经处理好了,发送消息 MOSDPGInfo。

8).当primary osd接收到MOSDPGInfo消息,解析为MInfoRec事件,这时primary osd的状态为active,接收MInfoRec开始处理。

6998:当向一个osd发送MOSDPGLog后,会在对应osd的序号添加到peer_active的队列中,当osd反馈消息MOSDPGInfo后,会将osd的序号添加到actingbackfill队列中。这里判断是不是所有的osd都处理完成了事务。

7000:如果所有的osd都完成了事务的处理,接下来进入all_activated_and_committed处理中。在all_activated_and_committed中主要是要发送事件通知PG的状态,通知告知已经是AllReplicasActivated事件。

3.2.7  Active(Activating)-> WaitLocalRecoveryReserved->WaitRemoteRecoveryReserved-> Active(recovering)

active接受到AllReplicasActivated事件后,开始处理,这其中主要调用pg-> on_activate ()函数。由于PG是由ReplicatedPG子类继承的,所以这里调用ReplicatedPG::on_activate 进行处理。

9079:判断是否需要进行recovery数据的恢复。

9082:如果需要进行数据恢复,则发送事件DoRecovery()事件。

9085:判断是否需要进行backfill数据恢复。

9088:如果需要进行backfill数据恢复,则需要发送事件RequestBackfill()事件。

9091:即不需要recovery也不需要backfill等操作,则发送事件AllReplicasRecovered事件。

9).假设这里需要进行数据的恢复,这时发送了DoRecovery事件。activ状态接受到事件DoRecovery后进入子状态WaitLocalRecoveryReserved。该状态是active的子状态,仍让处于active状态中。在WaitLocalRecoveryReserved中会进行reserver处理并且发送LocalRecoveryReserved事件,WaitLocalRecoveryReserved接受到该事件后将转化为WaitRemoteRecoveryReserved状态。进入该状态后发RemoteRecoveryReserved事件,处理该事件时再次发送事件AllRemotesReserved,状态转化为Recovering。

6651:进入recovering时要进行的处理。

6658:清除PG的state中的PG_STATE_RECOVERY_WAIT。

6659:设置PG的state中的 PG_STATE_RECOVERING。

6660:准备将pg交给osd的recovery线程处理,进行数据恢复,这里是先添加到recovery_wq,然后等待线程处理队列中的pg数据恢复请求。

3.2.8 recovering->recoverd->clean

10). 该队列是由osd->recovery_wq 来实现的,而不是OSDService-> recovery_wq。

该队列的处理线程直接调用函数OSD::do_recovery()进行处理。在其中主要使用pg-> start_recovery_ops进行处理,在start_recovery_ops中判断这个pg已经数据恢复完成的时候。

代码能进行到这里说明已经PG的数据恢复完成。具体的数据恢复过程,后面的章节会讲述。

9510:这时检测状态是不是正在进行数据恢复状态是否为PG_STATE_RECOVERING。

9512:清除状态PG_STATE_RECOVERING。

9513:判断是不是要进行backfill处理?

9522:如果不需要进行backfill处理,这时代表所有的数据恢复都完成了,则发送事件AllReplicasRecovered。

11).这时recovering状态的pg接收到AllReplicasRecovered事件,则将pg的状态转化为Recovered状态。这时将会再次发送GoClean()事件。PG接收到GoClean()事件,将转化为clean状态。

最后的PG状态就是Active+clean的状态。clean是Active的一个子状态。最终完成了PG的所有状态变换。

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

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

相关文章

【K 均值聚类】02/5:简介

一、说明 k-mean算法是一种聚类算法&#xff0c;它的主要思想是基于数据点之间的距离进行聚类。K-means聚类是一种无监督的机器学习算法。让我们再解释一下这句话。聚类分析的目标是将数据划分为同类聚类。每个聚类中的点彼此之间比其他聚类中的点更相似。 无监督机器学习是在没…

k8s集群中集群方式安装nacos

1、前提条件 一个k8s集群&#xff0c;其中有三个master 节点&#xff0c;这三个节点的标签名称为etcd 三个master节点的ip 分别为&#xff1a;192.165.187.170 、192.165.187.171、192.165.187.172一个mysql 数据库&#xff0c; 数据库的ip 为&#xff1a;192.165.187.180 用户…

Java虚拟机整型数加载指令学习

JVM中 int 类型数值&#xff0c;根据 取值范围将 入栈的 字节码指令 就分为4类&#xff1a; 取值 -1~5 采用 iconst 指令&#xff1b; 取值 -128~127 采用 bipush 指令&#xff1b; 取值 -32768~32767 采用 sipush指令&#xff1b; 取值 -2147483648~2147483647 采用 ldc 指令。…

pyppeteer模块常用方法

目录 await page.方法 设置相关 setUserAgent(str) setCookie&#xff08;cookie1, cookie2.......&#xff09; 页面相关 goto(url) reload() goBack()/goForward() 执行js evaluate(js_str) 截图 screenshot(dict) 保存pdf pdf(dict) 获取内容 content() co…

Fragment的创建分析

之前的文章讨论了Fragment的销毁流程&#xff0c;初始状态为resume&#xff0c;然后经历pause -> stop -> destroyView -> destroy -> detach这么几个流程&#xff08;本篇文章基于Support27.1.1来分析的&#xff09;。清楚了Fragment的销毁&#xff0c;那也来看看…

《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3架构升级

架构升级 GPU 支持 早在 Milvus 1.x 版本,我们就曾经支持过 GPU,但在 2.x 版本中由于切换成了分布式架构,同时出于对于成本方面的考虑,暂时未加入 GPU 支持。在 Milvus 2.0 发布后的一年多时间里,Milvus 社区对 GPU 的呼声越来越高,再加上 NVIDIA 工程师的大力配合——为…

CTFHUB ICS(1)

1.异常的工程文件 把文件拖到kali里面去了 unzip 文件名解压文件 文件很多&#xff0c;我们先进到解压的文件夹里面 strings $(find . | xargs) | grep flag linux命令的作用是在当前目录及子目录下递归查找文件,提取文件中的字符串,然后用grep过滤 find . - 在当前目录及递…

cadence virtuoso bandgap温漂公式

先仿真温漂&#xff0c;然后将曲线send to calculate。 调用ymax&#xff0c;ymin&#xff0c;average函数。

PGInfo核心字段详解

PGInfo存在于PG的整个生命周期中&#xff0c;其在对象数据的写入、数据恢复、PG Peering过程中均发挥重要的作用。本章试图研究pg info在整个PG生命周期中的变化过程&#xff0c;从而对PG及PGInfo有一个更深入的理解。 class PG : DoutPrefixProvider { public:// pg statepg_…

Unable to remove Temporary User Data

错误截图 原因 项目的临时数据目录是存在了未授权的盘符&#xff0c;当删除它的时候&#xff0c;遇到了权限问题&#xff0c;没有权限没法删除。 解决方法 增加字段&#xff1a;userDataDir 解决

WSL使用技巧 / 虚拟机对比

WSL使用技巧 / 虚拟机对比 前言虚拟机比较VMware使用技巧WSL使用技巧官方文档工具安装WSL基本命令运行命令关闭卸载磁盘管理导入导出指定安装路径 前言 本文介绍了VMware和WSL的区别&#xff0c;并详细介绍了WSL的使用方法和技巧。 虚拟机比较 VMware 比较灵活&#xff0c;拥…

高压放大器该如何选择(高压放大器选型要求有哪些)

选择适合的高压放大器对于电子设备和实验中的特定应用非常重要。高压放大器通常用于放大高电压信号&#xff0c;如激光驱动、粒子加速器、电力系统和医学成像等领域。在选择高压放大器时&#xff0c;以下几个因素值得考虑。 首先&#xff0c;您需要确定所需的输出电压范围。不同…

Date.toLocaleString()不同系统语言之会返回不同的format(可能导致我查的出来数据别人查不出来)

最近发生了个Bug,访问部署在服务器上的服务&#xff0c;我选了时间之后查的出来数据&#xff0c;别人就不行&#xff0c;同样的条件&#xff0c;同样的时区。百思不得解。 直到看了 request里面的参数&#xff0c;发现怎么format不一致&#xff0c;都是访问的服务器部署的服务。…

Linux下的系统编程——进程的执行与回收(八)

前言&#xff1a; 前面我们对进程已经有了一个初步的了解与认识&#xff0c;现在让我们学习一下进程中一些函数的具体使用&#xff0c;比如exec可以执行一些指定的程序&#xff0c;wait / waitpid可以回收子进程&#xff0c;什么是孤儿进程&#xff0c;什么是僵尸进程&#xf…

性能测试实现天罗地网对各个中间件实现监控

名师出高徒&#xff0c;我亲自带你出征&#xff0c;直捣黄龙。高手都是顶峰相见&#xff01;将军有剑 不斩苍蝇&#xff0c;将军赶路&#xff0c;不追小兔。赶紧上车 带你入行就是高手。

【ccf-csp题解】第1次csp认证-第三题-命令行选项-题解

题目描述 思路讲解 本题是一个简单的字符串模拟题&#xff0c;这种题目是csp认证第三题的常客 大致思路是用两个bool数组记录某一个选项&#xff08;0--25下标对应小写字母a--z&#xff09;&#xff0c;第一个数组中无参选项为true&#xff0c;第二个数组中有参选项为true&a…

【算法系列篇】分治-归并

文章目录 前言什么是归并算法1. 排序数组1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 数组中逆序对2.1 题目要求2.2 做题思路2.3 Java代码实现 3. 计算右侧小于当前元素的个数3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 翻转对4.1 题目要求4.2 做题思路4.3 Java代码实现 总…

金融信创,软件规划需关注自主安全及生态建设

软件信创化&#xff0c;就是信息技术软件应用创新发展的意思&#xff08;简称为“信创”&#xff09;。 相信在中国&#xff0c;企业对于“信创化”这个概念并不陌生。「国强则民强」&#xff0c;今年来中国经济的快速发展&#xff0c;受到了各大欧美强国的“卡脖子”操作的影…

CNN(七):ResNeXt-50算法的思考

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 在进行ResNeXt-50实战练习时&#xff0c;我也跟其他学员一样有这个疑惑&#xff0c;如下图所示&#xff1a; 反复查看代码&#xff0c;仍然有…

探讨前后端分离开发的优势、实践以及如何实现更好的用户体验?

随着互联网技术的迅猛发展&#xff0c;前后端分离开发已经成为现代软件开发的一种重要趋势。这种开发模式将前端和后端的开发工作分开&#xff0c;通过清晰的接口协议进行通信&#xff0c;旨在优化开发流程、提升团队协作效率&#xff0c;并最终改善用户体验。本文将深入探讨前…