返回介绍

gRPC 服务

发布于 2021-04-03 03:37:36 字数 8408 浏览 1756 评论 0 收藏 0

gRPC 官方文档中的 quickstart - php, 很容易给 PHPer 产生误导, 按照官网的文档, 运行起来 gRPC 服务就很麻烦, 更不用说整套的 RPC 服务了.

推荐阅读 tech| 再探 grpc, 讲解了在 PHP 中实现 gRPC 相关基础知识.

hyperf 对 gRPC 支持做了更进一步的封装, hyperf-skeleton 项目为例, 详细讲解整个步骤:

  • .proto 文件以及相关配置实例
  • gRPC server 示例
  • gRPC client 示例

.proto 文件以及相关配置实例

  • 定义好 proto 文件 grpc.proto
syntax = "proto3";

package grpc;

service hi {
    rpc sayHello (HiUser) returns (HiReply) {
    }
}

message HiUser {
    string name = 1;
    int32 sex = 2;
}

message HiReply {
    string message = 1;
    HiUser user = 2;
}
  • 使用 protoc 生成示例代码
# 使用 linux 包管理工具安装 protoc, 下面以 alpine 为例, 也可以参考 hyperf-skeleton 下的 Dockerfile
apk add protobuf

# 使用 protoc 自动生成代码
protoc --php_out=grpc/ grpc.proto

# tree grpc
grpc
├── GPBMetadata
│   └── Grpc.php
└── Grpc
    ├── HiReply.php
    └── HiUser.php
  • 配置 composer.json, 使用 grpc/ 下代码的自动加载. 如果 proto 文件中使用不同的 package 设置, 或者使用了不同的目录, 进行相应调整即可,添加之后执行 composer dump-autoload 使自动加载生效
"autoload": {
    "psr-4": {
        "App\\": "app/",
        "GPBMetadata\\": "grpc/GPBMetadata",
        "Grpc\\": "grpc/Grpc"
    },
    "files": [
    ]
},

gRPC server 示例

  • gRPC server 服务器配置

server.php 文件(参考 配置):

'servers' => [
    ....
    [
        'name' => 'grpc',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9503,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\GrpcServer\Server::class, 'onRequest'],
        ],
    ],
],
  • gRPC server 路由配置

routes.php 文件(参考 路由):

Router::addServer('grpc', function () {
    Router::addGroup('/grpc.hi', function () {
        Router::post('/sayHello', 'App\Controller\HiController@sayHello');
    });
});

HiController.php 文件中的 sayHello 方法:

public function sayHello(HiUser $user) 
{
    $message = new HiReply();
    $message->setMessage("Hello World");
    $message->setUser($user);
    return $message;
}

.proto 文件中的定义和 gRPC server 路由的对应关系: /{package}.{service}/{rpc}

  • 如果想更深入一点

gRPC server 如何对 gRPC 请求进行处理的: \Hyperf\GrpcServer\CoreMiddleware::process() (vendor/hyperf/grpc-server/src/CoreMiddleware.php:46, 复制后直接使用 phpstorm 打开), 解析出 request_uri, 即得到 /{package}.{service}/{rpc} 信息, 然后调用好封装好的 gRPC 编解码类 \Hyperf\Grpc\Parser::deserializeMessage(vendor/hyperf/grpc-server/src/CoreMiddleware.php:137), 就可以获取到请求的明文信息

gRPC server 如何进行 gRPC 响应, 相信你可以根据上面的信息, 自己发现.

gRPC client 示例

示例代码可以在 GrpcController 中找到:

public function hello()
{
    // 这个client是协程安全的,可以复用
    $client = new \App\Grpc\HiClient('127.0.0.1:9503', [
        'credentials' => null,
    ]);

    $request = new \Grpc\HiUser();
    $request->setName('hyperf');
    $request->setSex(1);

    /**
        * @var \Grpc\HiReply $reply
        */
    list($reply, $status) = $client->sayHello($request);

    $message = $reply->getMessage();
    $user = $reply->getUser();

    var_dump(memory_get_usage(true));
    return $message;
}

hyperf 已经封装好了 \Hyperf\GrpcClient\BaseClient, 只要根据 .proto 文件中的定义, 按需扩展:

class HiClient extends BaseClient
{
    public function sayHello(HiUser $argument)
    {
        return $this->_simpleRequest(
            '/grpc.hi/sayHello',
            $argument,
            [HiReply::class, 'decode']
        );
    }
}

gRPC 客户端还支持 gRPC 的 Streaming 模式。以双向流为例:

<?
public function hello()
{
    $client = new RouteGuideClient('127.0.0.1:50051');

    $note = new RouteNote();

    $call = $client->routeChat();
    $call->push($note);
    $call->push($note);

    /** @var RouteNote $note */
    [$note,] = $call->recv();
    [$note,] = $call->recv();
}

请注意在 streaming 模式下,您必须手动捕获连接断开的异常 (Hyperf\GrpcClient\Exception\GrpcClientException) 并根据需要选择是否重试。

写在后面

如果你是 gRPC 的重度使用者, 欢迎关注 hyperf 的后续开发者工具, 可以根据 .proto 文件生成全套 gRPC 代码.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文