首先來解釋下什麼是pg peering過程?react
當最初創建PG以後,那麼須要同步這個pg上全部osd中的pg狀態。在這個同步狀態的過程叫作peering過程。一樣當啓動osd的時候,這個osd上全部的pg都要進行peering過程,同步pg的狀態。peering過程結束後進入pg的Active狀態,若是須要進行數據恢復則進行數據的恢復工做。數據結構
那麼從PG的建立或者掃描開始,PG就開始設置了本身的初始狀態,到最後的徹底同步,這期間使用一個叫作state_machine的機制進行標記和處理,而後加上事件機制進行通訊。最後達到active+clean。函數
下面是一個pg的全部狀態,pg的狀態管理所有都交給一個叫作recoverymachine的成員來管理,pg的全部的狀態是一個相似樹形的結構,每一個狀態可能存在子狀態,子狀態還可能存在子狀態以下圖。post
pg的狀態變化是一套狀態機,根據不一樣的狀態接收到不一樣的事件進行相互的轉化。this
a.建立pg後,會通過一系列的PG的狀態變化,由Initial最後演化成Active+clean狀態。spa
b.就是osd啓動後,會進行PG掃描,掃描後會從新在本osd上創建PG,而後在通過一系列的pg狀態變化,最後達到clean狀態。線程
c.當其餘osd啓動後,若是和本osd處於同一個PG內,會收到pg成員變化事件,處理該事件則本osd上的pg狀態也會從新被設置,再次經歷狀態變化,最後達到平衡的clean狀態。server
下面通過一個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狀態。繼承
來看看這些事件,貌似不少,可是結合流程去看就簡單的多了。隊列
1)pg在建立或者掃描時都會從新的把pg的結構建立起來,上一節在pg建立的時候已經說了,由monitor 會發送事件給osd,osd會處理事件,而且完成pg的建立工做。這裏和故障恢復有密不可分的關係,下一節講述數據的故障恢復。
2)建立pg的時候 會初始化一個叫作recovery_state的成員,該成員就是用來控制pg的狀態變化和處理事件的機制。recover_state中存在一個成員叫作recovery_machie,該成員繼承了boost::statechart::state_machine狀態機,該狀態機 就是用來處理狀態變化的。
pg 與state_machine的關係以下圖。
該途中代表了幾個數據結構之間的關係。
1).來看一下申請PG的時候 對PG結構的初始化。在PG進行初始化的時候就對recoverystate(this)。
2075:recoverystate的構造函數。
2078:對於machine進行初始化。這時初始化machine的狀態爲Initial狀態。
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).來看一下當進入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。
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上拉取。
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()事件。
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事件。
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數據恢復請求。
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的全部狀態變換。