1 bucket index背景简介
bucket index是整个RGW里面一个非常关键的数据结构,用于存储bucket的索引数据,默认情况下单个bucket的index全部存储在一个shard文件(shard数量为0,主要以OMAP-keys方式存储在leveldb中),随着单个bucket内的Object数量增加,整个shard文件的体积也在不断增长,当shard文件体积过大就会引发各种问题,常见的问题有:
-
对index pool进行scrub或deep-scrub的时候,如果shard对应的Object过大,会极大消耗底层存储设备性能,造成io请求超时。
-
底层deep-scrub的时候耗时过长,会出现request blocked,导致大量http请求超时而出现50x错误,从而影响到整个RGW服务的可用性。
-
当坏盘或者osd故障需要恢复数据的时候,恢复一个大体积的shard文件将耗尽存储节点性能,甚至可能因为OSD响应超时而导致整个集群出现雪崩。
本文重点在介绍一种方法去合理优化单个bucket的shard文件体积,目前受限于RGW的index构架设计,shard问题只能优化无法根治.(当然你也可以使用Indexless bucket)
indexless bucket介绍和使用可以参考下面内容
www.ksingh.co.in/blog/2017/0…
bing index问题介绍可以参考下文
cephnotes.ksperis.com/blog/2015/0…
2 index shard 优化基本思路
下面这些都是经验之谈,仅供各位参考:
-
index pool一定要上SSD,这个是本文优化的前提,没硬件支撑后面这些操作都是白搭。
-
合理设置bucket 的shard 数量
-
shard的数量并不是越多越好,过多的shard会导致部分类似list bucket的操作消耗大量底层存储IO,导致部分请求耗时过长。
-
shard的数量还要考虑到你OSD的故障隔离域和副本数设置。比如你设置index pool的size为2,并且有2个机柜,共24个OSD节点,理想情况下每个shard的2个副本都应该分布在2个机柜里面,比如当你shard设置为8的时候,总共有8*2=16个shard文件需要存储,那么这16个shard要做到均分到2个机柜。同时如果你shard超过24个,这很明显也是不合适的。
-
控制好单个bucket index shard的平均体积,目前推荐单个shard存储的Object信息条目在10-15W左右,过多则需要对相应的bucket做单独reshard操作(注意这个是高危操作,谨慎使用)。比如你预计单个bucket最多存储100W个Object,那么100W/8=12.5W,设置shard数为8是比较合理的。shard文件中每条omapkey记录大概占用200 byte的容量,那么150000*200/1024/1024 ≈ 28.61 MB,也就是说要控制单个shard文件的体积在28MB以内。
-
业务层面控制好每个bucket的Object上限,按每个shard文件平均10-15W Object为宜。
3 如何判断线上shard符合的要求
查看index pool名称
root@demo:/home/user# ceph df
GLOBAL:
SIZE AVAIL RAW USED %RAW USED
92114M 88218M 3895M 4.23
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
rbd 0 131 0 87674M 2
.rgw.root 16 324 0 87674M 2
.zone.rgw.root 17 1279 0 87674M 2
.zone.rgw.domain 18 1480 0 87674M 8
.zone.rgw.control 19 0 0 87674M 8
.zone.rgw.gc 20 0 0 87674M 32
.zone.rgw.buckets.index 21 0 0 87674M 32 #index pool
.zone.rgw.buckets.extra 22 0 0 87674M 54
.zone.rgw.buckets 23 768M 0.83 87674M 254
.zone.log 24 0 0 87674M 11
.zone.intent-log 25 0 0 87674M 0
.zone.usage 26 0 0 87674M 2
.zone.users 27 34 0 87674M 3
.zone.users.email 28 0 0 87674M 0
.zone.users.swift 29 0 0 87674M 0
.zone.users.uid 30 1013 0 87674M 5
复制代码
查看bucket的shard设置
shard参数介绍
rgw_override_bucket_index_max_shards #用于单机模式
bucket_index_max_shards #用于集群模式
注意默认0表示不做shard切分,最大设置为7877,该参数在集群初始化阶段设置,并且需要重启所有rgw服务才生效,特别注意的是非特殊情况不要在已经上线的生产系统进行调整。
复制代码
下面以集群模式为例
获取集群模式下的shard设置
root@demo:/home/user# radosgw-admin region get --name client.radosgw.zone1
{
"name": "zone",
"api_name": "zone",
"is_master": "true",
"endpoints": [
"http:\/\/demo.ceph.work:80\/"
],
"hostnames": [],
"master_zone": "zone1",
"zones": [
{
"name": "zone1",
"endpoints": [
"http:\/\/demo.ceph.work:80\/"
],
"log_meta": "true",
"log_data": "true",
"bucket_index_max_shards": 8 #shard数为8
}
],
"placement_targets": [
{
"name": "default-placement",
"tags": []
}
],
"default_placement": "default-placement"
}
复制代码
获取单机模式下的shard设置
root@demo:/home/user# ceph --admin-daemon /home/ceph/var/run/ceph-client.radosgw.zone1.asok config show|grep rgw_override_bucket_index_max_shards
"rgw_override_bucket_index_max_shards": "0",
复制代码
查看bucket列表
root@demo:/home/user# radosgw-admin bucket list --name client.radosgw.zone1
[
"multi-upload",
"demo-abc",
"test1",
"user-bucket1"
]
复制代码
获取multi-upload这个bucket 的ID
root@demo:/home/user# radosgw-admin bucket stats --bucket=multi-upload --name client.radosgw.zone1
{
"bucket": "multi-upload",
"pool": ".zone.rgw.buckets",
"index_pool": ".zone.rgw.buckets.index",
"id": "zone1.14214.10", #bucket ID
"marker": "zone1.14214.10",
"owner": "u-user",
"ver": "0#1,1#3,2#345,3#1,4#1,5#1,6#681,7#5",
"master_ver": "0#0,1#0,2#0,3#0,4#0,5#0,6#0,7#0",
"mtime": "2017-05-05 10:23:12.000000",
"max_marker": "0#,1#00000000002.20.3,2#00000000344.367.3,3#,4#,5#,6#00000000680.711.3,7#00000000004.23.3",
"usage": {
"rgw.main": {
"size_kb": 724947,
"size_kb_actual": 725308,
"num_objects": 114
},
"rgw.multimeta": {
"size_kb": 0,
"size_kb_actual": 0,
"num_objects": 51
}
},
"bucket_quota": {
"enabled": false,
"max_size_kb": -1,
"max_objects": -1
}
}
复制代码
获取multi-upload这个bucket的shard文件对应的Object列表
上面查到shard为8,所以下面有编号为0~7的几个文件。
root@demo:/home/user# rados ls -p .zone.rgw.buckets.index |grep "zone1.14214.10"
.dir.zone1.14214.10.5
.dir.zone1.14214.10.1
.dir.zone1.14214.10.7
.dir.zone1.14214.10.6
.dir.zone1.14214.10.4
.dir.zone1.14214.10.3
.dir.zone1.14214.10.0
.dir.zone1.14214.10.2
复制代码
统计所有bucket shard的omapkeys条目数,总共1329个
每条omapkeys预计占用200 bytes的存储空间,因此1329个omapkeys总共占用的磁盘空间为
1329*200 = 265800 bytes
root@demo:/home/ceph/var/lib/osd/ceph-2# rados ls -p .zone.rgw.buckets.index |grep "zone1.14214.10"|awk '{print "rados listomapkeys -p .zone.rgw.buckets.index "$1 }'|sh -x|wc -l
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.5
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.1
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.7
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.6
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.4
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.3
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.0
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.2
1329
复制代码
查看每个bucket shard文件的omapkeys条目数,以“.dir.zone1.14214.10.6”为例
926*200 = 185200 bytes ≈ 180kb 满足需求
root@demo:/home/ceph/var/lib/osd/ceph-2# rados ls -p .zone.rgw.buckets.index |grep "zone1.14214.10"|awk '{print "rados listomapkeys -p .zone.rgw.buckets.index "$1 " |wc -l"}'|sh -x
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.5
+ wc -l
0
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.1
+ wc -l
3
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.7
+ wc -l
5
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.6
+ wc -l
926
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.4
+ wc -l
0
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.3
+ wc -l
0
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.0
+ wc -l
0
+ rados listomapkeys -p .zone.rgw.buckets.index .dir.zone1.14214.10.2
+ wc -l
395
复制代码
细心的各位会发现上面的shard分布极不均匀,那是由于每个Object存储的时候查找对应的shard用的是hash(Object_name)再取余的方式,具体参考下面代码,如果Object名称非常接近,就容易造成bucket shard分布不够均匀的情况。
int RGWRados::get_bucket_index_object(const string& bucket_oid_base, const string& obj_key,
uint32_t num_shards, RGWBucketInfo::BIShardsHashType hash_type, string *bucket_obj, int *shard_id)
{
int r = 0;
switch (hash_type) {
case RGWBucketInfo::MOD:
if (!num_shards) {
// By default with no sharding, we use the bucket oid as itself
(*bucket_obj) = bucket_oid_base;
if (shard_id) {
*shard_id = -1;
}
} else {
uint32_t sid = ceph_str_hash_linux(obj_key.c_str(), obj_key.size());
uint32_t sid2 = sid ^ ((sid & 0xFF) << 24);
sid = sid2 % MAX_BUCKET_INDEX_SHARDS_PRIME % num_shards;
char buf[bucket_oid_base.size() + 32];
snprintf(buf, sizeof(buf), "%s.%d", bucket_oid_base.c_str(), sid);
(*bucket_obj) = buf;
if (shard_id) {
*shard_id = (int)sid;
}
}
break;
default:
r = -ENOTSUP;
}
return r;
}
复制代码
4 如何缓解 index shard 过大造成影响
下篇再讲