ceph mgr 做为 ceph 12.2 主推的功能之一,是负责 ceph 集群管理的组件。本文深入介绍 ceph mgr 的工作原理,目的是提供一个思维框架,在该组件出现问题或是有新的需求时,读者有能力修改源码对其进行改进。
监控是管理的第一步,所以 ceph-mgr 目前的主要功能是把集群的一些指标暴露给外界使用。监控是什么东西呢?举个例子,例如用户访问网站 5xx 了,那么监控就是这么一个系统:采集网站 5xx 的个数,存起来,然后在 5xx 多的时候通过报警短信报给开发,然后为开发解决该问题提供其他信息(例如日志,指标图表)。所以监控系统是一个数据系统,包含采集,存储,分析(包含报警),可视化,这几个部分。
关于监控,在此之前,ceph 以及社区有不少尝试。
calamari。calamari 是 ceph 背后的公司 Inktank 为 ceph 企业版开发的监控管理程序,在 Red Hat 收购该公司后开源,目前基本处于停滞状态。其基本原理是利用 salt 远程执行 python 脚本,该脚本通过 ceph 每个守护进程暴露在本地的 admin socket 采集到数据或者执行命令。其主要包含几部分:
评价:
cephmetrics。基本原理是基于 collectd 插件,从 admin socket 中采数据发往 graphite,用 grafana 做图。
评价:
ceph_exporter。基本原理是利用 librados,从 ceph monitor 中取数据,通过 http 协议把指标以 prometheus 规定的格式暴露出来。
评价:
在以上背景下,ceph 官方开发了 ceph-mgr,主要目标实现 ceph 集群的管理,为外界提供统一的入口。要深入了解 ceph-mgr,就得了解 ceph-mgr 是如何跑起来的。
由 官方文档 可知,ceph-mgr 是通过可执行文件 ceph-mgr
跑起来的,在源码src/CMakeLists.txt
搜索 ceph-mgr
可以搜到 add_executable(ceph-mgr ${mgr_srcs}...
,从中可以看出 ceph-mgr 主要由 src/mgr
里的文件编译出来(猜也猜的出来),main 函数在 src/ceph_mgr.cc
。以上就是相关文件,有需要深入的人可以去读,这里介绍整理之后的 ceph-mgr 工作原理。
ceph-mgr 工作的模式是事件驱动型的,意思就是等待事件,事件来了则处理事件返回结果,又继续等待。其主要运行的线程包括:
mgrmap
, osdmap
,monitor 会在这些数据发生变化时把事件通知到 messenger 监听的端口。事件处理器包括:
mgrmap
,就是当主挂掉时要顶上来,当自己不是主时要退回去。什么时候切主由 monitor 管理,所以 MgrStandby 里切主逻辑比较简单,有一个 Mgr
实例,当收到 mgrmap 时生成该实例,存到 MgrStandby 属性里,就完了。因为在收到消息时,MgrStandby 如果看到有 Mgr
实例,就会把消息发到它那处理,在定时函数里,也会调用 mgr 的定时函数,这样,实际上,MgrStandby 就担起了主的任务。mon_map
,fs_map
,osd_map
等事件,在内存中维护了集群成员信息,它管理 ceph-mgr 插件,为插件提供了所有数据的来源,也在特定事件发生时通知给 ceph-mgr 的插件,例如插件的 notify
函数,就是被 Mgr 回调的。pg scrub
等。serve
。plugin 可以在 serve 里跑个 http server 来提供对外服务,ceph-mgr 为 plugin 提供了 get
,get_server
等函数,这些函数返回关于集群的指标等数据。例如 prometheus 插件,就把 ceph 内部指标通过 http 协议以 prometheus 格式暴露出来,使得监控 ceph 集群变得较为简单。ceph 是 c++ 写的,ceph 会调用 python plugin 定义的方法(例如 serve),python plugin 可以调用 c++ 定义的函数(例如 get
),python/c++ 的互调是 python 提供的机制,其基本原理是:
PyObject
,模块,函数、类、数据都是。cpython 提供了 PyImport_Import
用于通过名字得到 m模块对象对应的 PyObject,类可以通过 PyObject_GetAttrString
取模块的属性得到,以此类推,cpython 还提供了由 c 类型的值生成对应 python 类型的值的PyObject 的方法,例如 PyObject* PyString_FromString(char *)
。有函数对象,有参数对象,就可以通过 PyObject * PyObject_CallObject()
调用函数,将得到的 PyObject* 再转回 c++ 类型就 OK 了。PyObject* ceph_state_get(PyObject *self, PyObject *args)
,在函数里里面通过 PyArg_ParseTuple(args, "ss:ceph_state_get", &handle, &what)
把参数解析为 c++ 类型,就实现了一个 Python 函数。通过 PyMethodDef CephStateMethods[] = get
把 Python 函数加入到一个注册表里。通过 Py_InitModule("ceph_state", CephStateMethods)
,将注册表里的函数定义为 ceph_state
模块的属性,并把该模块注入到 python sys.path 里,python 就可以通过 ceph_state.ceph_state_get
调用该函数了。