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 $
  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
posted @ 2015-05-19 10:07  雪飞猫  阅读(2074)  评论(1编辑  收藏  举报