概述
Ceph OSD处理OP,snap trim,scrub的是相同的work queue - osd::op_shardedwq
研究该shardedwq,有利于我们对snap trim和scrub的配置参数调整;
相关数据结构
这里主要涉及到两个数据结构:
class PGQueueableclass ShardedOpWQ
class PGQueueable
这个是封装PG一些请求的class,相关的操作有:
OpRequestRefPGSnapTrimPGScrub
1 | class PGQueueable { |
class ShardedOpWQ
这个是OSD中shard相关线程的work queue类,用来处理PGQueueable封装的三类PG操作;
1 | class OSD : public Dispatcher, public md_config_obs_t |
op_shardedwq对应的thread pool为:osd_op_tp
osd_op_tp的初始化在OSD的初始化类中:
1 | osd_op_tp(cct, "OSD::osd_op_tp", "tp_osd_tp", |
这里相关的配置参数有:
osd_op_num_threads_per_shard,默认值为 2osd_op_num_shards,默认值为 5
PG会根据一定的映射模式映射到不同的shard上,然后由该shard对应的thread处理请求;
ShardedOpWQ的处理函数
该sharded的work queue的process函数如下:
1 | void OSD::ShardedOpWQ::_process(uint32_t thread_index, heartbeat_handle_d *hb ) |
从上面可以看出在调用实际的处理函数前,就先获取了PG lock;处理返回后释放PG lock;
osd::opshardedwq的_process()函数会根据request的类型,调用不同的函数处理:
OSD::dequeue_op()ReplicatedPG::snap_trimmer()PG::scrub()
在文件osd/OSD.cc中有这三类操作的不同处理函数定义:
1 | void PGQueueable::RunVis::operator()(OpRequestRef &op) { |
OSD操作的处理函数
1 | /* |
PG scrub的处理函数
1 | /* Scrub: |
分析
Ceph PG lock的粒度
从函数OSD::ShardedOpWQ::_process()中看出,thread在区分具体的PG请求前就获取了PG lock,在return前释放PG lock;这个PG lock的粒度还是挺大的,若snap trim和scrub占用了PG lock太久,会影响到OSD PG正常的IO操作;
OSD PG相关的OP类型有(OSD::dequeue_op()函数处理):
CEPH_MSG_OSD_OPMSG_OSD_SUBOPMSG_OSD_SUBOPREPLYMSG_OSD_PG_BACKFILLMSG_OSD_REP_SCRUBMSG_OSD_PG_UPDATE_LOG_MISSINGMSG_OSD_PG_UPDATE_LOG_MISSING_REPLY
osd_snap_trim_sleep和osd_scrub_sleep配置
从上面看g_conf->osd_snap_trim_sleep和g_conf->osd_scrub_sleep配置为非0后,能让snap trim和scrub在每次执行前睡眠一段时间(不是random时间),这样能一定程度上降低这两个操作对PG IO ops的影响(获取PG lock);
如果设置了osd_snap_trim_sleep或osd_scrub_sleep为非0,处理的线程会sleep,这样虽说释放了PG lock,但是占用了一个PG的一个处理线程,所以才有贴出来的ceph bug - http://tracker.ceph.com/issues/19497
现在我们配置的是:
osd_op_num_shards = 30osd_op_num_threads_per_shard = 2//默认值
所以一旦某个shard对应的一个thread被占用了,对应处理该shard的只有一个thread了,这样就有可能影响映射到该shard上的PG的正常IO了。