ceph存储 PG的状态机和peering过程

article/2025/9/17 9:00:30


PG 的状态机和peering过程

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

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

 

那么从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状态机,该状态机就是用来处理状态变化的。 

pgstate_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 ()。交由状态机进行处理。当状态为Initialmachine遇见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&),最后将状态转化为了Startedtransit< 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状态如何来处理MakePrimaryMakeStray的事件吧,下面来看。

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& queryquery的类型是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信息,发送事件,等待所有的副本将自己的logmissing准备好发送给primary osd。这时primary osd处于GetMissing状态处理MLogRec事件,处理时proc_replica_log(),合并副本的log

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

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

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,副本osdpg状态为stray,接收到MLogRec事件后。主要做的有三件事儿:a.合并接收到的log到本地log中,b.准备发送事件Activatec.转化到状态ReplicaActive。最后由ReplicaActive状态处理事件Activate。这时同样会调用PG::activate()处理。这里主要准备了两件事儿,1.准备申请注册事务的回调处理函数C_PG_ActivateCommitted2.准备进行数据恢复时的各种状态设置。完成后提交事务操作,等待事务完成。

 

目前,有两件事儿需要说明一下,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:清除PGstate中的PG_STATE_RECOVERY_WAIT

6659:设置PGstate中的 PG_STATE_RECOVERING

6660:准备将pg交给osdrecovery线程处理,进行数据恢复,这里是先添加到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的状态。cleanActive的一个子状态。最终完成了PG的所有状态变换。


http://chatgpt.dhexx.cn/article/5vWC8t0Y.shtml

相关文章

你所不知道的BGP知识,Peering 和IP-Transit.

了解网络的同行都知道BGP又称“边界网关协议”&#xff0c;他的英文全称是“border gateway protocol”&#xff0c;业内简称“BGP”&#xff0c;他是应用在TCP上的一种路由协议&#xff0c;它的主要功能是为了实现自治系统间的路由选择功能&#xff0c;通俗来讲就是通过控制路…

AWS攻略——Peering连接VPC

文章目录 创建IP/CIDR不覆盖的VPC创建VPC创建子网创建密钥对创建EC2 创建Peering接受Peering邀请修改各个VPC的路由表修改美东us-east-1 pulic subnet的路由修改悉尼ap-southeast-2路由 测试知识点 我们回顾下《AWS攻略——VPC初识》中的知识&#xff1a; 一个VPC只能设置在一…

蒙特卡洛法(Monte Carlo)电动汽车负荷预测matlab程序设计

电动汽车充电负荷的时间分布预测 规模化电动汽车充电负荷在未来某一天随时间特性的分布规律是研究电动汽车发展对配 电网影响以及充电站选址定容问题的前提与基础。电动汽车充电负荷的分布情况与车主的行 为特征有关&#xff0c;不同类型的电动汽车车主出行规律以及充电习惯不…

蒙特卡洛法(三)马尔科夫链蒙特卡洛法

马尔科夫链蒙特卡洛法适合于随机变量是多元的、密度函数是非标准形式的随机变量各分量不独立的情况。如何构建具体的马尔科夫链是这个方法的关键&#xff0c;离散变量的时候&#xff0c;需要定义转移矩阵&#xff0c;构建可逆马尔科夫链&#xff0c;保证遍历定理成立。常用的马…

蒙特卡洛法简述

蒙特卡洛法简述 一.简介&#xff1a; 1.蒙特卡洛方法又称随机模拟法&#xff0c;随机抽样技术&#xff0c;是一种随机模拟方法。 蒙特卡洛法使用随机数&#xff08;伪随机数&#xff09;以概率和统计理论方法为基础&#xff0c;将所要求解的问题同一定的概率模型相互联系&am…

蒙特卡洛法模拟计算圆周率π

一、蒙特卡洛法介绍 蒙特卡罗方法&#xff08;Monte Carlo method&#xff09;&#xff0c;也称统计模拟方法&#xff0c;是一种以概率统计理论为基础的数值计算方法&#xff0c;常用于特定条件下的概率计算问题。蒙特卡罗是摩纳哥的著名赌城&#xff0c;该法为表明其随机抽样的…

蒙特卡洛法之MATLAB实现

by WC 1.7.2016蒙特卡洛法&#xff08;随机取样法&#xff09;也称为计算机随机模拟方法&#xff0c;它源于世界著名的赌城——Monte Carlo。它是基于对大量事件的统计结果来实现一些确定性问题的计算。使用蒙特卡洛法必须使用计算机生成相关分布的随机数。 eg&#xff1a; y…

C语言文件打开关闭和读写

文件在进行读写操作之前要先打开&#xff0c;使用完毕要关闭。在C语言中&#xff0c;文件操作都是由库函数来完成的。在本节内将介绍主要的文件操作函数。 文件的打开(fopen函数) fopen函数用来打开一个文件&#xff0c;其调用的一般形式为&#xff1a; 文件指针名 fopen( 文…

C语言文件详解(一)文件介绍,文件打开和关闭

文章目录 一、文件介绍1.1为什么使用文件1.2什么是文件1.3文件名 二、文件的打开和关闭2.1文件指针2.2文件的打开和关闭 一、文件介绍 1.1为什么使用文件 文件属于文件的一种&#xff0c;与普通文件载体不同&#xff0c;文件是以硬盘为载体存储在计算机上的信息集合。那么为什…

C语言fopen打开文件失败了,原来是这个原因~~~~

大家好&#xff0c;我是疯狂的比特&#xff0c;一个每天在互联网上种菜和砍柴的程序员 今天给大家分享一个C语言初学者常见的一个问题。 问题 经常有人问我&#xff0c;我的C语言代码好好的&#xff0c;怎么就打开文件失败了呢&#xff1f; 我们先来看看代码吧 #include <s…

【C】C语言打开,读取文件

文章目录 C语言打开&#xff0c;读取文件一、明明白白我的心二、代码飞起来三、过程不重要&#xff0c;重点看结果 C语言打开&#xff0c;读取文件 一、明明白白我的心 1、gcc编译C语言代码 2、winds10操作系统 3、VS Code编辑器(强推&#xff0c;最近博主用这个…

C语言<文件的打开与关闭>

目录 一.为什么使用文件 二.什么是文件 1.程序文件 2.数据文件 3.文件名 三.文件的打开与关闭 1.文件指针 2.文件的打开与关闭 结语 一.为什么使用文件 我们前面学习结构体时&#xff0c;写了通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录…

C语言文件打开方式

使用文件的方式共有12种&#xff0c;下面给出了它们的符号和意义。 文件打开方式 意义 rt 只读打开一个文本文件&#xff0c;只允许读数据 wt 只写打开或建立一个文本文件&#xff0c;只允许写数据 at 追加打开一个文本文件&#xff0c;并在文件末尾写数据 rb 只…

C语言————文件的打开(知识点总结+举例)

fopen函数用来打开一个文件&#xff0c;其调用的一般形式为&#xff1a; 文件指针名fopen(文件名,使用文件方式); 其中&#xff1a; “文件指针名”必须是被说明为FILE 类型的指针变量&#xff1b; “文件名”是被打开文件的文件名&#xff1b; “使用文件方式”是指文件的类型…

【C语言】文件的打开和关闭,文件的顺序读写

文章目录 1、为什么使用文件 2、什么是文件 3、文件的打开和关闭 文件的打开 文件的关闭 4、文件的顺序读写 4.1文件读写的特点 4.2fputc、fgetc函数 4.3fgets、fputs函数 4.4fscanf、fprintf函数 5、标准输入输出流stdin、stdout 1、为什么使用文件 在编写例如通讯…

C语言-文件操作

当程序的生命周期结束&#xff0c;在内存中存放的数据就会随着内存的释放而清除&#xff0c;这并不满足我们日常生活中的记录需求&#xff0c;所以C语言开发了文件操作模式&#xff0c;通过将数据存放在硬盘&#xff0c;数据库等方式&#xff0c;实现数据的持久化。 文件存在于…

C语言打开文件详解

C语言中操作文件之前必须先打开文件&#xff1b;所谓“打开文件”&#xff0c;就是让程序和文件建立连接的过程。 打开文件之后&#xff0c;程序可以得到文件的相关信息&#xff0c;例如大小、类型、权限、创建者、更新时间等。在后续读写文件的过程中&#xff0c;程序还可以记…

一 形参与实参

1 实际参数&#xff08;实参&#xff09; 真实传给函数的参数&#xff0c;叫实参。即在函数调用时写入的实际参数。 实参可以是&#xff1a;常量、变量、表达式、函数等。无论实参是何种类型的量&#xff0c;在进行函数调用时&#xff0c;它们必须有确定的值&#xff0c;以便把…

【C语言函数参数详解】——实际参数(实参)形式参数(形参)

文章目录 一.什么是实际参数&#xff08;实参&#xff09;二.什么是形式参数&#xff08;形参&#xff09;三.形参与实参的关系 这篇文章我们一起学习一下函数的参数&#xff0c;函数的参数分为实参和形参。 一.什么是实际参数&#xff08;实参&#xff09; 首先我们来学习实…

java 静态工厂_高效Java第一条考虑用静态工厂代替构造函数

获得类的实例&#xff1a; 1.提供一个公有的构造函数&#xff1b; 2.提供一个公有的静态工厂方法&#xff0c;该方法只是一个返回类的实例的静态方法。 静态工厂方法与设计模式中的工厂方法模式不同。 提供静态工厂方法的优势——静态工厂方法与构造函数不同的第一大优势在于&a…