• 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
  • 相关阅读:
    react-native window下创建Hello(解决创建一路的坑)
    vue2.0 监听滚动 锚点定位
    vue-awesome-swiper 轮播图使用
    vue和react区别
    vuex 管理状态
    vue 解决axios 跨域问题
    判断一个对象是否为空? js
    微信小程序中的自定义组件(components)
    深入理解ES6箭头函数中的this
    vue中组件的data为什么是一个函数
  • 原文地址:https://www.cnblogs.com/yayanyang/p/4513789.html
Copyright © 2020-2023  润新知