从一开始,在Ceph中选择和调整PG数量一直是管理Ceph集群中最令人沮丧的部分之一。 选择适当资源池的指南令人困惑,来源之间不一致,并且经常被警告和例外所包围。 最重要的是,如果选择了错误的值,獭并不总是可以进行纠正,并且性能和/或稳定性会受到影响。 Nautilus之前的Ceph版本中的关键限制是,如果pg_num值太小,则总是可以增加它,但是如果它太高,则不能减小它。

不再!。在Nautilus中,池的pg_num值可以降低。更重要的是,可以启用pg autotuner,该组件允许系统自动进行任何适当的调整,以便用户可以完全忽略pg_num调整的前期技巧。

PG是什么?

RADOS(Ceph的底层存储层)中存储的数据对象被分组到逻辑池中。 池具有复制因子,纠删码方案之类的属性,并且可能具有仅将数据放置在HDD或SSD上的规则。 在内部,根据存储在池中对象名称的哈希值将池分为pg_num placement groups或PG。 因此,每个placement group都是整个池的伪随机slice(切片),shard(分段)或fragment (片段),并且特定PG中的所有对象都被分组并一起存储在同一组存储设备(OSD)上。

对象很少的小池只需要几个PG。大型池(例如,包含集群中存储的大部分数据的池)需要大量PG,以确保数据分布在多个设备上,从而平衡所有OSD上的空间利用率,并在系统负载时提供良好的并行性。
PG太少会对少数存储设备的性能造成瓶颈,而PG过多会使Cave的行为效率低下-在极端情况下甚至不稳定-这是因为管理每个PG需要进行内部跟踪。

标准的经验法则是,我们希望每个OSD大约有100个PG,但要计算出系统中每个池的PG数量-同时考虑复制和纠删码等因素-可能是一项挑战。

PG分裂和合并

自2012年以来,Ceph就一直支持PG“分裂”,使现有PG可以将其内容“拆分”为许多较小的PG,从而增加了池中PG的总数。 这使集群开始时很小,然后随时间增长而扩展。 从Nautilus开始,我们现在还可以将两个现有PG“合并”到一个更大的PG中,从而减少PG的总数。 如果池中的相对数据量随着时间的推移而减少,从而需要或适当地减少了PG,或者整个集群都缩小了,或者所选的PG的初始数量太大,则这很有用。

传统上,当PG数量增加时,PG分裂是一气呵成的。例如,要将池的pg_num值从16调整为64,只需

$ ceph osd pool set foo pg_num 64
  • 1

集群将16个PG中的每个PG一次性分割成4个片段。 以前,还需要第二步来调整这些新PG的位置,以便将它们存储在新设备上:

$ ceph osd pool set foo pgp_num 64
  • 1

这是移动实际数据的开销最大的部分。从Nautilus开始,第二步不再是必需的:只要pgp_num和pg_num当前匹配,pgp_num就会自动跟踪任何pg_num更改。更重要的是,根据新的target_max_misplace_rate配置选项(默认为0.05或5%),逐步调整pgp_num以迁移数据并(最终)收敛到pg_num,以限制系统上的数据迁移负载。也就是说,默认情况下,Ceph会尝试让不超过5%的数据处于“错位”状态,并排队等待迁移,从而限制对客户端工作负载的影响。

PG合并的工作方式与分裂类似,不同之处在于内部pg_num值总是每次一次减少一个PG。 合并是一个更为复杂和精细的过程,需要将PG的IO暂停几秒钟,并且一次合并一个PG可使系统将影响最小化并简化整个过程。 当使用以下命令减少foo池的pg_num时,将设置一个内部pg_num_target值,该值指示pg_num的所需值,并且集群会慢慢收敛于该值。 例如,要将pool foo的PG从64降低到4,

$ ceph osd pool set foo pg_num 4
$ ceph osd pool ls detail | grep foo
pool 1 'foo' replicated size 3 min_size 2 crush_rule 0 object_hash rjenkins pg_num 63 pgp_num 62 pg_num_target 4 pgp_num_target 4 autoscale_mode warn last_change 391 lfor 0/391/389 flags hashpspool stripe_width 0
  • 1
  • 2
  • 3

#查看状态
ceph balancer status
#计算当前集群得分
ceph balancer eval
#选择模式,crush-compat 模式执行命令的数据迁移过程,相应pg会处于active+remapped+backfill状态,pg重新映射且数据回填之中,内部osd之间数据的读写过程,并不会影响客户端的读写操作。
ceph balancer mode crush-compat

PG auto-scaler

调整pg_num值的能力是向前迈出的关键一步,但它并未解决PG调整问题,对于大多数用户而言,这似乎是不可思议的事情。 Nautilus包括一个称为pg_autoscaler的新管理器模块,该模块允许集群考虑每个池中实际存储(或预期要存储)的数据量,并自动选择适当的pg_num值。

由于为pg_autoscaler是新的,因此需要在Nautilus中显式启用它:

$ ceph mgr module enable pg_autoscaler
  • 1

autoscaler是按每个池配置的,可以在以下几种模式下运行:

  • 警告(warn) 模式:如果建议的pg_num值与当前值相差太大,则会发出健康警告。 这是新池和现有池的默认设置。
  • 启用(on) 模式:无需任何管理员交互即可自动调整池pg_num。
  • 禁用(off) 模式:还可以为任何给定池关闭autoscaler,让管理员像以前一样手动管理pg_num。

要为特定池启用autoscale,

$ ceph osd pool set foo pg_autoscale_mode on
  • 1

启用后,可以通过CLI查询所有池的当前状态和建议的调整。 例如,在我们的实验集群上,我们有:

$ ceph osd pool autoscale-status
 POOL                          SIZE  TARGET SIZE  RATE  RAW CAPACITY   RATIO  TARGET RATIO  PG_NUM  NEW PG_NUM  AUTOSCALE 
 device_health_metrics       18331k                3.0        431.3T  0.0000                     1              warn      
 default.rgw.buckets.non-ec      0                 3.0        431.3T  0.0000                     8              warn      
 default.rgw.meta             2410                 3.0        431.3T  0.0000                     8              warn      
 default.rgw.buckets.index   38637k                3.0        431.3T  0.0000                     8              warn      
 default.rgw.control             0                 3.0        431.3T  0.0000                     8              warn      
 default.rgw.buckets.data    743.5G                3.0        431.3T  0.0050                    32              on        
 .rgw.root                    1113                 3.0        431.3T  0.0000                     8              warn      
 djf_tmp                      1169G                3.0        431.3T  0.0079                  4096          32  off       
 libvirt-pool                 2048M                3.0        431.3T  0.0000                  3000           4  off       
 data                        66692G                3.0        431.3T  0.4529                  4096              warn      
 default.rgw.log              8146k                3.0        431.3T  0.0000                     8              warn      
 metadata                    54050M                4.0        431.3T  0.0005       
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

您会注意到,大部分数据位于存储所有QA结果的CephFS的“元数据”和“数据”池中。大多数其他池是各种测试遗留下来的,(大部分)是空的。

让我们看一下每一列:

  • SIZE列仅报告存储在池中的数据总量(以字节为单位)。 这包括对象数据和omap键/值数据。
  • TARGET SIZE报告有关池的预期大小的任何管理员输入。如果池刚刚创建,则最初不会存储任何数据,但管理员通常对最终将存储多少数据有所了解。如果提供,则使用此值或实际大小中的较大者来计算池的理想PG数。
  • RATE值是原始存储占用与存储的用户数据的比率,对于复本桶(bucket)来说,它只是一个复制因子,对于纠删码池来说,它是一个(通常)较小的比率。
  • RAW CAPACITY是池由CRUSH映射到的存储设备上的原始存储容量。
  • RATIO是池占用的总存储空间的比率。
  • TARGET RATIO是管理员提供的值,类似于TARGET SIZE,它表示用户预计池将占用集群总存储的多大部分。
  • 最后,PG_NUM是池的当前PG数量,而NEW PG_NUM(如果存在)是建议值。
  • AUTOSCALE列指示池的模式,可以是禁用、警告或启用。

建议的值考虑了几个输入,包括池占用(或预期占用)的整体群集的比例、池分布在哪些OSD上,以及每个OSD的目标PG数(由mon_target_pg_per_osd配置选项定义,默认为100)。autoscaler将始终选择一个2的幂的pg_num值,因为这对于Ceph而言效率更高(这意味着同一池中的所有PG的大小都大致相同),并且只有当建议的值大于实际值的三倍时,autoscaler才会建议更改pg_num。这意味着,在大多数情况下,不断增长的池的pg_num值在每次更改时都会跃升4倍,并且除非其大小有非常显著的变化,否则将倾向于保持相同的值。

首次设置集群时,通常设置池的target ratio很有帮助,以便autoscaler可以做出良好的初始决策。 例如,如果集群的主要用途是用于块存储,则可以将rbd池的target ratio设置为.8并启用PG auto-scaling:

$ ceph osd pool create foo 1
$ rbd pool init foo
$ ceph osd pool set foo target_size_ratio .8    #表示此pool占整体空间的80%
$ ceph osd pool set foo pg_autoscale_mode on
  • 1
  • 2
  • 3
  • 4

此时,集群将自行选择一个pg_num并将其应用于后台。

查看ceph 详细的pgm 和pg信息

ceph osd pool ls detail

您可以使用以下命令控制将pg_autoscale_mode用于新创建的池

$ ceph config set global osd_pool_default_autoscale_mode <mode> 
  • 1

最后扩容完后使用:

ceph osd pool set volumes pg_num_min 1024
ceph osd pool set volumes pg_num_max 1024

固定池的pgm大小,防止其随意伸缩。

我可以完全放手吗?

是。如果您为新池启用自动扩展,并在现有池上启用它,则随着数据存储在集群中,系统将向上扩展PG。

这种方法的唯一问题是在存储数据后调整PG计数会在集群中移动数据,这很昂贵。 根据经验,如果创建了一个空池,然后将其填充以占用集群的所有可用空间,那么写入的所有数据将在写入后大约移动一次。 这不是理想的选择-最好在创建池时提供target ratiotarget bytes值,以便选择适当的初始PG计数-但无知的开销至少是有限且合理的。

 

 

手动重平衡方案:

Ceph Balancer
从Luminous 开始,Ceph 新增的了balancer ,可以将PG 在各个OSD上自动迁移,已达到均衡的效果。推荐使用。

1)查看balancer 模块状态

ceph mgr module ls # 查看各个模块的状态
ceph balancer status

2)启用balancer 模块(默认enable)

ceph mgr module enable balancer

3)启用均衡(默认active 是false)

ceph balancer on

4)设置模式(修改PG mapping)

ceph balancer mode upmap

或设置模式(修改weight)

ceph balancer mode crush-compat

其中upmap 模式设置兼容版本

ceph osd set-require-min-compat-client luminous

Luminous 需要手动设置均衡计划?

ceph balancer eval #对集群所有pool进行权重调整计算,针对特定pool 采用 ceph balancer eval <POOL_NAME>
ceph balancer optimize plan2 #生成一个调优配置,或指定存储池 ceph balancer optimize plan2 default.rgw.buckets.data
ceph balancer eval plan2 #执行调优计算
ceph balancer show plan2 #查看调优计算最终的结果
ceph balancer execute plan2 #根据上面模拟计算的结果,执行最终的权重调整

5)查看调整结果

ceph osd df

6)关闭自动调整

ceph balancer off
ceph balancer status

OSD PG 数统计脚本:包含osd pool的排序,包含osd的排序,输出平均pg数目,输出最大的osd编号,输出最大超过平均值的百分比,输出最少pg的osd编号,输出最小低于平均值的百分比,
用于辅助查看集群各个OSD 的PG 分布情况,参考武汉-磨渣的博客《查询osd上的pg数》

ceph pg dump | awk ‘
/^PG_STAT/ { col=1; while($col!=”UP”) {col++}; col++ }
/^[0-9a-f]+\.[0-9a-f]+/ { match($0,/^[0-9a-f]+/); pool=substr($0, RSTART, RLENGTH); poollist[pool]=0;
up=$col; i=0; RSTART=0; RLENGTH=0; delete osds; while(match(up,/[0-9]+/)>0) { osds[++i]=substr(up,RSTART,RLENGTH); up = substr(up, RSTART+RLENGTH) }
for(i in osds) {array[osds[i],pool]++; osdlist[osds[i]];}
}
END {
printf(“\n”);
slen=asorti(poollist,newpoollist);
printf(“pool :\t”);for (i=1;i<=slen;i++) {printf(“%s\t”, newpoollist[i])}; printf(“| SUM \n”);
for (i in poollist) printf(“——–“); printf(“—————-\n”);
slen1=asorti(osdlist,newosdlist)
delete poollist;
for (j=1;j<=slen;j++) {maxpoolosd[j]=0};
for (j=1;j<=slen;j++) {for (i=1;i<=slen1;i++){if (array[newosdlist[i],newpoollist[j]] >0 ){minpoolosd[j]=array[newosdlist[i],newpoollist[j]] ;break } }};
for (i=1;i<=slen1;i++) { printf(“osd.%i\t”, newosdlist[i]); sum=0;
for (j=1;j<=slen;j++) { printf(“%i\t”, array[newosdlist[i],newpoollist[j]]); sum+=array[newosdlist[i],newpoollist[j]]; poollist[j]+=array[newosdlist[i],newpoollist[j]];if(array[newosdlist[i],newpoollist[j]] != 0){poolhasid[j]+=1 };if(array[newosdlist[i],newpoollist[j]]>maxpoolosd[j]){maxpoolosd[j]=array[newosdlist[i],newpoollist[j]];maxosdid[j]=newosdlist[i]};if(array[newosdlist[i],newpoollist[j]] != 0){if(array[newosdlist[i],newpoollist[j]]<=minpoolosd[j]){minpoolosd[j]=array[newosdlist[i],newpoollist[j]];minosdid[j]=newosdlist[i]}}}; printf(“| %i\n”,sum)} for (i in poollist) printf(“——–“); printf(“—————-\n”);
slen2=asorti(poollist,newpoollist);
printf(“SUM :\t”); for (i=1;i<=slen;i++) printf(“%s\t”,poollist[i]); printf(“|\n”);
printf(“Osd :\t”); for (i=1;i<=slen;i++) printf(“%s\t”,poolhasid[i]); printf(“|\n”);
printf(“AVE :\t”); for (i=1;i<=slen;i++) printf(“%.2f\t”,poollist[i]/poolhasid[i]); printf(“|\n”);
printf(“Max :\t”); for (i=1;i<=slen;i++) printf(“%s\t”,maxpoolosd[i]); printf(“|\n”);
printf(“Osdid :\t”); for (i=1;i<=slen;i++) printf(“osd.%s\t”,maxosdid[i]); printf(“|\n”);
printf(“per:\t”); for (i=1;i<=slen;i++) printf(“%.1f%\t”,100*(maxpoolosd[i]-poollist[i]/poolhasid[i])/(poollist[i]/poolhasid[i])); printf(“|\n”);
for (i=1;i<=slen2;i++) printf(“——–“);printf(“—————-\n”);
printf(“min :\t”); for (i=1;i<=slen;i++) printf(“%s\t”,minpoolosd[i]); printf(“|\n”);
printf(“osdid :\t”); for (i=1;i<=slen;i++) printf(“osd.%s\t”,minosdid[i]); printf(“|\n”);
printf(“per:\t”); for (i=1;i<=slen;i++) printf(“%.1f%\t”,100*(minpoolosd[i]-poollist[i]/poolhasid[i])/(poollist[i]/poolhasid[i])); printf(“|\n”);
}’
———————————–
Ceph OSDs 间的数据均衡
https://blog.51cto.com/dengchj/2944207

发表评论

邮箱地址不会被公开。 必填项已用*标注