热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TarsGo支持ProtocolBuffer

tarsgo,环境,搭建,proto

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以上。


推荐阅读
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • REST与RPC:选择哪种API架构风格?
    在探讨REST与RPC这两种API架构风格的选择时,本文首先介绍了RPC(远程过程调用)的概念。RPC允许客户端通过网络调用远程服务器上的函数或方法,从而实现分布式系统的功能调用。相比之下,REST(Representational State Transfer)则基于资源的交互模型,通过HTTP协议进行数据传输和操作。本文将详细分析两种架构风格的特点、适用场景及其优缺点,帮助开发者根据具体需求做出合适的选择。 ... [详细]
  • 本文总结了一次针对大厂Java研发岗位的面试经历,探讨了面试中常见的问题及其背后的原因,并分享了一些实用的面试准备资料。 ... [详细]
  • 本文探讨了在一个物理隔离的环境中构建数据交换平台所面临的挑战,包括但不限于数据加密、传输监控及确保文件交换的安全性和可靠性。同时,作者结合自身项目经验,分享了项目规划、实施过程中的关键决策及其背后的思考。 ... [详细]
  • 本文详细记录了 MIT 6.824 课程中 MapReduce 实验的开发过程,包括环境搭建、实验步骤和具体实现方法。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • oracle 对硬件环境要求,Oracle 10G数据库软硬件环境的要求 ... [详细]
  • 本文总结了近年来在实际项目中使用消息中间件的经验和常见问题,旨在为Java初学者和中级开发者提供实用的参考。文章详细介绍了消息中间件在分布式系统中的作用,以及如何通过消息中间件实现高可用性和可扩展性。 ... [详细]
  • 深入解析Dubbo:使用与源码分析
    本文详细介绍了Dubbo的使用方法和源码分析,涵盖其架构设计、核心特性和调用流程。 ... [详细]
  • 近年来,区块链技术备受关注,其中比特币(Bitcoin)功不可没。尽管数字货币的概念早在上个世纪就被提出,但直到比特币的诞生,这一概念才真正落地生根。本文将详细探讨比特币、以太坊和超级账本(Hyperledger)的核心技术和应用场景。 ... [详细]
  • Java EE 平台集成了多种服务、API 和协议,旨在支持基于 Web 的多层应用程序开发。本文将详细介绍 Java EE 中的 13 种关键技术规范,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • 本文通过基准测试(Benchmark)对.NET Core环境下Thrift和HTTP客户端的微服务通信性能进行对比分析。基准测试是一种评估系统或组件性能的方法,通过运行一系列标准化的测试来衡量其表现。 ... [详细]
  • 本文详细介绍了在CentOS 6.5 64位系统上使用阿里云ECS服务器搭建LAMP环境的具体步骤。首先,通过PuTTY工具实现远程连接至服务器。接着,检查当前系统的磁盘空间使用情况,确保有足够的空间进行后续操作,可使用 `df` 命令进行查看。此外,文章还涵盖了安装和配置Apache、MySQL和PHP的相关步骤,以及常见问题的解决方法,帮助用户顺利完成LAMP环境的搭建。 ... [详细]
  • Apache Hadoop HDFS QJournalProtocol 中 getJournalCTime 方法的应用与代码实例分析 ... [详细]
  • 在JavaWeb项目架构中,NFS(网络文件系统)的实现与优化是关键环节。NFS允许不同主机系统通过局域网共享文件和目录,提高资源利用率和数据访问效率。本文详细探讨了NFS在JavaWeb项目中的应用,包括配置、性能优化及常见问题的解决方案,旨在为开发者提供实用的技术参考。 ... [详细]
author-avatar
悶得咪_438
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有