千家信息网

TarsGo新版本发布,支持protobuf,zipkin和自定义插件

发表于:2024-11-14 作者:千家信息网编辑
千家信息网最后更新 2024年11月14日,本文作者:陈明杰(sandyskies)Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架,目前支持C++,Java,PHP,Nodejs,Golang语言。该框架为用户提供了涉及到
千家信息网最后更新 2024年11月14日TarsGo新版本发布,支持protobuf,zipkin和自定义插件

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

TarsGo 新版本发布

在上次开源之后,有些用户反馈了一些需求,基于用户反馈的需求,我们进行了实现,并发布了1.1.0版本。 本次发布新增了:支持pb、支持zipkin分布式追踪、支持filter(自定义插件编写)、支持context 等,除此之外还做了一系列优化和bugfix。

新功能:PB支持

Protocol Buffers (简称 PB )是 Google 的一种数据交换的格式,它独立于语言,独立于平台,最早公布于 2008年7月。随着微服务架构的发展及自身的优异表现,ProtoBuf 可用于诸如网络传输、配置文件、数据存储等诸多领域,目前在互联网上有着大量应用。
如果对于现有已使用grpc,使用proto文件,想转换成tars协议的用户而言,需要将上面的proto文件翻译成Tars文件。这种翻译会比较繁琐,而且容易出错。 为此我们决定编写插件支持proto文件直接生成tars的rpc逻辑。protoc-gen-go的代码逻辑里面是预留了插件编写的规范的,参照grpc,主要有 grpc/grpc.go 和一个导入插件的link_grpc.go 。 这里我们编写 tarsrpc/tarsrpc.go 和 link_tarsrpc.go
使用方面:

  • 将这两个文件放到protoc-gen-go 下面,go install重新生成protoc-gen-go 二进制

  • 定义proto 文件

  • 使用重新编译安装的protoc-gen-go生成序列化和rpc相关接口代码
protoc --go_out=plugins=tarsrpc:. helloworld.proto
  • 编写tars 客户端和服务端代码,参数使用pb生成的结构体,其余代码逻辑和正常的tars服务一致。

  • 详细原理和使用文档,阅读 腾讯云社区文章

新功能: filter机制, 支持zipkin分布式追踪

为了支持用户编写插件,我们支持了filter机制,分为服务端的过滤器和客户端过滤器,用户可以基于这个机制,实现自己的TarsGo插件。

//服务端过滤器, 传入dispatch,和f, 用于调用用户代码, req, 和resp为传入的用户请求和服务端相应包体type ServerFilter func(ctx context.Context, d Dispatch, f interface{}, req *requestf.RequestPacket, resp *requestf.ResponsePacket, withContext bool) (err error)//客户端过滤器, 传入msg(包含obj信息,adapter信息,req和resp包体), 还有用户设定的调用超时type ClientFilter func(ctx context.Context, msg *Message, invoke Invoke, timeout time.Duration) (err error)//注册服务端过滤器//func RegisterServerFilter(f ServerFilter)//注册客户端过滤器//func RegisterClientFilter(f ClientFilter)

有了过滤器,我们就能对服务端和客户端的请求做一些过滤,比如使用 hook用于分布式追踪的opentracing 的span。
我们来看下客户端filter的例子:

//生成客户端tars filter,通过注册这个filter来实现span的注入func ZipkinClientFilter() tars.ClientFilter {    return func(ctx context.Context, msg *tars.Message, invoke tars.Invoke, timeout time.Duration) (err error) {        var pCtx opentracing.SpanContext        req := msg.Req        //先从客户端调用的context 里面看下有没有传递来调用链的信息,        //如果有,则以这个做为父span,如果没有,则起一个新的span,span名字是RPC请求的函数名        if parent := opentracing.SpanFromContext(ctx); parent != nil {            pCtx = parent.Context()        }        cSpan := opentracing.GlobalTracer().StartSpan(            req.SFuncName,            opentracing.ChildOf(pCtx),            ext.SpanKindRPCClient,        )        defer cSpan.Finish()        cfg := tars.GetServerConfig()        //设置span的信息,比如我们调用的客户端的ip地址,请求的接口,方法,协议,客户端版本等信息        cSpan.SetTag("client.ipv4", cfg.LocalIP)        cSpan.SetTag("tars.interface", req.SServantName)        cSpan.SetTag("tars.method", req.SFuncName)        cSpan.SetTag("tars.protocol", "tars")        cSpan.SetTag("tars.client.version", tars.TarsVersion)        //将span注入到 请求包体的  Status里面,status 是一个map[strint]string 的结构体        if req.Status != nil {            err = opentracing.GlobalTracer().Inject(cSpan.Context(), opentracing.TextMap, opentracing.TextMapCarrier(req.Status))            if err != nil {                logger.Error("inject span to status error:", err)            }        } else {            s := make(map[string]string)            err = opentracing.GlobalTracer().Inject(cSpan.Context(), opentracing.TextMap, opentracing.TextMapCarrier(s))            if err != nil {                logger.Error("inject span to status error:", err)            } else {                req.Status = s            }        }        //没什么其他需要修改的,就进行客户端调用        err = invoke(ctx, msg, timeout)        if err != nil {            //调用错误,则记录span的错误信息            ext.Error.Set(cSpan, true)            cSpan.LogFields(oplog.String("event", "error"), oplog.String("message", err.Error()))        }        return err    }

服务端也会注册一个filter,主要功能就是从request包体的status 提取调用链的上下文,以这个作为父span,进行调用信息的记录。
整体的一个效果:

详细代码参见 TarsGo/tars/plugin/zipkintracing
完整的zipkin tracing的客户端和服务端例子,详见 TarsGo/examples下面的ZipkinTraceClient和ZipkinTraceServer

新功能: 支持context

TarsGo 之前在生成的客户端代码,或者用户传入的实现代码里面,都没有使用context。 这使得我们想传递一些框架的信息,比如客户端ip,端口等,或者用户传递一些调用链的信息给框架,都很难于实现。 通过接口的一次重构,支持了context,这些上下文的信息,将都通过context来实现。 这次重构为了兼容老的用户行为,采用了完全兼容的设计。

服务端使用context

type ContextTestImp struct {}//只需在接口上添加 ctx context.Context参数func (imp *ContextTestImp) Add(ctx context.Context, a int32, b int32, c *int32) (int32, error) {    //我们可以通过context 获取框架传递的信息,比如下面的获取ip, 甚至返回一些信息给框架,详见tars/util/current下面的接口    ip, ok := current.GetClientIPFromContext(ctx)    if !ok {        logger.Error("Error getting ip from context")    }      return 0, nil}//以前使用AddServant ,现在只需改成AddServantWithContextapp.AddServantWithContext(imp, cfg.App+"."+cfg.Server+".ContextTestObj")

客户端使用context

    ctx := context.Background()    c := make(map[string]string)    c["a"] = "b" //以前使用app.Add 进行客户端调用,这里只要变成app.AddWithContext ,就可以传递context给框架,如果要设置给tars请求的context//可以多传入参数,比如c,参数c是可选的,格式是 ...[string]string    ret, err := app.AddWithContext(ctx, i, i*2, &out, c)

服务端和客户端的完整例子,详见 TarGo/examples

其他优化和修复

  • 将request package 的Sbuffer字段由vector 改成vector,解决和其他语言通信问题
  • 修复stat监控上报问题
  • 日志级别从远端更新
  • 修复路由刷新协程极端情况下死锁问题
  • 优化协程池方案,并添加协程池方案
  • 修复go协程启动顺序导致panic问题
  • golint大部分代码
客户 服务 客户端 支持 信息 用户 框架 代码 文件 过滤器 插件 生成 接口 分布式 参数 端的 语言 逻辑 问题 面的 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络摄像头不连接网络安全吗 手机软件开发购买 上海的网络安全有哪些大学 通州区网络技术咨询成本价 lol各个服务器都在哪个位置 北京涌金冠泰网络技术怎么样 杭州没事找事网络技术 邮件的数据库扩展名 服务器检测售后维修 mdf文件恢复新数据库 北京群控云控软件开发商 视易峰云服务器30授权破解 派出所开展网络安全宣传信息 软件开发前要做什么工作 云软件开发项目 企业云服务器创建时间 计算机网络技术可以报考一建 多业务环境共用数据库风险 共享网络安全网络文明手抄报 edge应用程序中的服务器 一般用于软件开发的语言 网信办领导致辞 江苏 网络安全 手抄报(网络安全) 东莞蛙人网络技术有限公司 防火墙和网络安全检测装置 服务器sql数据库怎么下载 公安局长访谈网络安全 邮箱 服务器 端口 如何修改网络安全类型 网络安全服务器品牌深信服
0