TarsGo支持Protocol Buffer

Wesley13
• 阅读 742

Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架TAF(Total Application Framework),目前支持C++,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用微服务的方式构建自己的稳定可靠的分布式应用,并实现完整有效的服务治理。目前该框架在腾讯内部,各大核心业务都在使用,颇受欢迎,基于该框架部署运行的服务节点规模达到上万个。

Tars 于2017年4月开源,并于2018年6月加入Linux 基金会,项目地址:https://github.com/TarsCloud

TarsGo 是Tars 的Go语言实现版本, 于2018年9月开源, 项目地址:https://github.com/TarsCloud/TarsGo

点击阅读原文即可访问

Tars协议是一种类c++标识符的语言,用于生成具体的服务接口文件,Tars文件是Tars框架中客户端和服务端的通信接口,通过Tars的映射实现远程对象调用。Tars 协议是和语言无关,基于IDL接口描述语言的二进制编码协议。

详见TarsProtocol

https://github.com/TarsCloud/TarsProtocol/blob/master/docs/tars\_protocol.md

Protocol Buffers (简称 PB )是 Google 的一种数据交换的格式,它独立于语言,独立于平台,最早公布于 2008年7月。随着微服务架构的发展及自身的优异表现,ProtoBuf 可用于诸如网络传输、配置文件、数据存储等诸多领域,目前在互联网上有着大量应用。

PB协议是单独的协议,如果要支持RPC,可以定义service字段,并且基于protoc-gen-go 的grpc 插件生成相应的grpc编码。

以下面的 proto 文件为例

syntax = "proto3";package helloworld;// The greeting service definition.service Greeter {  // Sends a greeting  rpc SayHello (HelloRequest) returns (HelloReply) {}}// The request message containing the user's name.message HelloRequest {  string name = 1;}// The response message containing the greetingsmessage HelloReply {  string message = 1;}

使用protoc生成相应的接口代码,以Go语言为例:

protoc --go_out=plugins=grpc:. helloworld.proto

如果对于现有已使用grpc,使用proto,想转换成tars协议的用户而言,需要将上面的proto文件翻译成Tars文件。对于Tars而言,Tars是编写tars文件,然后用相应的工具tars2xxx, 比如tars2go生成相应的接口代码。上面的proto文件翻译成tars文件是:

module helloworld{    struct HelloRequest {        1 require string name ;    };    struct HelloReply {        1 require string message ;    };    interface Greeter    {        int SayHello(HelloRequest req, out HelloReply resp);    };}

然后调用tars2go生成 相应的tarsgo接口:

tars2go --outdir ./ helloworld.tars

这种翻译会比较繁琐,而且容易出错。为此我们决定编写插件支持proto直接生成tars的rpc逻辑。

有两种方案,一种是写protoc插件,直接读取protoc解析proto文件的二进制流,对service相应的字段进行解析,以便生成相应的rpc逻辑,其他交由protoc-gen-go处理

另外一种是直接编写protoc-gen-go的插件,类似gRPC插件,

这里决定采用方案2 。

protoc-gen-go 并没有插件编写的相关说明,但protoc-gen-go的代码逻辑里面是预留了插件编写的规范的,参照grpc,主要有 grpc/grpc.go 和一个导致插件包的link_grpc.go 。这里我们编写 tarsrpc/tarsrpc.go 和 link_tarsrpc.go

代码逻辑基本上就是继承 generator.Generator,注册插件, 获取相应的service,method,和method的input和output,再调用P方法将要生成的代码输出即可。

func init() {    generator.RegisterPlugin(new(tarsrpc))}// tarsrpc is an implementation of the Go protocol buffer compiler's// plugin architecture. It generates bindings for tars rpc support.type tarsrpc struct {    gen *generator.Generator}func (t *tarsrpc) generateService(file *generator.FileDescriptor, service *pb.ServiceDescriptorProto, index int) {    originServiceName := service.GetName()    serviceName := upperFirstLatter(originServiceName)    t.P("// This following code was generated by tarsrpc")    t.P(fmt.Sprintf("// Gernerated from %s", file.GetName()))    t.P(fmt.Sprintf(`type  %s struct {        s model.Servant    }    `, serviceName))    t.P()... ...}

这里主要是生成 service 转成相应的interface,然后interface里面有定义的rpc method, 用户可以实现自己真正业务逻辑的method,其余的都是tars相应的发包收包逻辑。Tars的请求包体:

type RequestPacket struct {    IVersion     int16             `json:"iVersion"`    CPacketType  int8              `json:"cPacketType"`    IMessageType int32             `json:"iMessageType"`    IRequestId   int32             `json:"iRequestId"`    SServantName string            `json:"sServantName"`    SFuncName    string            `json:"sFuncName"`    SBuffer      []uint8           `json:"sBuffer"`    ITimeout     int32             `json:"iTimeout"`    Context      map[string]string `json:"context"`    Status       map[string]string `json:"status"`}

我们只需要将rpc method的名字,放入RequestPacket 的SFuncName ,然后将请求参数调用proto的Marshal序列化后放到 SBuffer。

而对于回包,Tars的回包结构体:

type ResponsePacket struct {    IVersion     int16             `json:"iVersion"`    CPacketType  int8              `json:"cPacketType"`    IRequestId   int32             `json:"iRequestId"`    IMessageType int32             `json:"iMessageType"`    IRet         int32             `json:"iRet"`    SBuffer      []uint8           `json:"sBuffer"`    Status       map[string]string `json:"status"`    SResultDesc  string            `json:"sResultDesc"`    Context      map[string]string `json:"context"`}

同样,我们只需要将返回的结果,调用Marshal 将请求放入 SBuffer ,其他逻辑和tars保持一致。

编写完插件,就可以通过和grpc生成代码相同的方式,将proto 文件转化成tars的接口文件:

protoc --go_out=plugins=tarsrpc:. helloworld.proto

下面是简单的服务端例子

package mainimport ( "github.com/TarsCloud/TarsGo/tars" "helloworld" //上面工具生成的package)type GreeterImp struct {}func (imp *GreeterImp) SayHello(input helloworld.HelloRequest)(output helloworld.HelloReply, err error) {    output.Message = "hello" +  input.GetName()    return output, nil}func main() { //Init servant    imp := new(GreeterImp)                                    //New Imp    app := new(helloworld.Greeter)                            //New init the A JCE    cfg := tars.GetServerConfig()                              //Get Config File Object    app.AddServant(imp, cfg.App+"."+cfg.Server+".GreeterTestObj") //Register Servant    tars.Run()}

简单的客户端调用例子

package mainimport ( "fmt" "github.com/TarsCloud/TarsGo/tars" "helloworld")func main() {    comm := tars.NewCommunicator()    obj := fmt.Sprintf("StressTest.HelloPbServer.GreeterTestObj@tcp -h 127.0.0.1 -p 10014 -t 60000")    app := new(helloworld.Greeter)    comm.StringToProxy(obj, app)    input := helloworld.HelloRequest{Name: "sandyskies"}    output, err := app.SayHello(input)    if err != nil {        fmt.Println("err: ", err)    }    fmt.Println("result is:", output.Message)}

protoc-gen-go 的插件放在:TarsGo/tars/tools/pb2tarsgo , 需要要求Protocol Buffer 3.6.0以上。

jessemjchen 2018-10-10

TarsGo支持Protocol Buffer

本文分享自微信公众号 - TARS星球(TarsCloud)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
TarsPHP 新版本发布,支持 Protobuf 协议
!(https://static.oschina.net/uploads/space/2020/0702/162528_DudP_4021301.jpg)作者丨张勇编辑丨TARS小助手TARS是腾讯从2008年到今天一直在使用的微服务开发框架,2018年成为Linux基金会开源项目目前支持PHP、C、Java、Nodejs与Go语
Easter79 Easter79
3年前
TarsGo支持Protocol Buffer
Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架TAF(TotalApplicationFramework),目前支持C,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。它集可扩展协议编解码、高性能RPC通信框架、名字路
Stella981 Stella981
3年前
Spring Boot日志集成
!(https://oscimg.oschina.net/oscnet/1bde8e8d00e848be8b84e9d1d44c9e5c.jpg)SpringBoot日志框架SpringBoot支持JavaUtilLogging,Log4j2,Lockback作为日志框架,如果你使用star
Wesley13 Wesley13
3年前
TarsGo新版本发布,支持protobuf,zipkin和自定义插件
Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架,目前支持C,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用
Easter79 Easter79
3年前
TarsGo新版本发布,支持protobuf,zipkin和自定义插件
Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架,目前支持C,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用
Java服务总在半夜挂,背后的真相竟然是... | 京东云技术团队
最近有用户反馈测试环境Java服务总在凌晨00:00左右挂掉,用户反馈Java服务没有定时任务,也没有流量突增的情况,Jvm配置也合理,莫名其妙就挂了