gRPC 服务开发
目录
介绍
在 imi 框架中集成 gRPC 服务开发、客户端调用及连接池。
通讯协议为二进制的 Protobuf。
Github: https://github.com/imiphp/imi-grpc
仅支持 Swoole
Composer
本项目可以使用composer安装,遵循psr-4自动加载规则,在你的 composer.json
中加入下面的内容:
{
"require": {
"imiphp/imi-grpc": "~2.1.0"
}
}
然后执行 composer update
安装。
你也可以直接创建 imi gRPC 骨架项目:composer create-project imiphp/project-grpc:~2.1.0
使用说明
可以参考 https://github.com/imiphp/imi-grpc/tree/master/example 目录示例,包括完整的服务端和客户端调用。
服务和消息格式定义
gRPC 和 Protobuf 是黄金搭档,Protobuf 是用来做通讯消息格式的序列化和反序列化的工作。
gRPC 通讯有请求(Request)消息和响应(Response)消息,从请求消息中获取请求参数,通过响应消息返回给客户端。
定义参考:example/grpc/grpc.proto
syntax = "proto3";
package grpc;
option php_generic_services = true;
service AuthService {
rpc Login (LoginRequest) returns (LoginResponse);
}
message LoginRequest {
string phone = 1; // 手机号
string password = 2; // 密码
}
message LoginResponse {
bool success = 1; // 是否成功
string error = 2; // 错误信息
}
定义好后,通过命令生成 PHP 文件:protoc --php_out=./ grpc.proto
protoc 下载和安装:https://github.com/protocolbuffers/protobuf/releases
生成好文件后,要把生成出来文件所在命名空间,配置到 composer.json
,例:
"autoload": {
"psr-4": {
"Grpc\\": "grpc/Grpc",
"GPBMetadata\\": "grpc/GPBMetadata",
}
},
服务端
config.php
配置忽略目录
'ignorePaths' => [
\dirname(__DIR__) . \DIRECTORY_SEPARATOR . 'grpc',
],
如果你用主服务器:
[
// 主服务器配置
'mainServer' => [
'namespace' => 'ImiApp\GrpcServer',
'type' => 'GrpcServer',
'host' => '127.0.0.1',
'port' => 8080,
],
]
如果你用子服务器:
[
// 子服务器(端口监听)配置
'subServers' => [
// 子服务器名
'XXX' => [
'namespace' => 'ImiApp\GrpcServer',
'type' => 'GrpcServer',
'host' => '127.0.0.1',
'port' => 8080,
]
],
]
控制器
写法与 Http Api 几乎一致。
标准 gRPC Url 格式为:http://host:port/{package}.{service}/{method}
/**
* @Controller("/grpc.AuthService/")
*/
class AuthServiceController extends HttpController implements AuthServiceInterface
{
/**
* Method <code>login</code>
*
* @Action
*
* @param \Grpc\LoginRequest $request
* @return \Grpc\LoginResponse
*/
public function login(\Grpc\LoginRequest $request)
{
$response = new LoginResponse;
$success = '12345678901' === $request->getPhone() && '123456' === $request->getPassword();
$response->setSuccess($success);
$response->setError($success ? '' : '登录失败');
return $response;
}
}
客户端
连接池配置
[
// 连接池配置
'pools' => [
'grpc' => [
'pool' => [
'class' => \Imi\Rpc\Client\Pool\RpcClientCoroutinePool::class,
'config' => [
// 根据实际情况设置
'maxResources' => 100,
'minResources' => 1,
],
],
'resource' => [
// 这里需要和你的服务端路由一致
'url' => 'http://127.0.0.1:8080/{package}.{service}/{name}',
// 'url' => 'http://127.0.0.1:8080/{package}.{service}/{name|ucfirst}', // 参数支持设定函数处理,比如这个将方法名首字母大写,兼容其它部分语言
'clientClass' => \Imi\Grpc\Client\GrpcClient::class,
'method' => 'POST', // 指定请求方式,默认 GET
],
],
],
'rpc' => [
'defaultPool' => 'grpc',
],
]
客户端调用
代码调用:
// $service = \Imi\Rpc\Client\Pool\RpcClientPool::getInstance('连接池名')->getService('服务名', '生成出来的服务接口类名');
$service = \Imi\Rpc\Client\Pool\RpcClientPool::getInstance()->getService('grpc.AuthService', \Grpc\AuthServiceInterface::class);
$request = new \Grpc\LoginRequest;
$request->setPhone('');
$service->login($request);
注解调用:
use Imi\Rpc\Annotation\RpcClient;
use Imi\Grpc\Client\Annotation\GrpcService;
class Test
{
/**
* @RpcClient()
*
* @var \Imi\Rpc\Client\IRpcClient
*/
protected $rpcClient;
/**
* @GrpcService(serviceName="grpc.AuthService", interface=\Grpc\AuthServiceInterface::class)
*
* @var \Grpc\AuthServiceInterface
*/
protected $authService;
public function aaa()
{
$request = new \Grpc\LoginRequest;
$request->setPhone('');
// 方法一
$this->rpcClient->getService('服务名', '生成出来的服务接口类名')->方法名($request);
// 方法二
$this->xxxRpc->方法名($request);
}
}
@GrpcService
注解的 serviceName
属性格式为 {package}.{service}
;interface
属性是生成出来的服务接口类名
↓↓↓注意↓↓↓:
使用@GrpcService
注解注入时,如果调用的grpc
接口方法名是:getName
、send
、recv
、call
、getClient
,请使用call
方法来调用,因为这和内置方法名相冲突了。