内容简介:Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架TAF(Total Application Framework),目前支持C++、Java、PHP、Nodejs与Go语言。该框架为用户提供了涉及到开发、运维,以及测试的一整套解决方案,...
Tars是腾讯从2008年到今天一直在使用的后台逻辑层的统一应用框架TAF(Total Application Framework),目前支持C++、 Java 、 PHP 、Nodejs与 Go 语言。该框架为用户提供了涉及到开发、运维,以及测试的一整套解决方案,帮助一个产品或者服务快速开发、部署、测试、上线。它集可扩展协议编解码、高性能RPC通信框架、名字路由与发现、发布监控、日志统计、配置管理等于一体,通过它可以快速用微服务的方式构建自己的稳定可靠的分布式应用,并实现完整有效的服务治理。
TarsPHP作为Tars在PHP语言的解决方案,设计的时候主要考虑如下四个方面:
- 功能完善:对标现有C++、Java与NodeJS体系功能
- 灵活:论灵活,谁与PHP争锋?
- 轻量:用最轻量的设计,点到即止,即插即用
- 高效:插上Swoole协程的翅膀,不得不飞
Protobuf简介
Protocol buffers (简称PB)是Google开源的语言中立,平台无关,可扩展的序列化数据的格式,可用于通信协议,数据存储等。它和XML类似,但比XML更小,更快,更简单。
PB是编码协议,如果涉及到网络传输和RPC调用,就需要引入通讯协议。Google开源的RPC框架gRPC就使用Http2作为通讯协议,PB作为编码协议。
和TarsGo中关于PB支持的不同
TarsGo中关于PB的支持,本质是对proto协议文件的支持,提供将proto协议文件转换为tars协议的能力,在相互调用中实际使用的是tars协议。这个服务可以和其他Tars服务相互工作。
TarsPHP中关于PB的支持,是构建了一个gRPC服务,这个服务部署在Tars平台上,参与tars平台寻址,受tars平台管理。这个服务使用gRPC on Http2作为网络通讯协议,使用Protobuf作为编码协议,可以和其他PB client 相互工作。
两者方向不同,不能混合使用,希望大家区分。
相关数据
我们使用相同Http服务,分别使用Tars和Pb协议和后端服务通讯并进行压测。
- 服务器环境:2核 4G,php 7.2.16,swoole 4.4.0
- 服务空跑指的是简单的ping到后端服务,不进行任何业务处理直接返回;
- 单次简单RPC指的是向后端服务获取弹幕数量返回一个int,数量值rand生成,并没有使用mysql count;
- 单次复杂PRC会实际向后端获取弹幕列表结构体,包含多条弹幕对象完整结构。
| QDPS | PB | TARS |
|---|---|---|
| 服务空跑 | 3800 | 6200 |
| 单次简单RPC | 3600 | 6150 |
| 单次复杂RPC | 1050 | 1150 |
从压测数据来看,Tars性能比PB高出一截,但对比两者打包解包性能发现PB打包解包性能略优于Tars,导致这样结果的主要原因我认为是gRPC使用Http2作为通讯协议相比Tars的自定义通讯协议需要跟多开销。
使用TarsPHP 构建 PB Server
初始化环境
-
Protoc 安装
-
首先需要安装protoc库,这个库的主要作用是打包解包protobuf协议数据。可以参考 https://github.com/protocolbuffers/protobuf/tree/master/src 直接安装。
./autogen.sh ./configure make make install如果 protoc –version 可以正常输出,说明安装完成
-
-
php protobuf安装
-
之后需要安装 php protobuf扩展,这个扩展主要用作php和protoc库中间的一个桥梁。
git clone https://github.com/protocolbuffers/protobuf.git cd ./php/ext/google/protobuf/ phpize ./configure make make install (需要编辑php.ini文件,开启protobuf扩展)如果 php –ri protobuf 有输出,说明安装正常。
-
-
Swoole 安装
-
建议使用4.4.0或以上版本,需要开启http2 和 openssl支持。
-
编写一个proto文件
参考TarsPHP中ActDemo中评论服务的tars文件,我们写了一个actComment.proto的协议文件。
和tars协议文件不同,proto协议中规定输入输出参数必须也只能是一个message结构体,因此需要对输入输出参数单独在封装一个message。
syntax = "proto3";
package protocol.QD.ActCommentPbServer; //包名,会根据包名生成 php类路径
service CommentObj {
rpc ping(PingRequest) returns (PingResponse) {};
rpc getCommentCount(CountRequest) returns (CountResponse) {};
rpc createComment(CreateRequest) returns (CreateResponse) {};
rpc getComment(GetRequest) returns (GetResponse) {};
}
//输入参数通用结构体
message CommonInParam {
int32 appId = 1;
int32 areaId = 2;
int64 userId = 3; //用户信息
string userIp = 4; //来源名称
string serverIp = 5; //调用方服务器ip
};
//输出参数通用结构体
message CommonOutParam {
int32 code = 1; //接口返回码
string message = 2; //接口返回提示信息
};
message SimpleComment {
int32 id = 1;
int64 activityId = 2;
int64 userId = 3;
string content = 4;
string title = 5;
string ext1 = 6;
int64 createTime = 7;
};
message QueryParam {
int64 activityId = 1;
int32 page = 2;
int32 size = 3;
int32 orderType = 4;
};
message CreateRequest {
CommonInParam inParam = 1;
SimpleComment comment = 2;
};
message CreateResponse {
CommonOutParam outParam = 1;
};
message GetRequest {
CommonInParam inParam = 1;
QueryParam queryParam = 2;
};
message GetResponse {
CommonOutParam outParam = 1;
repeated SimpleComment list = 2;
};
message PingRequest {
};
message PingResponse {
};
message CountRequest {
};
message CountResponse {
int32 count = 1;
};
生成server端代码
protoc可以根据proto文件生成对应的php类代码,但是官方并不支持proto文件生成server端代码,可以使用gRPC插件生成client代码。如果需要使用生成的client代码我们还需要安装grpc库和grpc php扩展。
因此我们的思路是,先使用protoc生成php需要的类,然后自己解析proto文件生成server 端interface,这个过程非常像现有的tars2php的过程,因此我们叫它proto2php。
由于使用两个 工具 生成还比较麻烦,我们把调用proto的过程集成到proto2php中方便大家使用。
我们先构建一个tars.proto.php设置一些基本信息。
return array(
'appName' => 'QD',
'serverName' => 'ActCommentPbServer',
'objName' => 'CommentObj',
'withServant' => true, //决定是服务端,还是客户端的自动生成
'tarsFiles' => array(
'./actComment.proto',
),
'dstPath' => '../src/protocol', //这里指定的是 impl 基础interface 生成的位置
'protocDstPath' => '../src', //这里指定的是 protoc 生成的问题
'namespacePrefix' => 'Protocol',
);
然后执行 php …/src/vendor/phptars/tars2php/src/proto2php.php ./tars.proto.php
之后会生成GPBMetadata目录和protocol目录。其中protocol中就是proto文件生成的php类,另外CommentObjServant.php就是proto2php文件生成的server端interface类。构建TarsPHP pb server需要实现这个类。
部署TarsPHP PB server
按照Demo中 Readme部署tarsphp pb server即可。
几点注意:
- 需要在impl目录中实现interface逻辑。
- 在src下的services.php中指定home-api,home-class位置,protocolName是pb,serverType是grpc
- tars平台上协议类型是 tcp,非tars协议。
- 需要在composer.json中添加require “google/protobuf”,autoload中需要配置 Protocol 和 GPBMetadata,范例如下:
{ "name" : "tars-tcp-server-demo", "description": "tars tcp server", "require": { "phptars/tars-server": "~0.3", "phptars/tars-deploy": "~0.1", "phptars/tars-log": "~0.1", "phptars/tars2php": "~0.1", "ext-zip" : ">=0.0.1", "google/protobuf": "^3.8" }, "autoload": { "psr-4": { "Server\\" : "./", "Protocol\\" : "./protocol", "GPBMetadata\\" : "./GPBMetadata" } }, "minimum-stability": "stable", "scripts" : { "deploy" : "\\Tars\\deploy\\Deploy::run" } }
最后执行 composer run-script deploy,生成代码包,上传到Tars平台上发布。
使用client 访问
可以使用gRPC生成的php客户端访问测试,也可以直接使用swoole 的http2客户端构建一个grpc客户端。
class TestGrpcClient
{
public static function callGrpc($ip, $port, $path, $requestBuf)
{
$cli = new Swoole\Coroutine\Http2\Client($ip, $port, false);
$cli->connect();
$req = new swoole_http2_request;
$req->method = 'POST';
$req->path = $path;
$req->headers = [
"user-agent" => 'grpc-c/7.0.0 (linux; chttp2; gale)',
"content-type" => "application/grpc",
"grpc-accept-encoding" => "identity,deflate,gzip",
"accept-encoding" => "identity,gzip",
"te" => "trailers",
];
$req->pipeline = false;
$req->data = $requestBuf;
$cli->send($req);
$response = $cli->recv();
return $response->data;
}
public static function main()
{
$commonIn = new CommonInParam();
$commonIn->setUserId(0);
$commonIn->setAppId(1);
$commonIn->setAreaId(10);
$commonIn->setServerIp('127.0.0.1');
$commonIn->setUserIp('');
$query = new QueryParam();
$query->setActivityId(123);
$query->setPage(1);
$query->setSize(10);
$query->setOrderType(1);
$request = new GetRequest();
$request->setInParam($commonIn);
$request->setQueryParam($query);
$requestBuf = $request->serializeToString();
$packBuf = pack('CN', 0, strlen($requestBuf)) . $requestBuf;
go(function () use ($packBuf){
$path = "/protocol.QD.ActCommentServer.CommentObj/getComment";
$ret = self::callGrpc('127.0.0.1', 10008, $path, $packBuf); //这里注意要修改成你服务在tars上绑定的ip 127.0.0.1不一定可以
$response = new GetResponse();
$response->mergeFromString(substr($ret, 5));
foreach ($response->getList() as $row) {
var_dump($row->getContent());
}
});
}
}
执行php client.php观察返回。
生成client端代码
前面提到的client,只是我们访问PB server 的简单demo,可以帮助我们测试PB server的状态。如果需要在其他Tars服务中调用PB server应该如何使用呢?和Tars类似我们也提供了生成PB client端代码的方式。
这里使用TarsActDemo下的QD.ActHttpServer为范例演示如何生成Tars PB client代码并调用PB服务。
- 拷贝actComment.proto文件到tars目录
- 构建actCommentPb.proto.php 文件,内容和生成server代码用的tars.proto.php内容一致,修改 withServant = false
- 执行 php …/src/vendor/phptars/tars2php/src/proto2php.php ./actCommentPb.proto.php
- 之后在protocol/QD/ActCommentPbServer 中可以看到相关生成代码。(和Server 端代码类似,CommentObjServant.php是 proto2php生成的,其他文件是proto2php 调用 protoc 插件生成的)
- 和Server端类似需要添加 GPBMetadata 和 Protocol 到composer.json 的psr-4中。
- 和Tars 调用类似,可以直接调用CommentObjServant类的相关方法和PB 服务通讯。需要注意的是 传入的 CommunicatorConfig 中的socketModel 需要设置为 4 grpc 模式。
范例如下:
$inParam = new CountRequest();
$outParam = new CountResponse();
$conf = self::getConfig();
$conf->setSocketMode(4);
$servant = new CommentObjServant($conf);
$servant->getCommentCount($inParam, $outParam);
return $outParam->getCount();
欢迎给项目点 star 并参与贡献。
https://github.com/TarsPHP/TarsPHP
作者:张勇
以上所述就是小编给大家介绍的《TarsPHP 新版本发布,支持 Protobuf 协议》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Paradigms of Artificial Intelligence Programming
Peter Norvig / Morgan Kaufmann / 1991-10-01 / USD 77.95
Paradigms of AI Programming is the first text to teach advanced Common Lisp techniques in the context of building major AI systems. By reconstructing authentic, complex AI programs using state-of-the-......一起来看看 《Paradigms of Artificial Intelligence Programming》 这本书的介绍吧!
JSON 在线解析
在线 JSON 格式化工具
HTML 编码/解码
HTML 编码/解码