ceph monitor的一個主要功能是使用paxos分布式式協定維護一個key/value資料庫的一緻性。所使用的資料庫引擎一般是leveldb。
為了适應不同的資料庫引擎, ceph定義一個monitordbstore類來抽象對k/v資料庫的操作。對後端資料庫要求是支援事務或者原子性的key/value批量更新。它定義個一 transaction類來說明一個事務包含的所有操作,并且這個類是可以序列化和反序列化的,以便在伺服器之間傳送:
例如它定義個put、erase的成員函數操作:
而序列化、反序列化函數:
ceph 主要用這個monitordbstore來為各個需要使用paxos的子產品提供存儲,為了各個子產品不互相幹擾,每個子產品會選擇一個字首, 所有屬于這個子產品的資料都使用這個prefix再加上 一個key,才構成後端資料庫真正的key, 具體結構時這樣的:
monitordbstore的api 主要是
負責把transaction的每一條操作以原子方式在後端資料庫執行,是一個同步操作,而
是一個異步操作,事務完成後會回調一個從context導出的類對象,類似于c語言中的回調函數。
除此以外,monitordbstore還有get操作
定義疊代器用來批量擷取資料,它可以指定幾個prefix, 并批量把資料追加到一個transaction裡面,以便在伺服器見批量傳資料, 可以預見加進去的資料操作是put操作
ceph内部使用了log來記錄最近一段時間的操作,log存放在leveldb中,key的字首‘paxos’被paxos核心子產品保留。每一條log一個key, key的組成是paxos字首+
index, index是用整數來表示的,順序增加。為了加快log的查詢, 還用"first_committed" "last_committed", 兩個key來表示這段log, 前者是第一條log,後者是最後一條log。
每次monitor server啟動時都會按照monmap中的伺服器位址去連接配接其他monitor伺服器,并同步資料。這個過程叫做bootstrap(). bootstrap的第一個目的是補全資料,從其他服務拉缺失的paxos log或者全量複制資料庫,其次是在必要時形成多數派建立一個paxos叢集或者加入到已有的多數派中。
啟動時将自己加入到一個外部法人集合,因為剛開始自己肯定不是在多數派中:
然後給其它所有它知道的伺服器發送探測包:
任何一個伺服器收到探測包都會比較自己的最後一次修改資料的版本是否落後于正在探測的伺服器的資料:
對于被探測的伺服器,如果最後一條log的index number都跟不上對方的第一條記錄的index number,意味着已經落後太多了,中間log記錄已經缺失,不可能讓paxos核心部分通過log來傳播資料到本程序以獲得資料的最終版本,本程序需要重新開機bootstrap從對方主動拉資料。此時不會帶對方的探測包傳回應答。正常情況,我們會報告本伺服器的paxos狀态:
主要内容包括我們是否是多數派的一員(通過傳回多數派成員清單),以及我的paxos log的第一條記錄号和最後一條記錄号。
一旦一個發出探測包的伺服器收到一個應答也會檢查paxos log是否過時:
一種情況是我的最後一條log記錄和對方的第一條log記錄之間有空隙,中間有缺失,隻能主動從對方拉資料,道理與上面相同。還有一種是根據配置變量paxos_max_join_drift,資料并沒有缺失,但是要傳的log超過一個閥值,不如全量從對方複制資料。
輸入探測方發現不需要在這個階段複制資料,并且對方就是多數派的一員,那麼可以肯定它的資料是和其他伺服器同步的,至少應該樂觀的認為,:-) ,是以直接加入到多數派去:
ceph monitor通過bootstrap過程,探測伺服器清單中的各個伺服器,比對log的最小記錄号和最大記錄号,直到本機資料的log曆史(第一條記錄和最後一條記錄)都與所有其他伺服器有交集,說明本機沒有漏掉資料,進而進入多數派的形成過程,為paxos核心部分隻通過傳播log就可以同步資料創造條件。在boostrap階段,伺服器分析是否存在一個多數派,必要是通過進入競選形成多數派。在這個階段的全量同步和部分資料傳輸,沒有介紹,因為相對簡單,可以通過閱讀ceph源碼獲得。
本章并未涉及ceph paxos設計最核心部分,有時間再介紹。