解读|TARS开源项目发布Go语言版本

文章转自开源中国node

导语:近日,Tars 开源项目在上海发布并开源了 Go 语言版本,其性能与 C++ 版本至关,比 gRPC 的性能高 5 倍。 ——编者git

Tars 是腾讯开源的一款微服务框架,它于去年 4 月份开源,并于今年 6 月捐赠给了 Linux 基金会。Tars 为用户提供了涉及到开发和运维的一整套解决方案,帮助一个产品或者服务快速开发、发布、部署、上线和维护。它集可扩展协议编解码、高性能 RPC 通讯框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,经过它能够快速用微服务的方式构建稳定可靠的分布式应用,并实现完整有效的服务治理。通过一年多的发展,目前 Tars 已经被许多企业使用,如阅文集团、虎牙直播、科大讯飞,优品财富、龙图游戏和金太阳教育等。github


据悉,9 月 15 日,腾讯宣布正式开源 Tars 的 Golang 版本 Tars-Go。编者从 Tars 的开源公告中了解到 Tars 与当前市面上其它微服务框架的差别、技术架构、性能数据与相关技术细节,本文将详细介绍 Tars 这次释出的 Golang 版本。算法


项目地址:编程

https://github.com/TarsCloud/TarsGo后端


支持服务治理、多语言,只 Tars 一家性能优化


微服务架构这两年变得格外火热,它已经成为当前最主流的架构模式。提起微服务框架,咱们能够天然地举出 Dubbo、gRPC 与 Spring Cloud 等众多的知名项目,依据是否支持服务治理是否支持多语言两个维度可将这些微服务框架分为如下四类:服务器


  • 只有服务调用没有服务治理类的框架。典型的表明有 gRPC、Thrift 等,他们很好地解决了服务间通讯的问题,大部分也支持多语言,但使用这类框架时须要本身去解决服务治理问题。微信

  • 带服务治理但支持单一语言的框架。典型的表明有 Spring Cloud 和 Dubbo,它们都是用 Java 实现的框架,用户整合多个开源项目一块儿并能知足服务治理等的需求。网络

  • Service Mesh它支持服务治理,并经过 Sidecar 模式解决框架对多语言支持,业务须要再封装一套通信组件去解决通信问题,以及异步调用等问题,同时会增长架构和维护的复杂度。

  • 带服务治理并支持多语言的框架。目前业界比较少,除了 Tars 目前尚未发现其它具备表明性的框架。


从上面的分析大概能够发现,Tars 是支持服务治理的同时又提供多语言支持的微服务框架,这是 Tars 的独特之处,也是其优点。


Tars 能够运行在物理机、虚拟机和容器,其协议主打的是基于 IDL 实现的 Tars 协议,它是一种二进制解析协议,与 pb 相似,同时 Tars 还扩展支持其它协议,乃至用户自定义。


调用方式主要以 RPC 为主,支持同步、异步和单向调用几种方式。在服务治理方面除了支持服务注册、发现等业界常说的能力以外,还提供面对海量访问的一些其它治理能力,如 Set 模型、自动区域感知、过载保护等,语言上除了这次新支持的 Golang,目前已经支持了 C++、Java、NodeJS 与 PHP,同时总体框架能够和 DevOps 很好地协同工做。


Tars 总体分为三个部分:Registry、服务节点和基础服务集群。

Registry

Registry 是微服务集群的管理和控制节点,提供服务注册和发现等功能。


服务节点

服务节点是 Tars 运行的原子单元,能够是一个容器也能够是一个虚机或物理机,一个业务服务经过部署多个服务节点来解决容量和容错问题。服务节点上包括一个 node 管理服务和一个或多个业务服务,node 服务对本节点的服务进行统一管理,提供启停、监控服务节点等功能,同时接收业务服务节点上报过来的心跳,上报给 Registry 做为服务发现的数据来源。


基础服务集群

基础服务集群是为解决微服务治理而设计的一系列服务,服务节点数量不定,为了自身的容错容灾,通常也要求在多个服务器上进行部署,具体的节点数量与业务规模有关,好比,若是业务规模大须要打较多的日志,就须要部署更多的日志服务节点。基础服务主要包括监控统计、配置中心、日志聚合、认证鉴权和分布式调用链等。Tars 具备很是完善的服务治理能力。


Tars 经过 Registry、服务节点和基础服务集群协同工做,透明完成服务发现/注册、负载均衡、鉴权、分布式跟踪等服务治理相关工做。如框架经过 Registry 来注册 xxxsvr,Client 经过访问 Registry 获取到被调服务的地址信息列表,Client 再根据须要选择合适的负载均衡方式来调用服务。负载均衡支持轮询、hash、权重等多种方式。


为了更及时地屏蔽故障节点,Client 根据调用被调服务的异常状况判断是否有故障来更快地进行故障屏蔽。具体策略是,当 Client 调用某个服务器出现调用连续超时超过设置阈值,或者调用的超时比率超过必定百分比阈值,Client 就会对此服务器节点进行屏蔽,让流量分发到正常的节点上去。对屏蔽的服务器节点,每隔必定时间进行重连,若是正常,则进行正常的流量分发。


随着业务增加,服务的部署不免会跨机房或者地域,常规的负载均衡方式面对跨地区或者跨机房部署的服务会由于网络缘由形成延时增大,为了加快服务间的访问速度,减小因建设跨地区、跨机房调用带来的网络资源消耗,减小网络故障带来的影响,Tars 提供自动区域感知的服务治理功能。


经过 Registry 和开发框架配合实现自动区域感知,这样的优点有:

  • 运维简单

  • 下降延时减小带宽消耗

  • 更强的容灾能力


此外 Tars 还提供 Set 模型


Set 模型是根据业务功能特征对部署进行规范化和标准化,以 Set 为单元进行部署。Set 模型的优势有:

  • 有效防止故障扩散

  • 方便进行容量管理


对于流量控制,服务发布上线主要面对的问题是“如何作对业务无损的服务变动”与“如何作灰度验证”,在 Tars 中,可经过 Registry 和开发框架配合实现按需进行流量控制,达到无损发布和灰度流量的目的。

语言支持方面,除了此前已经支持的 PHP、C++、NodeJS 与 Java,这次还加入了 Golang 支持。


此外,Tars 还提供一个 OSS 平台,可以使运营可视化、Web 化。

它主要包含如下特色:

  • 业务管理:包括已部署的服务,以及服务管理、发布管理、服务配置、服务监控、特性监控等

  • 运维管理:包括服务部署、扩容、模版管理等

  • 提供 Open API ,可定制本身的 OSS 系统


Tars-GoTars Go


多语言支持是 Tars 的一大优点,在此以前 Tars 已经推出了 C++、Java、PHP、NodeJS 版本。Go 语言的协程并发机制使它很是适用于大规模高并发后端服务器程序开发,同时随着容器化技术的飞速发展,诸如 Docker、Kubernetes 与 Etcd 等项目兴起,使得 Go 语言愈来愈流行,并成为云原生的首选语言。Tars 的 Go 语言版本也所以应运而生,这次 Tars-Go 的推出,在大环境总体逐渐走向云原生的当下,意义非凡。


这次新推出的 Go 版本 Tars-Go 总体架构主要能够分为三个部分,以下图所示:

  • 左边是 tars2go 工具,tars2go 基于巴科斯范式(BNF),这是一种描述程序语言结构的形式化方法,用来对 Tars 文件进行语法和词法分析,生成相应的代码,供客户端和服务端使用。同时它提供 Tars 协议二进制流的编解码功能,将二进制包转成相应的 Go 数据结构。

  • 右边部分是 package tars,它包含了 Client Server 两部分的功能:

    • Client 由 Servantproxy、Communicator、ObjProxy、adapterproxy 等逻辑结构组成,这些逻辑结构用来管理 servant,obj 对应到的服务端节点的 ip 端口,和 C++ 的逻辑保持一致。底层使用 net.Conn 来创建具体的链接,并用 SendQueue chan 来控制并发数量。Client 还包含一些 Goroutine,用来作特性监控和 stat 监控上报。

    • Server 使用 package net 的 listener 来管理 TCP 和 UDP 链接,使用多个 Goroutine 进行 accept,并将 accept 以后的 net.Conn 通过 SendQueue chan 交给后端的 Handler 进行处理。Handler 由一堆 woker Goroutine 组成,每一个 Goroutine 基于 net.Conn 进行收发包、Tars 协议解码,并通过 dispatcher(由 tars2go 生成) 来调用用户的代码实现,而后将结果编码成二进制流返回给 Client。Server 也包含一些 Goroutine 实现远程日志异步上报等功能,防止同步调用阻塞请求。


编者了解到,Tars 开源团队在研发 Tars-Go 的过程当中经历的对其各个方面的性能调优改造,Tars-Go 在早先的版本注重于功能的开发和完善,没有体系化地进行压测和性能分析。在业务使用一段时间后,开始注重性能优化。Tars 开源团队对 tars2go 工具先进行了一轮优化,在生成语树的时候生成好了类型信息,避免使用反射进行类型判断,编解码的效率提高了 2 倍,而后对再对总体 servant 进行了一轮轮压测,并进行 CPU profile 性能分析。


下面是性能提高优化的几个实例:


Timer 性能问题

每一个请求进来,Tars-Go 会建立一个协程进行处理,由于要处理调用超时,会建立一个 timer,在结束的时候会删掉 timer,当并发量一上来,就会频繁建立和删除 timer,占用服务大量 CPU 时间。

研发团队在一个 issue 中发现 ,在多 CPU 的场景下,若是存在大量的 timer,性能就会大量损耗,优化方式是每一个 p 有本身的 timer,这样能够大幅提高总体并发性能。因而 Tars-Go 将编译环境升级至 1.10.3,从 profile 来看,性能获得了很大的提高,而且基于时间轮询算法实现了本身的 timer,以精度换取性能和效率。


net 包的 SetDeadline 调用性能问题

为了设置网络链接的读写超时,Tars-Go 使用了 net 包的 SetReadDeadline/SetWriteDeadline 等相关调用,但从 profile 发现,当并发很是大的时候,会致使这两个调用占用了大量的 CPU 时间。为了绕开这两个相关调用,使用了 Sysfd 进行 Socket 读写超时的设置。


bytes Buffer 带来的性能问题

从下图能够看出,有至关大的一部分时间耗在了 slice 相关的操做上,原来在包的编解码过程当中,使用 bytes.Buffer 进行临时存放,当 bytes.Buffer 底层用的 byte slice 大小不够的时候,就会分配必定的内存空间,频繁地分配效率很低,因此致使大包状况下性能降低比较明显。

联想到了 Redis 的内存模型和 Linux 的 slab 机制,对于频繁建立销毁的对象,采用预先建立和重复利用的方式。而 Go 自己提供了一种 sync.Pool 机制,供临时对象的复用,以减小 GC,Tars-Go 在此基础上,实现了相似 Linux slab 机制分配的 buffer 管理方案,经过这种方案,性能大幅提升。


其余方面的优化

通过上面的性能优化后,Tars-Go 在小包的并发表现提高了 5 倍。

  • 压测机型:4 核/8线程 CPU 3.3Ghz 主频 16G 内存

  • 压测逻辑:客户端带着必定大小的数据给服务端,服务端原样返回给客户端

  • 服务端单进程,多个客户端发起测试


Tars-Go 编程示例


Tars 协议是一个二进制协议,它是与语言无关的IDL语言,由工具自动生成服务端和客户端代码,下边是一个 Tars 协议的示例:


具体编程的时候,首先须要定义一个 Tars 文件,以下所示:定义接口 Mult ,a 和 b 为入参,c 为出参,均为整型。


接着生成接口代码。使用 tars2go JesseTest.tars 便可自动生成 pacakge Prajna JesseTest 的 servant 和 Mult 方法的框架实现,业务无需关心实现细节:


最后,实现接口代码,将入参 a、b相乘后的结果放到 c 返回给客户端:

以后 go build 就能够进行编译。


而客户端只需关注出入参,引入由 Tars 文件转化成的包便可完成一次 RPC 调用。


将来,Linux 基金会将增强 Tars 项目的社区运做机制,让 Tars 的影响力从中国走向国际。

  • Tars:https://github.com/TarsCloud

  • Tars-Go:https://github.com/TarsCloud/TarsGo

  • 微信扫码加入TARS-GO官方交流群:

以上内容参考 Tars 开源团队核心成员陈明杰的演讲 PPT 《亿级规模高可用架构源码剖析——腾讯 Go 语言开发框架 TARS-GO》。

相关文章
相关标签/搜索