TARS开启阅文集团技术架构变革之门

本文作者:欧樑

后端研发架构师,现任职于阅文集团技术部基础服务研发组,一直致力于Java应用架构设计以及业务架构演进研发,对分布式系统架构有深入理解。

什么是TARS

TARS(点击阅读原文,快速访问GitHub)是腾讯从2008年到今天一直在使用的后台逻辑层统一应用框架(Total Application Framework)的开源版本,目前支持C++,Java和NodeJs三种语言。

该框架为用户提供了涉及到开发、运维、以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。 它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用微服务的方式构建自己的稳定可靠的分布式应用,并实现完整有效的服务治理。

目前该框架在腾讯内部的各大核心业务都在使用,颇受欢迎,基于该框架部署运行的服务节点规模达到上万个。内外部版本在代码结构、功能上基本相同。本文基于私有云版本的TARS,部分功能可能与目前开源及公有云TARS版本有所区别。

业务集的现状

公司TARS业务服务集每日接口调用最大值近百亿,业务峰值在数万每秒,近60种业务服务。对于常规的开发部署方式,必然会花费大量成本进行编码、部署以及运维的统一。使用TARS则轻松很多,正是TARS优秀的服务表现,为公司的APP抗住了515书友粉丝节,百万红包,除夕手Q线上联动等过亿级用户量的活动。

业务集结构

TARS哪里好

TARS是个大而全的分布式应用。抛开对开发部署习惯的改变,用了TARS之后,确实省却了很多且又方便了很多。

  • 服务容错方面,TARS拥有基本的容错和负载均衡,让我们可以忽略间歇、偶发、永久的设备故障,任何一台服务器down掉都不影响业务访问,同时提供对网络异常,超时节点屏蔽,定时重试和流量导回的切换能力。
  • 高性能方面,TARS运用Reactor模型以及能够高效支持百万级别的句柄监听——Epoll ET。为TARS框架提供高达41w/s吞吐量。
  • 伸缩性方面,扩容是业务发展必不可少的过程,TARS对平滑扩容提供良好支持,流程化的配置可完成无感知的服务扩容升级。
  • 管理和运维方面,TARS自带监控模块,对主调反馈做了实时统计,在管理界面提供了多维度性能数据图。供开发及运维判断当前服务状态,并可配置参数阈值进行短信或微信告警通知。

TARS的具体使用方法

TARS开发流程

1开发TARS,必须知道如何撰写JCE接口文件

JCE接口文件借鉴了ICE[1] ,引入代码生成的思路,并结合无线侧手机的应用场景,做到了编解码效率和网络带宽使用的权衡考虑。TARS的JCE接口描述语言文件是以.tars后缀结尾的。

[1] ICE是什么:ICE ,Internet Communications Engine,是一个面向对象,适用于异构环境的中间件平台。

对于一个上层业务服务,调用5-6个基础TARS是常有的事情。摸清产品业务后,分别找到对应服务的开发,由于每个服务基本是一个TARS服务。所以沟通一个服务只需3步:1.“XX服务的JCE能给我下吗!?;”2.传来一个JCE文件;3.“thanks”;

JCE的内容都是约定俗成的,对应的结构体和接口也有相应注释。所以,沟通就是那么简洁明了。

下图为JCE文件:

JCE文件

2JCE与TARS服务端的实际开发

通过jce-maven-plugin编译,可生成特定Servant接口。继承接口就可实现业务逻辑。

Servant接口

继承类

在遵循TARS规范的java项目里面,services.xml中配置此继承类。

services.xml

TARS项目有特定目录结构,具体结构如下图gateway。service项目为一个普通java project,可在本地开发通过后,发布jar类库引入gateway中,TARS容器只需编译gateway即可。

TARS目录结构

TARS的目录结构以及严格maven化,省去了开发逻辑代码单独打包的过程。同时严格的区分了开发及上线测试流程,对规范研发管理流程有极大的帮助。

3TARS客户端调用流程

获取Communicator实例

CommunicatorConfig cfg = CommunicatorConfig.load("config.conf");

Communicator communicator = CommunicatorFactory.getInstance().getCommunicator(cfg);

获取ServantProxyConfig实例并配置

ServantProxyConfig proxyConfig = new ServantProxyConfig(taf.serverName);

TARS config对象常用参数设置

调用Communicator的stringToProxy方法并传入ServantProxyConfig实例,最后返回Jce生成的动态代理对象,并调用对应的方法。

communicator.stringToProxy(api, proxyConfig);

ServantProxyFactory中创建动态代理对象

TARS支持接口同步或异步调用,通过对config对象超时时间的设置,可以实现软件层面的服务过载保护。

同步调用:

HelloPrx prx = c.stringToProxy("TestApp.HelloServer.HelloObj");

//发起远程调用

prx.hello(1000, "hello word");

异步调用:

HelloPrx prx = c.stringToProxy("TestApp.HelloServer.HelloObj");

//发起远程调用

prx.async_hello(new HelloPrxCallback() {

@Override

public void callback_expired() { }

@Override

public void callback_exception(Throwable ex) { }

@Override

public void callback_hello(String ret) {

System.out.println(ret);

}

}, 1000, "hello word");

从去年到现在,公司迁移改造如火如荼的进行。主要目标是从.net代码中阅读逻辑,用JAVA改写成一个个TARS服务。同时提供更高的可用性,为公司app相关的新需求迭代保驾护航。

在这个过程中,对于app的接口提供层(Tomcat部署)改动极大,从原来直接访问数据持久层到调用一个个TARS微服务,其中不乏一些问题。

曾经一段时间,对于TARS的接入采取了最简单有效的同步方式,并利用TARS提供的客户端同步超时配置来处理接口超时。结果,一个访问频繁的读取接口由于网络传输的不稳定,会导致连锁的处理线程独占,从而降低整个服务吞吐能力,并伴有重启等现象。

经过jvm,gc等分析,改用TARS提供的异步方式获取接口返回以及编码层面细粒度的超时控制,基本解决了上述问题。目前,业务调用总量也翻了番(峰值从当时120W左右到目前250W),节省了一半的设备。

TARS被调方式的多样性也对不同业务场景支持更加全面。

4

JCE-WUP协议

TARS除了支持客户端通过JCE生成类的调用方式,还可以发起WUP数据包协议调用。

什么是WUP:

1、WUP(wireless uni-protocol)无线统一协议

2、基于JCE编码的命令字(Command)层协议封装

3、UniPacket实现请求与回应包对象的封装

支持协议动态扩展

4、序列化的数据可用于网络传输或者持久化存储

5、支持直接调用TARS的服务端

JAVA版本封包方式

TafUniPacket uniPacket = new TafUniPacket();

uniPacket.setTafVersion(Const.VERSION_WUP3);

uniPacket.setEncodeName("UTF-8");

uniPacket.setServantName("TestApp.HelloServer.HelloObj");

uniPacket.setFuncName("hello");

uniPacket.put("word", "Hello World");

byte[] sendPackect = uniPacket.encode();

随后自己使用Socket发包,调用信息为TARS服务物理机URL,而非主控URL。

TARS通过轮询或者健康统计来选择可用URL。

具体逻辑可查看tars-core源码,com.qq.TARS.client.cluster.DefaultLoadBalance类:

tars-core源码

对应于WUP,TARS有相同的概念TUP。相关工具类为TARSUniPacket,封包、解包、调用TARS服务方式完全一样。

https://github.com/Tencent/TARS/blob/master/docs/TARS_tup.md

5

结合版本控制工具编译和发布

TARS支持常用版本控制管理工具的关联编译:SVN/GIT。录入SVN路径,可扫描到该路径下有效的分支。录入GIT路径,可扫描该目录下有效TAG分支。

TARS编译界面

发布的相关日志管理也集成在平台中,可实时确定发布情况。

TARS发布界面

所有的TARS项目用的编译发布都是一套,通过一定队列分配进行作业。编译后会生成唯一的发布版本。存储了历史发布记录,可追溯,方便回滚。

团队中有很多业务开发并行进行,会创建很多分支。有时你想学习别人的代码,但又发现有很多分支无法确定目前线上运行的版本,通过发布日志就可查询最近发布的版本分支。

6

TARS提供了容器接口测试功能

服务正常发布后,遵循TARS自定义入参出参的格式,即可调用JCE中定义的方法进行自测。

TARS接口测试

对于一个接口的开发,本地测试完,只能说接口逻辑通了。放到线上可能会出种种问题,环境配置、接口性能、接口未能符合分布式的考虑等等。这个测试功能无疑是可以验证线上是否正确的良好手段。

加上TARS的接口可以转换暴露成HTTP形式,所以,QA与我们达成一致,每次提测的接口必须提供HTTP的调用。这样既方便的了功能验证,又可以遵循原先的压测形式。

7

服务多维度监控

服务调量和性能指标监控直观反应服务运行情况,通过不同维度的设置和查询,可迅速评估流量高峰、定位响应异常、查看调用路径以及优化调用毛刺。

多维度查询控制

直观耗时曲线

调用链查询

TARS监控已经成为我们定位问题的第一入口。流量抖动和耗时增加基本可以一目了然。监控还细化到接口维度,为“闲暇时间”接口优化提供了参考。

8

TARS提供了丰富的参数配置

TARS的默认配置对于平日开发维护基本够用。对于特殊业务的特定配置,TARS同样支持,可通过调节各种参数来增加服务表现。举例TARS-JAVA,可通过节点服务管理增加Reactor模型工作线程数,亦可通过修改配置模板调优jvm参数或服务超时等特性。

记得某业务服务从Tomcat改用TARS。原因不必多说,主要是默认了TARS的高吞吐以及容错等特性。可运行一天后,突然收到了短信告警,平均耗时超过阈值。打开TARS监控观察,调用量没有明显上涨,调用曲线也符合之前业务特性。

“怎么耗时一直在慢慢上涨”。当时第一反应是不是代码层面问题,排查了一圈,基本确定和原有“汤姆猫”上运行的代码一致,除了适配TARS入口调用的代码。再查看了物理机的监控,CPU/IO/MEM均没有特别异常。

通过对TARS特性监控的查看,注意到相关监控中req.queue.waitingtime(请求在队列中等待时间),jvm.thread.num(jvm当前线程总数) 确有异常。等待时间曲线阶段性增长,线程数却不多。初步判定应该与服务器处理线程有关。

“都是应用服务器,处理能力怎么那么低,如果是Tomcat会器调整maxConnections,acceptCount等等”。

倒腾了半天,原来TARS也支持容器性能细粒度的修改。于是把工作线程数,从默认配置的5改成了32,重启观察一阵,现象没有再发生。

TARS同时提供私有模板功能,可做更细粒度的配置,甚至jvm层面的调优。把配置能力没有保留的提供给使用者也是个优秀架构易用性的重要体现。

TARS的展望

Tencent已于2017年04月10日正式在github上对外开放了TARS的开源版本(查看阅读原文,直接访问),同时提供了技术讨论群(qq技术交流群:579079160),并表示会内部一直使用和对外一直维护。

TARS支持群

可以预见,TARS将能够支持更多天马行空的产品需求,对于业务支撑和线上极端情况的容错度将越来越大。希望这篇科普可以勾起各位的兴趣,帮助大家早日加入使用TARS的行列。

文章来源于腾讯云开发者社区,点击查看原文