十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
1 问题描述
创新互联建站是一家集网站建设,嘉禾企业网站建设,嘉禾品牌网站建设,网站定制,嘉禾网站建设报价,网络营销,网络优化,嘉禾网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。在ceph12和ceph14.2.8使用过程中遇到,当osd数量很多时(1000多个),pg需要设置很多(5、6万)时,ceph balancer status 或 ceph osd status等mgr命令会卡住很长时间才返回,其它mon等命令没问题。
2 问题排查
卡住的都是mgr相关命令,因此推测是mgr进程问题。
排查是osd多,还是pg多导致,这个很容易操作不详细介绍,通过实验是pg多导致的。下图是我的测试环境的ceph:
使用top -H命令可以发现mgr-fin线程cpu使用率经常达到100%。
使用ceph daemon mgr.ceph-212 perf dump查看mgr统计信息
mgr-fin线程cpu使用率经常达到100%,finisher队列数据量很大,队列又是mgr-fin一个线程在处理,mgr命令发给mgr后就进入finisher队列排队处理,导致mgr命令卡住。
Mgr参数说明:
"mgr_stats_period": "5" 默认为5秒,每5秒所有osd、mds和其它mgr会给主mgr发送一个MSG_MGR_REPORT消息,所有osd给主mgr发送MSG_PGSTATS消息
"mgr_tick_period": "2" mgr每隔2秒给mon发送beacon
“mgr_mon_messages” mgr-mon限流大值,默认为128
Mon参数说明:
"mon_mgr_digest_period": "5" 默认为5秒,每隔5秒,mon会给主mgr发送MSG_MGR_DIGEST
3 mgr介绍
mgr模块分担和扩展monitor的部分功能,减轻monitor的负担。入口在src/ceph_mgr.cc的main函数。
所有mgr服务启动时身份都是standby(初始化一个MgrStandby类对象),初始化一个monitor的客户端monc(MonClient类),调用monc.sub_want函数向monitor请求mgrmap(MSG_MGR_MAP消息)及相关msg。
在MgrStandby::ms_dispatch函数中处理收到的消息,既MgrStandby::handle_mgr_map函数处理MSG_MGR_MAP消息,发现自己在mgrmap为active时,会初始化mgr主服务进程,然后调用Mgr::background_init -->finisher.start()启动Finisher的线程 -->调用finisher.queue向Finisher的队列里添加任务,此任务为Mgr::init(),MgrStandby::send_beacon()。
Mgr::init函数
DaemonServer::init 初始化daemonServer:
初始化了一个mgr类型的Messenger msgr,监听有关mgr消息,收到消息后通过DaemonServer::ms_dispatch处理此消息,包括MSG_PGSTATS、MSG_MGR_REPORT、MSG_MGR_OPEN、MSG_MGR_CLOSE和MSG_COMMAND。
Mgr::load_all_metadata
向monitor节点发请求分别获取mds、osd和mon的元数据,然后根据这些元数据信息生成3个(分别记录mds、osd和mon的元数据)DaemonState的share_ptr添加到daemon_state中。
通过monc->sub_want函数向monitor发消息,分别获取log-info、mgrdigest、fsmap 、servicemap和osdmap。Mgr::ms_dispatch函数处理收到的消息,包括MSG_MGR_DIGEST、CEPH_MSG_MON_MAP、CEPH_MSG_FS_MAP、CEPH_MSG_OSD_MAP、MSG_SERVICE_MAP和MSG_LOG。
py_module_registry->active_start:
这个py_module_registry(PyModuleRegistry类对象)是在mgr服务启动时初始化一个MgrStandby类对象时初始化,然后初始化Mgr类时传进来。MgrStandby::init时调用py_module_registry.init函数(既PyModuleRegistry类的init)加载pyModule:
参数mgr_module_path的值(默认为/usr/share/ceph/mgr/)下所有目录中下面有文件module.py的目录的名字为pyModule的名字(源码中是src/pybing/mgr下的python模块)。为所有的这些pyModule生成类PyModule对象,调用mod->load加载modules,然后添加进modules中。
active_modules.reset(new ActivePyModules(...)) 重新初始化active_modules。
for (const auto &i : modules){
active_modules->start_one(i.second)
}
ActivePyModules::start_one:
modules[name].reset(new ActivePyModule(py_module, clog));
finisher.queue(new FunctionContext([this, active_module, name](int) {
int r = active_module->load(this);
active_module->thread.create(active_module->get_thread_name());
}
处理MSG_MGR_DIGEST消息: (默认每隔5秒,mon会给主mgr发送MSG_MGR_DIGEST)
Mgr::ms_dispatch函数里检查到消息类型是MSG_MGR_DIGEST时调用Mgr::handle_mgr_digest函数
cluster_state.load_digest(m) 从m中提取数cluster_state.health_json,
cluster_state.mon_status_json。
py_module_registry->notify_all("mon_status", "");
py_module_registry->notify_all("health", "");
py_module_registry->notify_all("pg_summary", "");
PyModuleRegistry::notify_all(const std::string ¬ify_type, const std::string ¬ify_id)
active_modules->notify_all函数 既ActivePyModules::notify_all
遍历modules中的ActivePyModule,创建一个任务添加到finisher队列里,此任务调
用ActivePyModule::notify:
调用pyModule的(源码中是src/pybing/mgr下的python模块下的module.py)的
notify函数
src/pybing/mgr/progress/module.py中的notify函数
当notify_type 是"osd_map"时,调用self._osdmap_changed检查是否有osd out了或有新osd加入。
旧的osd out,就调用self._osd_out查找被out的这个osd影响的pg,然后生成一个PgRecoveryEvent对象ev,self._events[ev.id] = ev
新osd加入,就调用self._osd_in检查self._events中是否有PgRecoveryEvent事件ev并且加入的osd在ev.evacuating_osds中,如果有,则结束此ev。
当notify_type 是"pg_summary"时:
data = self.get("pg_dump") 调用ceph_state_get函数 -->self->py_modules->get_python("pg_dump"),即ActivePyModules::get_python获取pg_map格式化后返回,当pg数量很多时,pg_map就会很大,获取pg_map并格式化比较耗时(当pg数量达到6万多时,我统计了下可达到5秒)。但是下面只有当字典self._events不为空时才有可能处理获取的pg_map数据,因此这一步很多时候是多余的,因此可以先判断self._events不为空时才获取pg_map,可以减轻mgr进程的压力。默认每隔5秒,mon会给主mgr发送MSG_MGR_DIGEST,mgr收到后,会执行到这里处理,因此这里很可能就是pg多时,mgr卡住的一个原因。
//这里的self._events中有两类event:PgRecoveryEvent和RemoteEvent。PgRecoveryEvent是正在进行的pg recovery事件(由前面的self._osd_out创建),RemoteEvent由update函数创建
for ev_id, ev in self._events.items(): //更新self._events
if isinstance(ev, PgRecoveryEvent):
ev.pg_update(data, self.log)
self.maybe_complete(ev)
src/pybing/mgr/progress/module.py中的update函数
如果self._events中有ev_id,则ev = self._events[ev_id],否则ev =RemoteEvent(ev_id, ev_msg, refs),self._events[ev_id] = ev。
ev.set_progress(ev_progress)
ev._refresh()
4 解决问题根据上面mgr的介绍和分析,pg多时,mgr卡住的一个原因可能是因为src/pybing/mgr/progress/module.py中的notify函数处理"pg_summary"时没有检查self._events是否为空,就调用self.get("pg_dump")获取并格式化pg_map,比较耗时,finisher队列是mgr-fin一个线程在处理,这里耗时太多,就导致finisher队列里数据来不及处理导致堆积。
因此可以在调用self.get("pg_dump")时,先检查self._events是否为空,如果为空就直接退出notify函数。
经过验证,加入此判断后,重启mgr,运行一段时间后,使用ceph daemon mgr.ceph-212 perf dump查看mgr统计信息:
查看mgr命令耗时:
可知,finisher队列数据量很小,mgr命令也可以很快返回,问题解决。
当然也可以直接升级ceph到14.2.22。
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧