文档章节

TarsGo支持Protocol Buffer

TARS小助手
 TARS小助手
发布于 2018/11/12 11:33
字数 1482
阅读 347
收藏 3

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

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 greetings
message 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 main

import (
    "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 main

import (
    "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以上。

© 著作权归作者所有

上一篇: 初学者也说TARS
下一篇: 初学者也说TARS
TARS小助手
粉丝 9
博文 2
码字总数 4559
作品 0
深圳
私信 提问
TarsGo 新版本发布,支持 Protobuf、Zipkin 和自定义插件

Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架,目前支持C++、Java、PHP、Nodejs、Golang语言。该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产...

oschina
2018/11/13
1K
3
TarsPHP 新版本发布,支持 Protobuf 协议

Tars是腾讯从2008年到今天一直在使用的微服务开发框架,2018年成为Linux基金会开源项目,目前支持C++、Java、PHP、NodeJS与Go语言。该框架为用户提供了涉及到开发、运维,以及测试的一整套解...

TARS小助手
08/07
4.6K
24
多语言的序列化库--Adata

AData 是一个多语言的序列化库,和 protocol buffer 类似。 目前支持C++/Lua(5.1,5.2,5.3,jit)/C#,非常适合游戏的通讯协议和数据存储 Adata的优势,生成的代码量少,和protocol buffer...

叶秀兰
2015/03/12
703
1
Adata 1.1 发布,多语言的序列化库

Adata 1.1发布,调整lua的模块实现,大幅提升性能 http://git.oschina.net/lordoffox/adata AData是一个多语言的序列化库,和protocol buffer类似。 目前支持C++/Lua(5.1,5.2,5.3,jit)/...

lordoffox
2015/03/12
2.8K
5
Protocol Buffers 开发者指南

欢迎来到 protocol buffers 的开发者指南。protocol buffers 是一个语言中立,平台中立针对通讯协议,数据存储和其他领域中对结构化数据进行序列化的扩展方法。 本文档主要针对的是 Java,C...

honeymoose
07/25
49
0

没有更多内容

加载失败,请刷新页面

加载更多

为什么要在网站中应用CDN加速?

1. 网页加载速度更快 在网站中使用CDN技术最直接的一个好处就是它可以加快网页的加载速度。首先,CDN加速的内容分发是基于服务器缓存的,由于CDN中缓存了不少数据,它能够给用户提供更快的页...

云漫网络Ruan
41分钟前
7
0
亚玛芬体育(Amer Sports)和信必优正式启动合作开发Movesense创新

亚玛芬体育和信必优正式启动合作开发Movesense创新,作为亚玛芬体育的完美技术搭档,信必优利用Movesense传感器技术为第三方开发移动应用和服务。 Movesense基于传感器技术和开放的API,测量...

symbiochina88
52分钟前
4
0
创龙TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA核心板规格书

SOM-TL437xF是一款广州创龙基于TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA芯片设计的核心板,采用沉金无铅工艺的10层板设计,适用于高速数据采集和处理系统、汽车导航、工业自动化等领...

Tronlong创龙
52分钟前
4
0
好程序员Java学习路线分享MyBatis之线程优化

  好程序员Java学习路线分享MyBatis之线程优化,我们的项目存在大量用户同时访问的情况,那么就会出现大量线程并发访问数据库,这样会带来线程同步问题,本章我们将讨论MyBatis的线程同步问...

好程序员官方
58分钟前
6
0
IDEA 自定义方法注解模板

IDEA 自定义方法注解模板 1、使用效果 /*** 计算交易费用* @Author wangjiafang* @Date 2019/9/11* @param feeComputeVo* @return*/@PostMapping("/v1/fee_compute")public ApiResp......

小白的成长
58分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部