监控系统能帮助我们分析节点的服务存在的问题,例如:服务死循环、服务内存溢出、cpu耗时过长等问题。
skynet对服务的监控做得比较简陋,从设计原则上来说,这样做也是对的,因为框架层能做的,基本就是上报和打日志,上层的业务是变化万千的,不论怎么写,都可能满足不了上层的业务需求。skynet中对服务的监控实现在skynet_monitor.c和skynet_monitor.h中,当服务可能陷入死循环的时候,就打一条日志。
每次消息派发,都会调用skynet_monitor_trigger,一共调两次,第一次参数source和destination是真实的值,也就是不为0。第二次调是在消息派发完成的时候,source和destination都赋0。
如果第一次trigger调用以后,消息派发迟迟不完成,monitor线程第一次检查,会将check_version的值赋为version。然后monitor线程第二次检查,这个时候version和check_version就会相等,而且这时候destination也不为0,就会进入释放目标服务和打印报警的流程。
监控相关
关于服务上下文的一些核心已经在上面基本介绍的差不多了,最后介绍一下 context 的一些小细节或辅助功能,它们会关联在结构体 struct skynet_context 上的一个或多个字段,利用好这些功能,对我们分析查找问题有很大的帮助。
服务日志
这个功能可以把服务处理过的消息都导出到一个文件中,配合 debug console 的 logon 和 logoff 两个命令使用,这个功能可以帮助我们对某个指定的服务进行问题查找
性能指标
这些性能指标包括服务已经处理的消息总数、服务处理消息的 cpu 总耗时、是否出现死循环等,可以配合 debug console 的 stat 命令使用(都是调用了底层的 cmd_stat),下面是所有性能指标的名称和作用:
cpu,表示这个服务处理消息消耗的 cpu 总耗时,毫秒为单位,由 profile 字段控制,默认开启,数值越大表示这个服务越繁忙;
message,表示已经被这个服务处理过的消息总数;
time,这个指标可以计算出某个服务当前正在处理的消息已耗时长,可以用来检测一个服务的某个逻辑耗时是不是过长,一般情况为 0,如果值较大就需要注意了,是不是由业务逻辑有问题,可能死循环或者逻辑计算过大;
endless,若为 1 则表示服务长时间没有进行消息处理,可能出现了死循环,也可能是出现 endless 的前一个逻辑耗时超过 5s,它的值是由监控线程设置;
mqlen,表示服务当前还未处理的消息数量,如果消息堆积过多,会出现 May overload, message queue lenght=xxx 的错误日志,详细机制会在后面的消息处理部分详细讲解;
task,这一个指标较为特殊,它不是由底层提供,它的值需要在 lua 层获取,表示某个服务当前挂起的 coroutine 数量。
分离代码
reference
监控相关 详见:https://domicat.me/_posts/2020-05-10-learn-skynet-service/