TARS-PHP:PHP构建高性能RPC框架
内容来源:2018 年 5 月 19 日,阅文集团高级开发工程师梁晨在“PHPCon China 2018 技术峰会”进行《TARS-PHP:PHP构建高性能RPC框架》演讲分享。IT 大咖说(微信id:itdakashuo)作为独家视频合作方,经主办方和讲者审阅授权发布。
摘要
本次分享将介绍高性能RPC框架TARS的基本设计思想,以及在PHP语言和框架层面的TARS解决方案的设计与实现。以阅文集团的实践为例,介绍使用TARS-PHP进行服务治理以及SWOOLE2.0+PHP7+TARS架构所带来的开发、运维、性能的全面提升。
TARS
need-to-insert-img
TARS是包含运营、平台、通信框架、公共组件、统一协议的整套解决方案。上图是TARS的最新界面,分为服务管理和运维管理两部分,服务管理能够轻易的管理各种不同的服务,运维管理可以进行部署服务、扩展以及新建模板管理。这些都是TARS的运营和平台的能力,除此之外它还内置了很多公共组件,以服务的方式提供,包含常见的配置中心、日志中心、通知中心、特性上报以及主控等等。
TRAS 协议
TARS使用了一套二进制的协议,与语言无关有自己的独立语法。上面是协议的基本样式,其中自定了两个结构体LoginInfo和ProfileInfo,结构体内部可以随意的组合多个基础类型。下方的interface声明的是真正要调用的接口,它会用到上方定义的结构,参数列表中的out关键字标明了输出Info。这样我们就有了一份约定的接口文件,之后可以通过工具将它转化为实际使用的代码,从而方便开发。
除了二进制协议之外,我们还设计了一套通信的协议,包含协议版本、请求ID、服务器路由信息、接口信息、二进制数据包。
总的来说TARS是一整套微服务解决方案。微服务方面包括服务自动发现、智能调度、容灾容错、柔性熔断、路由与灰度。协议上即支持私有二进制协议,也可以通过启动HTTP服务来支持json的协议。目前TARS对多语言已经有了很好的支持,同时也兼容一些非常利于使用的运维体系。
TARS PHP
要设计一套TARS PHP方案首先要满足几点要求。第一必须要功能完善,能够对标现有C++、Java、NodeJS体系功能;第二要保持整个方案的灵活使用,让更多的人能够利用它;第三要是轻量级的设计,做到点到为止,即插即用;最后是能带来高效的性能。
need-to-insert-img
上图为整体方案的构成,主要分为4块。第一块是TARS client,因为我们最初的需求是用PHP接入到现有C++、Java的TARS服务。第二块是TARS Server,这里我们希望能够尽量的满足大家的需求,让一些常见的Server能够三合一,同时保持灵活和轻量。第三块是为了能够提升性能做的TARS EXT扩展,主要负责底层二进制的解包打包工作。第四块是开发效率,TARS体系中基本上针对每种语言都会有相应的不管是客户端还服务端的自动生成工具。
TARS client
need-to-insert-img
TARS client现在具备了以上的这些功能。自动寻址让你无需关系服务地址,只需知道服务的名字,我们每个服务都有App name和Server name以及主控,通过主控就能够知道服务的具体位置。主调上报是指所有的服务运行情况都由client上报,这样在Server界面中就能一览服务的所有情况。我们也提供了远程日志的能力,而且是只发不收的形式。接着是3种不同的发送服务的能力,分别是socket的接入方式,swoole同步,以及swoole协程 。
need-to-insert-img
以上是TARS client的整体结构图。中间为client的Server,它依赖于PHP扩展,左边是三种访问方式,右边是各种服务。每次请求的时候会先调用一次主控服务将列表缓存起来,一般缓存在swoole table或本地文件中。服务启动的时候会有定时时间用来决定服务何时过期。获取到地址之后进行RPC请求,请求完成后做一次主调上报,上报范围包括耗时、失败率、超时率等,如果有需要的话也可以写些远程日志。
TARS client 扩展
PHP扩展的主要是用来保证高性能和稳定。由于二进制协议的字符串操作涉及到很多的内存的拷贝和分配,所以我们最初的方案是使用C实现,但后来发现了这种方案有些短板。最终为了性能的考虑引入了PHP扩展,同时将打包解包与编解码进行集成,降低PHP调用API的次数。稳定性方面是在每次提交代码的时候,做多版本构建测试,根据我们线上使用的经验,还增加了Valgrind内存测试,目前的代码测试覆盖率基本上达到80%。
need-to-insert-img
通过上图的数据对比,可以很清楚的看出PHP扩展带来的优势。
TARS Server
Apache加PHP可能是大家较熟悉的传统PHP Server模式,后来随着Nginx的火热出现了Nginx配合PHP-FPM的形式。不过鉴于性能的优势我们之后转向了swoole,随着swoole 2.0的推出又带来了协程的能力。
我们的Server中包含TARS-HTTP-Server、TARS-TIMER-Server、TARS-TCP-Server。HTTP Server提供一些基础的功能,TIMER Server会做一些定时任务,TCP Server是为了提供一个高性能的RPC服务。
need-to-insert-img
Server启动的时候会进行初始化,解析平台下发的配置以及注册服务,之后会每隔1分钟向主控进行一次上报告知存活,如果发现有问题主控会重新将服务拉起了。TARS也支持在平台中建立配置下发到各种服务中,服务会自动向TARS Config拉取配置。
TARS TCP Server可以用swoole 1.0和2.0中的任意版本,不过PHP版本必须要求是5.6以上。它在配置方面非常灵活,既可以将swoole的配置通过平台下发到服务上,也可以指定服务入口。核心实现是基于注解路由,TARS在收到请求的时候会接收到一个包,包中包含调用的服务和接口信息,Server在知道这些信息之后会将需要用到的参数通过预先生成的方式放在注解中,服务启动时会解析这些注解转换成PHP真正调用的数组方式。同时我们还提供了一个管理端口,需要额外启动,用来接收平台的一些其他管理请求。
对于TARS HTTP Server我们仅实现了个相对简单的版本,提供各种基础功能,包括GET/POST请求、Cookie/Status返回、基本路由、文件上传以及Service Detect。
need-to-insert-img
上图是我们通过压测获得一些数据。
开发效率
need-to-insert-img
开发效率一直都是TARS需要关注的问题。从开发模式来看,首先Server会约定一个协议表明本次服务需要提供的接口并生成文件,即图中的TARS文件。然后TARS2PHP工具会根据该文件生成服务端接口代码和客户端调用代码,之后服务端会根据接口代码来实现实际业务逻辑,最后两边就可以联调了。整个过程都是解耦的并且不需要花费过多时间进行client调用。
TARS PHP 在阅文
need-to-insert-img
这里主要介绍下TARS PHP在阅文的应用。首先是接入层,它使用的是Nginx配合斯巴达(TARS在我们内部的系统),通过斯巴达系统能够很轻易的实现无缝扩容。为了实现前后端的解耦我们还引入了TARS Node HTTP,将所有的模板渲染都沉淀都nodeJS层。Nginx的AJAX请求之后会到达TARS PHP HTTP,这一层的业务并发在实际场景中大概是2千左右。再往下是微服务层,我们使用PHP、JAVA做了一些TARS的TCP微服务,它与HTTP的交互是基于TCP异步加协程的方案。
从实际数据来看,目前我们模板拼接的Node HTTP服务大概有十多个,逻辑API层PHP服务与定时服务有40多个,后台TCP服务有100多个,每个调用是亿级以上。
模块化设计
need-to-insert-img
上图是目前TARS PHP支持的模块,这些模块都可以单独的使用。Tars server提供了最基本的HTTP、TCP等服务,tars client可以调用其他tars服务。tars monitor的监控上报包含主调上报和特性上报。Tars registry模块可以让开发者通过主控通信的方式对地址进行缓存。Tars report的引入让开发者能很方便的将自己的框架引入到平台上,而不使用我们提供的框架。