ceph的數據存儲之路(7) -----PG 的狀態機和peering過程

PG 的狀態機和peering過程

首先來解釋下什麼是pg peering過程?react

當最初創建PG以後,那麼須要同步這個pg上全部osd中的pg狀態。在這個同步狀態的過程叫作peering過程。一樣當啓動osd的時候,這個osd上全部的pg都要進行peering過程,同步pg的狀態。peering過程結束後進入pgActive狀態,若是須要進行數據恢復則進行數據的恢復工做。數據結構

 

那麼從PG的建立或者掃描開始,PG就開始設置了本身的初始狀態,到最後的徹底同步,這期間使用一個叫作state_machine的機制進行標記和處理,而後加上事件機制進行通訊。最後達到active+clean函數

 

下面是一個pg的全部狀態,pg的狀態管理所有都交給一個叫作recoverymachine的成員來管理,pg的全部的狀態是一個相似樹形的結構,每一個狀態可能存在子狀態,子狀態還可能存在子狀態以下圖。post

pg的狀態變化是一套狀態機,根據不一樣的狀態接收到不一樣的事件進行相互的轉化。this

 

1、PG狀態變化的時機:

a.建立pg後,會通過一系列的PG的狀態變化,Initial最後演化成Active+clean狀態。spa

b.就是osd啓動後,會進行PG掃描,掃描後會從新在本osd上創建PG,而後在通過一系列的pg狀態變化,最後達到clean狀態。線程

c.當其餘osd啓動後,若是和本osd處於同一個PG內,會收到pg成員變化事件,處理該事件則本osd上的pg狀態也會從新被設置,再次經歷狀態變化,最後達到平衡的clean狀態。server

 

2、pg的狀態演化過程

下面通過一個pg狀態變化的過程提及,這個過程叫作PGpeering過程。peering的過程其實就是pg狀態從初始狀態而後到active+clean的變化過程。一個osd啓動以後,上面的pg開始工做,狀態爲initial,這時進行比對全部osd上的pglogpg_info,對pg的全部信息進行同步,選舉primary osdreplica osdpeering過程結束,而後把peering的結果交給recovering,有recovering過程進行數據的恢復工做(以下圖)。primary osdreplica osd通過一系列的狀態事件的交互,最後達到active狀態。繼承

來看看這些事件,貌似不少,可是結合流程去看就簡單的多了。隊列

 

 

3、pg狀態變化實例講解

3.1 pg狀態的管理結構:

1)pg在建立或者掃描時都會從新的把pg的結構建立起來,上一節在pg建立的時候已經說了,由monitor 會發送事件給osdosd會處理事件,而且完成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)

2075recoverystate的構造函數。

2078:對於machine進行初始化。這時初始化machine的狀態爲Initial狀態。

 

3.2.2  initial  -> reset -> Started

2).建立PG以後,就要對PG的發送一系列的事件了,首先是建立事件,調取函數handle_create()。在handle_create中主要發送了兩個事件。

5758handle_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:建立當前pgOSD集合。爲數據的恢復作準備。下一節數據恢復時會講述。

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_osdprimary選擇,副本選擇(計算backfill osdrecover 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 交給pgstate_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_ActivateCommittedb.準備想其餘的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的全部狀態變換。

相關文章
相關標籤/搜索