Post

ActorModel学习(二)消息协议格式设计及消息传递模式

ActorModel学习(二)消息协议格式设计及消息传递模式

消息协议设计

服务端引擎的消息协议一律使用proto协议规范设计、全部的消息可以被划分为两种类型:系统内部消息和系统外部消息。系统内部消息就是在服务端引擎内部流通的消息,系统外部消息就是客户端向网关发送的消息,网关会转发到内部服务端引擎的某个节点。总的来说,就是消息的产生方不同,系统内部消息产生与系统内部、系统外部消息产生于系统外部。

这样区分的好处:第一个是客户端能够无感的迁移到新的服务端引擎;第二个是在分布式系统中,每个actor收到的消息很可能是字节流(结构化对象),这样可以统一序列化和反序列化模式。举个例子:网关收到的来自客户端的消息,统一使用系统外部消息的格式反序列化;内部节点收到的字节流,统一使用系统内部的消息的格式反序列化。

系统外部消息协议统一接口范式

系统外部接口proto文件通常由使用者自己定义,但是服务器引擎会需要到定义的结构体内的成员。如何统一这些proto协议呢?这里使用适配器模式。假设现在存在服务A、B,B持有消息协议,A会收到由B持有的消息协议序列化的字节流。首先所有的proto文件的消息打包结构是统一的,A可以直接反序列化。问题是序列化后的内容不是统一的。现在消息内存在指令号,请求体字节流。A首先需要知道这个指令号对应什么指令。A向B发布自己的指令号定义的proto文件(权威proto),B生成后,将B持有的proto文件的指令号和A的标准指令号相匹配,存入redis的table中。标准指令号->自定义指令号。

A就可以在消息到来时,解析出指令号,查询对应的指令号,并进行对应的消息处理。

如果消息中存在请求体,但是这个请求体只能在B中解析呢?A可以在权威proto中定义好这个消息需要的返回体,并将字节流发送给B,B解析后打包返回体reply给A。

这样新的服务端引擎就可以在不干扰客户端代码的前提下,进行后端的服务替换。

消息协议注册中心

本质上维护N张Table,每个游戏逻辑服一张。游戏逻辑服启动的时候,会向消息协议注册中心注册自己的自定义消息协议。如何注册呢,就是游戏逻辑服持有权威pb和自定义pb,自己将指令的映射关系建立好后,将表发送到注册中心。系统中需要到映射关系的节点自行向注册中心获取。

表的结构是这样定义的:

1
2
3
4
message GamePbTable {
    int64 game_id = 1;
    map<int, int> cmd_id_map = 2;
}

消息协议注册中心本质上是一个适配器,适配了外部的早期已确定的消息协议。

消息传递模式

由于消息可能会被多次转发,actor context中的sender可能并不是消息的实际发送者,所以需要在消息内定义一个逻辑上的消息发送者。通用的消息格式(只是举例,不同的消息的实际成员不同)如下:

1
2
3
4
5
message SystemReq {
    string sender_physicaladdr
    string sender_logicaladdr
    ...content
}

我不想消息协议设计的过于复杂,导致带来很多不必要的解包封包,带来性能的下降。所以我不会对消息封装一个通用的消息,而是多样化的消息,然后在actor自行路由处理。

This post is licensed under CC BY 4.0 by the author.