Osheep

时光不回头,当下最重要。

skynet源码分析(4)--monitor

作者:shihuaping0918@163.com,转载请注明作者

skynet对服务的监控做得比较简陋,从设计原则上来说,这样做也是对的,因为框架层能做的,基本就是上报和打日志,上层的业务是变化万千的,不论怎么写,都可能满足不了上层的业务需求。skynet中对服务的监控实现在skynet_monitor.c和skynet_monitor.h中,当服务可能陷入死循环的时候,就打一条日志。具体日志内容详见代码。


#include "skynet_monitor.h"
#include "skynet_server.h"
#include "skynet.h"
#include "atomic.h"

#include <stdlib.h>
#include <string.h>

struct skynet_monitor {
    int version; //版本号
    int check_version; //上个版本号
    uint32_t source; //源
    uint32_t destination; //目标
};
//结构体初始化
struct skynet_monitor * 
skynet_monitor_new() {
    struct skynet_monitor * ret = skynet_malloc(sizeof(*ret));
    memset(ret, 0, sizeof(*ret));
    return ret;
}
//结构体回收
void 
skynet_monitor_delete(struct skynet_monitor *sm) {
    skynet_free(sm);
}
//触发监控
void 
skynet_monitor_trigger(struct skynet_monitor *sm, uint32_t source, uint32_t destination) {
    sm->source = source; //源
    sm->destination = destination; //目标
    ATOM_INC(&sm->version); //版本号递增
}
//检查监控,有一个线程专门做这个事情
void 
skynet_monitor_check(struct skynet_monitor *sm) {
    if (sm->version == sm->check_version) {//版本号相同
        if (sm->destination) { //destination不为0
//释放目标服务
            skynet_context_endless(sm->destination);
//打日志,警告可能有死循环
            skynet_error(NULL, "A message from [ :%08x ] to [ :%08x ] maybe in an endless loop (version = %d)", sm->source , sm->destination, sm->version);
        }
    } else { //版本号不同
        sm->check_version = sm->version;
    }
}

每次消息派发,都会调用skynet_monitor_trigger,一共调两次,第一次参数source和destination是真实的值,也就是不为0。第二次调是在消息派发完成的时候,source和destination都赋0。

如果第一次trigger调用以后,消息派发迟迟不完成,monitor线程第一次检查,会将check_version的值赋为version。然后monitor线程第二次检查,这个时候version和check_version就会相等,而且这时候destination也不为0,就会进入释放目标服务和打印报警的流程。

这一篇只能简单的就事论事, 要真正讲得很清晰,整个脉络贯通需要讲完消息派发才行。

点赞