[kimserver] 统计负载信息

2020-12-02

简单统计进程负载信息,信息以 json 格式保存在 zookeeper,方便后台页面管理节点。


1. 负载统计数据结构

数据结构:payload.proto,用 protobuf 来设计数据结构,方便数据读写,并且 protobuf 可以转 json(参考 《protobuf / json 数据转换》)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/* 节点信息。*/
message NodeData {
    string zk_path = 1;    /* zookeeper 节点路径。 */
    string node_type = 2;  /* 节点类型, gate/logic/... */
    string node_host = 3;  /* 内部服务集群通信 host。 */
    uint32 node_port = 4;  /* 内部服务集群通信 port。 */
    string gate_host = 5;  /* 对外通信 host。 */
    uint32 gate_port = 6;  /* 对外通信 port。 */
    uint32 worker_cnt = 7; /* 子进程个数。 */
};

/* 进程负载信息。*/
message Payload {
    uint32 worker_index = 1; /* 进程 id,父进程默认 0。 */
    uint32 conn_cnt = 2;     /* 连接个数. */
    uint32 cmd_cnt = 3;      /* 单位时间内处理命令个数。*/
    uint32 read_cnt = 4;     /* 读数据次数。 */
    uint32 read_bytes = 5;   /* 读数据量。*/
    uint32 write_cnt = 6;    /* 写数据次数。*/
    uint32 write_bytes = 7;  /* 写数据量。*/
    double create_time = 8;  /* 更新负载时间。*/
};

/* 统计负载信息。*/
message PayloadStats {
    NodeData node = 1;            /* 节点信息。*/
    Payload manager = 2;          /* 父进程负载信息。*/
    repeated Payload workers = 3; /* 多个子进程负载信息。*/
};

2. 统计流程

  1. 子进程统计负载信息。
  2. 子进程定时将负载信息发送给父进程。
  3. 父进程统计自己的以及多个子进程上报的负载信息。
  4. 父进程定时将统计信息转化为 json 数据,更新到 zookeeper 对应节点。

负载统计流程


3. zookeeper 目录

3.1. 创建负载节点

  1. 进程向 zookeeper 注册节点。
  2. 节点注册成功后获得节点名称,在 zookeeper 对应目录更新负载信息。

3.2. 系统配置信息

kimserver 配置信息,详细配置解析请参考 《[kimserver] 配置文件 config.json》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
    ...
    "zookeeper": {                       # zookeeper 中心节点管理配置。用于节点发现,节点负载等功能。
        "servers": "127.0.0.1:2181",     # redis 服务连接信息。
        "log_path": "zk.log",            # zookeeper-client-c 日志。
        "nodes": {                       # 节点发现配置。
            "root": "/kimserver/nodes",  # 节点发现根目录,保存了各个节点信息,每个节点启动需要往这个目录注册节点信息。
            "subscribe_node_type": [     # 当前节点关注的其它节点类型数组。用于集群里,节点之间相互通信。填充信息可以根据上面 node_type 配置。
                "gate",                  # 接入节点类型。
                "logic"                  # 逻辑节点类型。
            ]
        },
        "payload": {                     # zookeeper 节点负载信息。节点会定时刷新(1次/s),同步当前节点负载。
            "root": "/kimserver/payload" # 节点发现根目录。
        }
    }
}

3.3. zookeeper 数据

  • 负载节点目录结构。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# sudo zkCli
# ls -R /kimserver
/kimserver
/kimserver/nodes
/kimserver/payload
/kimserver/nodes/gate
/kimserver/nodes/logic
# gate 节点注册的节点。
/kimserver/nodes/gate/kim-gate-gate0000000078
# logic 节点注册的节点。
/kimserver/nodes/logic/kim-logic-logic0000000025
/kimserver/payload/gate
/kimserver/payload/logic
# gate 节点创建的负载目录。
/kimserver/payload/gate/kim-gate-gate0000000078
# logic 节点创建的负载目录。
/kimserver/payload/logic/kim-logic-logic0000000025
  • 负载节点数据。
1
2
# sudo zkCli
get /kimserver/payload/gate/kim-gate-gate0000000078
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    "node": {
        "zk_path": "/kimserver/nodes/gate/kim-gate-gate0000000078",
        "node_type": "gate",
        "node_host": "127.0.0.1",
        "node_port": 3344,
        "gate_host": "127.0.0.1",
        "gate_port": 3355,
        "worker_cnt": 1
    },
    "manager": {
        "worker_index": 0,
        "conn_cnt": 110,
        "cmd_cnt": 9915,
        "read_cnt": 547,
        "read_bytes": 2606151,
        "write_cnt": 102401,
        "write_bytes": 2606101,
        "create_time": 1606921932.438947
    },
    "workers": [{
        "worker_index": 1,
        "conn_cnt": 106,
        "cmd_cnt": 9915,
        "read_cnt": 546,
        "read_bytes": 2606101,
        "write_cnt": 102400,
        "write_bytes": 2606080,
        "create_time": 1606921931.451669
    }]
}

4. 源码实现

详细源码实现,请参考 core/network.cppgithub

1
2
3
4
5
6
7
8
9
10
11
12
/* 时钟定时执行(默认每秒一次)。 */
void Network::on_repeat_timer(void* privdata) {
    if (is_manager()) {
        ...
        /* 主进程上报负载统计信息给 zookeeper。 */
        report_payload_to_zookeeper();
    } else {
        /* 子进程上报统计信息给父进程. */
        report_payload_to_parent();
    }
    ...
}

5. 参考