master 组件、minitor 组件与服务器管理框架
在前面的介绍中,我们知道 pomelo 支持动态地增加以及删除某一个服务器,于是我们会问当增加一个应用服务器的时候,已经启动的应用服务器是怎么知道新增加了一个服务器的;当停止某个服务器时,其他服务器又是怎样获知这些消息,并使得以后的 rpc 或者消息不路由到已经停止的服务器的。还有,如果查看整个服务器群的信息,或者整个服务器群的运行状态。诸如此类的问题,pomelo 提供了一个管理框架,通过对这个框架进行扩展,用户将可以自己定制一些需要监控的信息,下面将对此进行介绍。pomelo 管理框架
pomelo 的管理框架中,将对应的主体分为三种角色,分别为 master,monitor,client。其中 master 可以认为对应于 master 服务器的 Master 组件,monitor 可以认为是所有服务器都加载的 Monitor 组件。而 client,可以认为是第三方的管理工具,pomelo 提供的命令行工具,pomelo-cli 以及 admin-console-web 都扮演了 client 角色。
一般情况下,监控管理模型大致可以分为两类:
- master 向 monitor 发出请求某些监控信息,monitor 向 master 上报其信息,master 获得到信息后进行缓存。第三方的 client 会连接到 master上,请求整个服务器群的监控信息,master 将缓存的监控信息返回给client;
- client 连接到 master 上后,给 master 发送一条命令,比如请求关服务器命令,master 获得这个命令后,也就是关闭服务器命令后,master 会向 monitor 广播此关闭命令,每一个 monitor 收到关闭命令后,关闭自身。

在上面类图中,Master 组件,Monitor 组件,AdminClient 分别扮演我们上面提到的 master,monitor 和 client 角色,下面的叙述中将对这些术语不加区分的混用。
- 对于 Master 端,MasterConsoleService 会管理所有已注册的 Module,生成以 ModuleId 为主键的 Module 的 map。MasterAgent 监听端口,承受来自 monitor 和 client 的连接与注册,接受 monitor 和 client 的 request/notify,向 monitor 发送 request/notify,需要注意的是,master 不会向 client 发出 request/notify,只会针对 client 的 request 进行 response;
- 对于 Monitor 端,MonitorConsoleService 会管理所有已注册的 Module,维护 Module 的 map。所有的服务器通过配置文件都能获知到 master 服务器的监听地址和端口,MonitorAgent 会主动发起连接到 master,并维护对应的连接,然后通过此连接与 master 端通信;
- 对于 client 端,要求使用一个用户名和口令主动发起到 master 的连接及注册,验证通过后,AdminClient 会维护到 master 的连接,然后就可以向 master 发送 request/notify 了;
- 所有与通信相关的类,都为维护自己的 socket 信息,对于 Master 来说,不仅仅有连接的 socket,还有监听的socket。在整个管理框架中,通信层使用的 socket.io;
- 每一个 Module 会定义四个回调 monitorHandler,masterHandler,clientHandler,start,对于不同用途的Module,可能会省略掉一些用不着的回调函数定义,也就是说这四个回调都是可选的。每一个回调函数的签名为 XXXHandler(agent, msg, cb),第一个参数指出调用的 Agent,可以是 MonitorAgent 或者 MasterAgent,第二个参数是 request/notify 中的请求体,第三个是回调函数,如果是请求的话,最后结果通过回调第三个参数返回结果,否则的话,忽略第三个参数。

实际上,控制流程是多个,这里为了省事,将所有流程都画到一个图中了,对于后面的一些行为实际上是可以没有先后顺序的,希望读者能够甄辨。
master 组件的启动
master 服务器总是率先启动,Master 组件在其 start 调用的最后才会调用 Starter.start,Starter.start 才会启动所有的应用服务器,因此 Master 组件总是最先 start。在 Master 组件的 start 调用中,会完成以下几步:- 加载注册 Module 到 MasterConsoleService,Module 的导出方式有两种,可以导出工厂函数,也可以导出对象,如果导出工厂函数的话,其签名应该是 FacFunc(opts,ConsoleServicee),其中 opts 是用户调用 app.registerAdmin 的时候传入的,ConsoleService 则是具体的加载注册 Module 的 MasterConsoleService;
- 在加载注册完所有的 Module 后,会开启 MasterAgent 对端口的监听,此时,master 就已经可以接收来自 monitor 和 client 的 request 和 notify 了;
- 开启监听后,MasterConsoleService 会 enable 所有的 module,这步操作主要是看看有没有 module 配置了周期性地拉去 monitor 信息,也就是 module 的配置中有 type 选项和 interval 选项,且 type 的值为 'pull',interval 指定了周期,则认为其配置了周期性监控操作,此时会完成周期性事件的调度,使得 master 可以周期性地获取监控信息;
- 最后如果有 Module 定义了 start 回调,将会在这里调用,一般在 start 回调里会做一些初始化信息。 经历了这些步骤后,master 完成启动。
monitor 组件的启动
由于应用服务器是在 Master 组件启动后期才创建,因此 monitor 总是后于 master 启动。monitor 的启动过程与 master 类似,唯一不同的就是,monitor 会发起到 master 的连接,而不是监听接口。monitor 中同样也会使用与 master 完全相同的方式,加载注册 Module,如果有 Module 配置了周期性地推送监控数据到 master 的话,即其配置 type 的值为 'push',这里也会调度对应的事件,使得能够周期地推送数据。最后如果有 Module 定义了 start 的话,则会回调 start。Monitor 的启动过程与 master 基本一致。client 的连接注册
client 会连接注册到 master 上,因此,client 需要在 master 开始监听端口后,才能成功连接上,在连接到 master 上后,基于安全的缘故,master 需要使用用户名和密码对其进行验证,具体的客户端验证的配置文件为 config/adminUser.json,例子程序里有相应的配置示例。如果 master 提供的用户名和密码,通过了验证,那么客户端就在 master 上注册成功,就可以给 master 发 request/notify 了。周期触发
对于配置了 type 和 interval 的 Module,它们被认为是需要周期性进行回调的,在前面的 enable module 阶段,已经对其进行了调度。如果配置的 type 为 'pull',那么每隔 interval 秒,在 master 端,其对应的 masterHandler 将会被回调,回调的时候,不会传入参数。主动请求
- 当有 monitor 向 master 发出 request/notify 的时候,请求参数会指出相应的 ModuleId 以及回调调用的参数,在 master 端,对应的 Module 的 masterHandler 将会被回调,此时回调会使用 monitor 请求中携带的参数。因此,通过对 masterHandler 请求的参数进行判断就可以区分到底是周期性任务还是 monitor 请求;
- 对于 monitor 端,与 master 类似,当某个 Module 配置了 type 为 'push' 的时候,其对应的 monitorHandler 将会被回调,当 master 给 monitor 发送 request/notify 的时候,其对应的 monitorHandler 也同样会被回调。与 master 一样,可以通过调用是否有参数进行区分是周期性的任务还是接收到了 master 的消息。当然,即使是 master 的消息,也可能没有携带任何参数,这种情况只能由用户自己处理了,一般来说,为了便于区分,不要发送不带参数的 request/notify;
- client 在连接到 master 上后,client 可以向 master 发送 request/notify,请求信息中带有 ModuleId 和对应的回调参数。master 接受后,对应 Module 的 clientHandler 将会被回调。这里要注意的是 master 不会主动向 client 发送 request/notify,只会对 client 的消息进行响应。
以上的用例行为基本上描述了 pomelo 的管理框架的执行流,下面会对 pomelo 内建的两个 module 做一些分析。
watchdog 分析
我们知道对于服务器配置的静态信息可以从配置文件中直接读取,但是由于服务器可以在运行时增加和停止,而整个服务器群的其他服务器也需要获知具体的服务器的动态信息,就需要一种机制来实现这一切。
pomelo 是通过内建的 Module watchdog 实现这一切的,下面继续通过选取典型的用例场景,使用非正式的时序图来说明其流程:

绑定连接/断开事件
在加载 watchdog 这个 module 时,在 master 端,除了会监听端口外,还做了一件很重要的工作,就是将底层 socket 的事件由 MasterAgent 捕捉后,重新抛出,由 MasterConsoleService 捕捉后进行处理,这些事件为:- register 事件,即一旦有 MonitorAgent 发起到 MasterAgent 的连接时触发,MasterConsoleService 会在这个事件的处理中,发起广播通知增加的服务器信息;
- disconnect 事件,即一旦有 MonitorAgent 断开连接时触发,MasterConsoleService 会在这个事件处理中,发起广播通知有服务器离开的消息;
- reconnect 事件,是当有应用服务器重连时触发,MasterConsoleService 会在这个事件处理中,发起广播通知有服务器重连的消息。
新增服务器
用例行为 4 展示了在 monitor 端,加载 watchdog 这个 module 的时候,会在 start 阶段,执行 watchdog 的 start,在这里,monitor 会向 master 发起一个订阅请求,也就是说此时 monitor 请求订阅所有的服务器变化信息,当 MasterAgent 接收到请求时,masterHandler 会回调,通过检查参数,获知是一个 subscribe 操作,masterHandler 的回调中会返回所有目前已经启动的服务器的信息给这个新启动的服务器,并将其加入到监听者列表,以后每次再有服务器变动的时候,也会将具体的服务器变动消息发送给此服务器。用例行为 3 展示了,当新增一个服务器的时候的交互行为,有 monitor 发起到 master 的注册请求,从而激发了 master 端的 register 事件处理,其行为为通过 MasterAgent 广播新增服务器的 notify 到所有已经订阅注册的服务器,这些服务器收到 notify 后,其 monitorHandler 被回调,在 monitorHandler 中会调用 app.addServers 方法,这样所有的服务器群都会获知新增的服务器。
停止服务器
用例行为 5 展示了当有应用服务器断开的情况,当有服务器断开的时候,会激发 MonitorAgent 的 disconnect 事件,在这个事件处理中,MasterConsoleService 会发起广播 notify 到所有的服务器,其他的服务器收到此 notify 后,monitorHandler 会被回调,在回调中,通过判断参数,获知是有服务器停止工作,调用 app.removeServer 删除相应的服务器。同时,在 master 端,watchdog 的监听者列表里也会将这个服务器的信息删除。服务器重连
用例行为 6 展示了当有应用服务器断开重连的情况,具体行为跟前面的服务器加入和离开类似,读者可以结合源码自行分析。watchdog 是 pomelo 内部很核心的一个 module,用来完成服务器状态信息交换。因此在这个 module 中仅仅涉及到 master、monitor 角色,没有 client 角色,因此省略了与 client 有关的 clientHandler 回调函数的定义。其事件是由底层 socket 连接来激发的,而不是周期性地由定时器激发,所以在 module 的定义中并没有指定其 type 和 interval 配置。
console 分析
这里在简单分析一下 console 组件,console 组件主要为 pomelo 命令行工具服务。

图中所示的用例为一般情况下,用户通过一个命令来管理整个服务器群的方式。我们以命令行工具的 list 命令为例子来说明:
- 用户执行 pomleo list [options],此时,命令行工具会创建一个 AdminClient,然后向 master 发出注册请求,后面的参数用来指定 master 的位置,端口号以及向 master 注册所使用的用户名和口令,master 用此来进行校验身份,给予不同的权限。其具体的参数以及参数默认值,在 pomelo 命令行工具里面会有详细的介绍;
- 当AdminClient 向 Master 注册成功后,给其发送请求,参数部分指定了 moduleId 和具体要做的操作,在我们这个例子中,moduleId 就是 console,具体的操作为 list 命令;
- 在 master 端,收到请求后,其 console module 的 clientHandler 被回调,在回调中,通过判断其操作是 list,于是向所有与其连接的 monitor 请求服务器信息;
- 在 monitor 端,收到 master 发出的请求后,其 console module 的 monitorHandler 被回调,在回调中会获得自己的服务器信息,包括 pid、heapused 等信息响应给 master;
- master 在收集完所有 monitor 的响应后,将获得到的服务器信息数据响应给 AdminClient,也就是会由命令行工具收到,并显示出来。
在 console 这个 module 中,由于没有 monitor 给 master 发 request/notify,所以 console 的 masterHandler 回调可以省略,同样 console 还省略了 start 回调,因为这里没有什么需要在正常的请求响应之前要执行的东西。
需要注意: 在命令行工具中,add 命令现在已经过时了,也就说 console module 中关于处理 add 方法的部分现在已经过时,当需要 add 服务器的时候,推荐使用 pomelo-cli,那是一个更强大的交互式命令行工具,pomelo-cli 使用的 module 定义在 pomelo-admin 中,包括 watchServer 等。读者可以按照前面的分析方式,自行分析 pomelo-cli 以及 pomelo-admin 中定义的 module。在 pomelo 应用中,通过 app.enable('systemMonitor'),将会使得应用默认注册 pomelo-admin 中定义的 module,否则,仅仅有 console 和 watchdog 会被默认注册。还有一个基于 web 的监控工具 pomelo-admin-web,它提供了通过 web 页面来看服务器管理监控信息的方式,它也是一个监控管理的客户端。
权限管理
在客户端连接到 master 上的时候,需要对客户端进行身份验证,验证使用用户名和口令,用户的权限分为三个等级,他们分别对应不同的权限。用户的配置信息在 adminUser.json 中,其中 level 1 的权限可以执行任何操作,其他 level 的权限的控制权限收到限制。关于权限控制以及用户信息的配置,可以参考 pomelo-cli 的相关文档。
小结
本部分详细介绍地介绍了 pomelo 的监控管理框架的工作流程,分析了 pomelo 核心的两个 module Watchdog 和 console 的工作原理。结合前面教程中关于 module 的例子,用户可以很容易地完成自己特殊需要的 module 的定制。