1 PG介紹
pg的全稱是placement group,中文譯爲放置組,是用於放置object的一個載體,pg的建立是在建立ceph存儲池的時候指定的,同時跟指定的副本數也有關係,好比是3副本的則會有3個相同的pg存在於3個不一樣的osd上,pg其實在osd的存在形式就是一個目錄,能夠列出來看下:算法
[root@abc ~]# ll /var/lib/ceph/osd/ceph-2/current/ total 332 drwxr-xr-x 2 root root 32 Sep 19 15:27 1.11_head drwxr-xr-x 2 root root 98 Sep 21 15:12 1.14_head drwxr-xr-x 2 root root 83 Sep 21 14:12 1.1f_head drwxr-xr-x 2 root root 98 Sep 21 18:43 1.24_head drwxr-xr-x 2 root root 6 Sep 21 18:43 1.24_TEMP drwxr-xr-x 2 root root 32 Sep 19 15:27 1.25_head drwxr-xr-x 2 root root 164 Sep 21 15:14 1.2d_head drwxr-xr-x 2 root root 32 Sep 19 15:27 1.2_head drwxr-xr-x 2 root root 98 Sep 21 15:15 1.34_head
這裏只列出來一部分,能夠看到有1.24這樣開頭的,這其實就是pg的id,前面的1表示這個pg是對應哪一個存儲池的,存儲池id能夠經過ceph df看到:函數
[root@u131Oi ~]# ceph df GLOBAL: SIZE AVAIL RAW USED %RAW USED 10704G 9808G 896G 8.37 POOLS: NAME ID USED %USED MAX AVAIL OBJECTS volumes 1 116M 0 3059G 46 images 2 29218M 0.92 3059G 3669 backups 3 0 0 3059G 0 vms 4 269G 8.09 3059G 103678 snapshots 5 0 0 3059G 0 gnocchi 6 394M 0.01 3059G 23310
說明該pg是屬於volumes存儲池的,後面的24是用於區分同個池中的不一樣的pg的,二者結合起來就做爲pg的id了,crush map經過pgid能夠計算出該pg是分佈在哪組osd上的,能夠經過以下命令查看pg分佈於哪些osd上:spa
[root@abc ~]# ceph pg map 1.24 osdmap e1008 pg 1.24 (1.24) -> up [0,2,8] acting [0,2,8]
能夠看到該pg的3副本分別是分佈在osd.0,osd.2和osd.8上的,其中最前面的0表示主副本存在於osd.0上。日誌
2 PG在ceph中的做用
從上面能夠看到全部數據其實都是抽象成多個object,每一個object都會對應到惟一的一個pg上(多副本表示有多個相同的pg,固然object也天然是多副本的),而後pg映射到osd上存儲,因此pg能夠說是ceph的核心概念了,那爲何要引進pg這個概念呢?
這是由於若是要追蹤的目標若是是object,那麼要追蹤的數量就太多了,這樣可能會加大複雜性,並且也會帶來不小的開銷,因而引進pg這個概念,把object裝進pg中,以pg爲存儲單元個體,直接追蹤pg狀態,通常pg數量是遠遠小於object數量的。code
3 PG數量計算方法
官方給出的計算公式是這樣的:
Total PGs = (Total_number_of_OSD * 100) / max_replication_count
但每一個池中pg數量最好接近或等於2的次方
例:
有100個osd,2副本,5個pool
Total PGs =100*100/2=5000
每一個pool 的PG=5000/5=1000,那麼建立pool的時候就指定pg爲1024
ceph osd pool create pool_name 1024
下面給出我在程序中寫的pg計算函數(僅供參考):對象
def pg_calc(osd_count, pool_count, rep_size): osd_count = int(osd_count) pool_count = int(pool_count) rep_size = int(rep_size) pg_num = 512 if rep_size == 2: if osd_count > 0 and osd_count < 5: pg_num = 128 elif osd_count >= 5 and osd_count <= 10: pg_num = 512 else: pg_num = int((osd_count * 100) / (rep_size)) else: pg_num = int((osd_count * 100) / (rep_size)) per_pool_pg = pg_num / pool_count for i in range(0, 21): tmp = 2 ** i if tmp >= per_pool_pg: pg_num = tmp break return pg_num
4 PG的狀態有哪些
從第2點咱們知道因爲pg的引進,咱們只要追蹤pg的狀態便可,所以pg在集羣中是存在多種狀態的,pg的狀態也決定着當前集羣數據的健康狀態。
(1)Active:當前擁有最新狀態數據的pg正在工做中,能正常處理來自客戶端的讀寫請求。
(2)inactive:正在等待具備最新數據的OSD出現,即當前具備最新數據的pg不在工做中,不能正常處理來自客戶端的讀寫請求。
(3)Clean:PG所包含的object達到指定的副本數量,即object副本數量正常。
(4)Unclean:PG所包含的object沒有達到指定的副本數量,好比一個PG沒在工做,另外一個PG在工做,object沒有複製到另一個PG中。
(5)Peering:PG所在的OSD對PG中的對象的狀態達成一個共識(維持對象一致性)。
(6)Degraded:主osd沒有收到副osd的寫完成應答,好比某個osd處於down狀態。
(7)Stale:主osd未在規定時間內向mon報告其pg狀態,或者其它osd向mon報告該主osd沒法通訊。
(8)Inconsistent:PG中存在某些對象的各個副本的數據不一致,緣由多是數據被修改。
(9)Repair:pg在scrub過程當中發現某些對象不一致,嘗試自動修復。
(10)Undersized:pg的副本數少於pg所在池所指定的副本數量,通常是因爲osd down的緣故。
(11)Scrubbing(deep + Scrubbing):pg對對象的一致性進行掃描。
(12)Recovering:pg間peering完成後,對pg中不一致的對象執行同步或修復,通常是osd down了或新加入了osd。blog
(13)Backfilling:通常是當新的osd加入或移除掉了某個osd後,pg進行遷移或進行全量同步。md5
(14)down:包含必備數據的副本掛了,pg此時處理離線狀態,不能正常處理來自客戶端的讀寫請求。rem
5 PG修復
5.1 一般查看集羣是否正常都是經過ceph -s命令查看,若是顯示是HEALTH_OK則表示集羣是健康的,一切運行正常,好比:同步
[root@ctl0 ~]# ceph -s cluster ce0d75a9-9d6a-4b8e-ab4c-c3645f69506a health HEALTH_OK monmap e3: 3 mons at {ctl0=10.16.30.16:6789/0,ctl1=10.16.30.14:6789/0,ctl2=10.16.30.15:6789/0} election epoch 20, quorum 0,1,2 ctl1,ctl2,ctl0 osdmap e39: 3 osds: 3 up, 3 in pgmap v58: 192 pgs, 6 pools, 0 bytes data, 0 objects 102 MB used, 98153 MB / 98255 MB avail 192 active+clean
但有時也會碰見ceph -s顯示的是HEALTH_WARN,以下所示:
[root@ctl0 ~]# ceph -s cluster ce0d75a9-9d6a-4b8e-ab4c-c3645f69506a health HEALTH_WARN 135 pgs degraded 135 pgs stuck unclean 135 pgs undersized 1/3 in osds are down monmap e3: 3 mons at {ctl0=10.16.30.16:6789/0,ctl1=10.16.30.14:6789/0,ctl2=10.16.30.15:6789/0} election epoch 20, quorum 0,1,2 ctl1,ctl2,ctl0 osdmap e41: 3 osds: 2 up, 3 in pgmap v64: 192 pgs, 6 pools, 0 bytes data, 0 objects 103 MB used, 98152 MB / 98255 MB avail 135 active+undersized+degraded 57 active+clean
能夠看到不少pg的狀態是不健康的了,但從中其實也能夠發現有一個osd掛了,其實只要把該osd從新拉起來就行了,拉起來後集羣會自動從新恢復健康狀態。可是也有可能出現這個osd再也起不來了,好比硬盤損壞了,這時多副本就發揮做用了,由於還有其它副本在其它osd上,這時咱們能夠經過均衡數據的方法來將集羣恢復並將該osd踢出集羣。
這裏咱們以osd.2爲例子。
均衡數據恢復步驟:
# 先將該osd reweight 到0,也就是將權重下降到0,讓數據副本分散到其它osd上
ceph osd reweight 2 0.0
# 待集羣從新恢復爲ok後執行如下命令將osd踢出集羣
service ceph stop osd.2 ceph osd out 2 ceph osd crush remove osd.2 ceph auth del osd.2 ceph osd rm osd.2
5.2 有時可能碰上osd拉起後仍是有些pg不健康的,好比:
(1)Unfound objects
ceph集羣知道該對象存在,但沒法定位該object在哪時會報這個錯誤。
解決辦法:
<1>嘗試讓失敗的osd起來,若是起來後集羣恢復正常,則結束
<2>嘗試將該pg的unfound對象回滾到上一個版本,ceph pg $pgid mark_unfound_lost revert,若是恢復正常,則結束
<3>若是仍是不行,那只有將該object刪除掉了,注意這會致使丟失數據,ceph pg $pgid mark_unfound_lost delete
(2)inconsistent objects
pg中保存的object中有些副本數據不一致,有些事伴隨着scrub errors錯誤
<1>ceph health detail 找出問題pg
<2>嘗試ceph pg repair $pgid,若成功,則結束(這個執行修復後通常要等久點,實在不能自動repair,再用如下方式)
<3>經過ceph pg map $pgid,找出主osd,打開其日誌查看是哪一個object不一致
<4>找出全部該objects全部副本存放的位置,用摘要算法(md5sum,sha256)等計算出其hash值,若是是3副本,刪除與其餘副本不一致的;若是是2副本,則可能會誤刪。
<5> 再次執行 ceph pg repair $pgid
(3)stale pgpg出現stale狀態,也就是pg處於僵死狀態,該狀態是沒法處理新的請求了的,新的請求過來只會block,這種狀況通常是因爲全部副本pg的osd都掛了,要模擬其實也很簡單,好比設置2副本,而後將2個不一樣故障域的osd掛掉便可出現,最好的恢復方法固然是從新拉起這兩個osd,但有時可能出現這樣的狀況,兩個osd永遠也拉不起來了,而後你把這兩個osd清理出去了,清理完後這些pg固然就是stale的狀態,這時的恢復方法只能是丟掉這個pg裏的數據了,從新建立pg:<1>使用命令ceph pg dump |grep stale 找出全部的stale的pg,也能夠ceph health detail |grep stale<2>執行ceph pg force_create_pg $pg_id命令強制從新建立pg,這時能夠看到pg會轉爲creating狀態<3>重啓ceph集羣中的全部OSD