转载

gslang——原生golang/RPC描述语言简介

gslang背景知识

gslang是采用go语言编写的RPC描述语言,最初它被用来描述 gscluster 网络服之间的接口调用契约;而gscluster项目本身是我在tap4fun时开发的一个游戏

服务端框架,所以能够看到 gscluster 里面有很多与游戏相关的概念。但是框架本身是为mico-service

而生的,所以你可以将它应用到任何你觉得合适的地方,不必局限于游戏服务器。

gslang是一个完整的RPC描述语言,它与 thrift 定位相同。没有直接采用thrift的原因是:

  1. 在开发gslang的时候,thrift对golang的支持并不完善;
  2. 根据项目需要,需要hack代码生成的过程例如:profile,debug 代码;

gslang前端解析器在github上的位置: 这里

语言特性

gslang支持的语言特性有:true/false,byte/sbyte,int16/uint16,int32/uint32,int64/uint64,float32/float64,table,struct,enum,contract,annotation

基本数据类型

byte/sbyte,int16/uint16,int32/uint32,int64/uint64,float32/float64

自定义数据类型

table/struct被用来定义用户定义数据类型,table与struct的区别在于table可以被用来定义annotation

示例:

// The cluster message type struct Message {  ID       byte;    //message Type  Content  []byte;   //content data }

进一步示例请参考: 这里

注意:gslang所有数据类型与网络传输格式无关,它只关心接口语言的定义

枚举类型

gslang支持枚举类型,并且可以指定枚举底层数据类型,可选择的数据类型有:byte/sbyte,int16/uint16,int32/uint32

enum Status(uint16){  Closed(0),  Disconnected(1),  Connecting(2),  InConnected(3),  OutConnected(4),  Online(5),  Offline(6),  Unreachable(7) }

服务契约、方法

服务通过contract关键字定义:

contract SampleActor {  SayHello(string) -> (bool); }
  1. SampleActor :服务名
  2. SayHello: 方法名,该方法有一个string类型输入参数和一个bool类型返回值

多参数:gslang方法支持多输入参数、多返回参数

服务接口集成:服务接口支持继承其它服务器接口,这个和java/C#等语言类似

类型注释(annotation/attribute)

gslang通过类型注释增强了DSL的表达能力,这点与C#/java类似。这个应该是gslang的杀手级特性,它可以被用来指导后端代码生成器生成个性化代码,而不用修改gslang前端编译器部分。在tap4fun的一个内部版本里,通过自定义annotation来决定是否对某个服务器方法生成profile代码。

后端代码生成

如前所述,gslang并不关心底层的序列化方式,也就更不关心底层的网络传输方式。这部分协议由gslang的后端代码生成器决定,一个已知的代码生成后端是 gs2go —golang代码生成后端,并且生成代码遵循的协议由 gscluster 定义。

需要指出的是: gscluster 的RPC调用底层数据包本身也是由gslang来描述的,具体情况可以参看 这个 文件。

构建一个环境

  1. 安装 gsmake ,gsmake这个工具的介绍可以看这里
  2. git clone https://github.com/gsdocker/gscluster
  3. cd ${gscluster directory}
  4. gsmake gotest -bench . ./test2

通过上面几步,就构建了一个基本的gsdocker/rpc测试环境。你可以观察生成的*.gs.go文件来了解代码生成的细节;

gscluster RPC协议细节

struct/table序列化

直接将字段数据按定义顺序递归序列化写入二进制流,没有tag/元数据信息;它的序列化/反序列化完全依赖于gslang脚本;

基本数据类型序列化

  1. interger类型 : 按照小端序写入
  2. string类型: [两字节,后续内容长度] + [UTF-8字符内容]
  3. 浮点类型:按 IEEE-754 内存表示序列化

RPC数据包

客户端/mico-service节点之间的rpc调用都被封装成一个一个RPC协议包传输,它的格式定义由gslang描述为下面形式:

// The gscluster rpc package code types enum Code {  WhoAmI(0),  Accept(1),  Reject(2),  DHExchange(3),  Call(4),  Return(5),  CER(6),  ErrReturn(7) }  // The gscluster prc package type define struct Message {  Code     Code;    //message Type  Content  []byte;   //content data }  struct DHExchange {  ID      string;  Content string; }  struct CER {  Add   bool;  Type  string;   // service type name  Name  string;   // service name  ID    uint32;   // srevice id }  struct Param{  Content []byte; }  struct Return {  ID      uint16;  Service uint32;  Params  []Param; }  struct ErrReturn {  ID   uint16;  Service uint32;  UUID []byte;  Code int32; }  struct Call {  ID      uint16;  Method  uint16;  Service uint32;  Params  []Param; } 

再次强调:gscluster的rpc协议封包本身是由gslang来直接定义的

结构体Call/Return分别用来实现RPC调用请求/应答:

  1. Call#ID : RPC包序列号,用来匹配应答包;
  2. Call#Service : Contract协议号
  3. Call#Method : Method协议号
  4. Call#Params : 参数列表

Service/Contract协议号与名字的映射关系由底层框架确定:

  1. 服务器之间的RPC调用,由调用两端通过协商握手协议确定;
  2. 网关与客户端之间的RPC调用,由于 gscluster 只支持GS/GW/GC三类服务契约——分别对应服务器/网关/客户端RPC接口——服务协议号被简单的手动分配。

gscluster

gscluster是一个golang实现的mico-service框架:

  1. 服务端采用基于角色的并发模型,每个客户端在服务器端都有一个actor角色对象与之一一对应。
  2. 服务节点/客户端之间,通过RPC协议进行通信;
  3. 内建网关服务,支持基于SLB之类的技术进行接入层的负载均衡;
  4. 总体上gscluster类似于云风设计的 skynet ,只不过gscluster在实现服务的时候更方便一些——内建goroutine,而不是开很多lua vm
正文到此结束
Loading...