概述
Ceph OSD处理OP,snap trim,scrub的是相同的work queue - osd::op_shardedwq
研究该shardedwq,有利于我们对snap trim和scrub的配置参数调整;
相关数据结构
这里主要涉及到两个数据结构:
class PGQueueable
class ShardedOpWQ
class PGQueueable
这个是封装PG一些请求的class,相关的操作有:
OpRequestRef
PGSnapTrim
PGScrub
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_OP
MSG_OSD_SUBOP
MSG_OSD_SUBOPREPLY
MSG_OSD_PG_BACKFILL
MSG_OSD_REP_SCRUB
MSG_OSD_PG_UPDATE_LOG_MISSING
MSG_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 = 30
osd_op_num_threads_per_shard = 2
//默认值
所以一旦某个shard对应的一个thread被占用了,对应处理该shard的只有一个thread了,这样就有可能影响映射到该shard上的PG的正常IO了。