记一次radosgw数据量大后排除告警

最近往ceph对象存储中,灌了1年的历史数据,大概4 5千万个文件进去以后,集群开始告警,这篇文章简要的记录了排除过程。由于排除的时间跨度有点长,大部分输出都没有了,只能写下大概的过程

pg中的对象太多

ceph health detail后,会提示 pool XXX has many more objects per pg than average ,提示内容其实说的很明白了。就是说某个池里单个pg的对象太多了,如果要消除这个,要么是删掉不用的pool,或者减少其他pool中的pg数量,要么就是这个池增长。由于ceph不支持直接减少pg数量,我们选择了扩容。 请注意,调整pg数量,会导致大量的数据需要平衡,平衡过程中如果有节点挂掉,可能会导致这个池无法写入,请评估风险。

增加的方法很简单,在管理节点执行下面的语句就完了

1
2
ceph osd pool set {pool-name} pg_num {pg_num}
ceph osd pool set {pool-name} pgp_num {pgp_num}

pg和pgp数量应该是一致的,而且最好是2的指数倍。

改完以后,噩梦就开始了,ceph -s 会提示

1
2
3
4
5
6
7
8
xxxxx/yyyyy objects misplaced (52.642%)
903 active+clean
123 active+remapped+backfilling
46 active+remapped+backfill_wait
9 active+undersized+degraded+remapped+backfilling
7 active+undersized+degraded+remapped+backfill_wait

recovery: 8256 kB/s, 158 objects/s

可以看到开始平衡了,然而默认参数下,速度极慢,1计算,会发现要好几天才能平衡完毕。

先按照网上的教程,把并发调大

1
2
ceph tell 'osd.*' injectargs '--osd-recovery-max-active 4'
ceph tell 'osd.*' injectargs '--osd-max-backfills 16'

会发现,恢复速度会有不小提升。然而过了半天再看,会发现又下降了回来。

真正很有效的参数是下面这个

1
ceph tell osd.* injectargs '--osd_recovery_sleep_hdd 0'

ceph在默认情况,ceph在恢复的间隔进行睡眠,默认0.1秒,可能是为了避免恢复造成压力,也可能是为了保护硬盘。将休眠关闭以后,恢复速度会基本达到网卡或者硬盘的性能极限。

数据平衡完毕以后,建议改回默认值

1
2
3
ceph tell 'osd.*' injectargs '--osd-recovery-max-active 3'
ceph tell 'osd.*' injectargs '--osd-max-backfills 1'
ph tell osd.* injectargs '--osd_recovery_sleep_hdd 0.1'

index文件过大

rehard

ceph -s 会有下面的字样

1
2 large objects found in pool 'xxxx.buckets.index'

一般的做饭是直接分片,shard数量根据实际的对象数量来预估。不超过每个shard,10万个

1
radosgw-admin reshard --bucket=xxx --num-shards=yyy

然并卵,这样多半要失败,而且会留下垃圾数据

检查一下,bucket-name替换为实际的桶名称

radosgw-admin metadata get bucket:bucket-name

找到bucket_id字段,替换下面的id

radosgw-admin metadata get bucket.instance:bucket-name:bucket_id

num_shards就是目前实际的shard数量,如果上面的reshard失败了,这个值还会是个比较小的值。

改为后台运行

radosgw-admin reshard add –bucket=realname-images –num-shards=768

用下面的命令查询进度

1
radosgw-admin reshard list

查询可以看到新的bucketid,然而,ceph并不会删除老的元数据。必须自己手动清理。

删除老的元数据

首先确认下是不是真的是bucket的key太多。看看到底有多少key

1
2
for i in `rados -p .default.rgw.buckets.index ls`; do echo -n "$i:"; rados -p default.rgw.buckets.index listomapkeys $i |wc -l; done > omapkeys
sort -t: -k2 -r -n omapkeys |head

先检查一下

1
2
3
4
5
for bucket in $(radosgw-admin bucket list | jq -r .[]); do
bucket_id=$(radosgw-admin metadata get bucket:${bucket} | jq -r .data.bucket.bucket_id)
marker=$(radosgw-admin metadata get bucket:${bucket} | jq -r .data.bucket.marker)
echo "$bucket:$bucket_id:$marker"
done

如果同一个桶出现一次以上,就说明还有老数据,用下面的脚本生成删除命令

1
2
3
4
5
6
7
8
for bucket in $(radosgw-admin bucket list | jq -r .[]); do
bucket_id=$(radosgw-admin metadata get bucket:${bucket} | jq -r .data.bucket.bucket_id)
marker=$(radosgw-admin metadata get bucket:${bucket} | jq -r .data.bucket.marker)
for instance in $(radosgw-admin metadata list bucket.instance | jq -r .[] | grep "^${bucket}:" | grep -v ${bucket_id} | grep -v ${marker} | cut -f2 -d':'); do
echo radosgw-admin bi purge --bucket=${bucket} --bucket-id=${instance}
echo radosgw-admin metadata rm bucket.instance:${bucket}:${instance}
done
done

如果嫌麻烦,可以把echo去了就是直接删除,我个人还是建议手工检查一下,再人工执行删除,另外,我个人非常不建议用rados rm来删除

以为这就完了?

扫描一下

虽然对象已经删除了,但是告警是还在的。需要手动扫描一下才行,看看是哪些pg里的多

1
for i in `ceph pg ls-by-pool default.rgw.buckets.index  | tail -n +2 | awk '{print $1}'`; do echo -n "$i: "; ceph pg $i query |grep num_large_omap_objects | head -1 | awk '{print $2}'; done | grep ": 1"

再扫描

1
ceph pg deep-scrub  11.3c

插曲

全部弄完以后,添加新的机器到集群中,发现新节点1启动,就会自杀,而且还有一个老节点也挂掉。搜索日志可以看到

1
map e2579 wrongly marked me down at e2579

没办法,先设置ceph osd set nodown , 数据平衡了一段时间以后,发现很多pg卡在inactive。再其他osd上查看。可以看到下面的日志

1
2
 heartbeat_check: no reply from 10.174.100.6:6801 osd.3 ever on either front o
r back, first ping sent 2019-04-11 20:48:40.825885 (cutoff 2019-04-11 20:49:07.530135)

然而直接telnet一切正常。最后排查

netstat -ant |sort -k4 发现没有指向某个ip的链接。 登录到指定的主机一看。原来运维把这台机器的ip设置错了,吐血。根据网上其他人的经验来看,inactive一般是selilux或者网络方面的问题