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