Jump to Navigation

gRPC对PHP的支持情况说明

gRPC对PHP的支持情况说明

gRPC设计能够支持大多数常用编程语言,PHP也不例外。

不过由于gRPC对不同语言的支持力度不一样,有些语言支持的非常完善,

而有些语言支持的不够完善,甚至达不到能够使用程度。

很不幸的是PHP语言正是支持力度非常靠后的一种语言。

gRPC包括客户端部分和服务端部分,对不同的语言也同时分为这两个部分。

以前从这两个部分说明gRPC的 PHP支持情况,软件包使用的是各包最新的有版本号的beta状态的包。

(也许还可以完全部使用仓库的HEAD版本进行测试,结果也许有所不同,后续有测试之后补上。)

基础依赖包

  • gRPC C实现包和运行库
  • protobuf实现包和运行库
  • PHP-5.5+

对PHP客户端的支持

客户端的支持,需要几个模块的配合使用,

  • 一个PHP扩展,
  • 一个对此扩展的简单PHP封装,
  • 一个对protoc提供的生成PHP代码的插件
PHP扩展

源代码:https://github.com/grpc/grpc/tree/master/src/php/ext/grpc

虽然提供了源代码,但是最好还是使用pecl中的包安装,更稳定些。

(注意如果要测试仓库中的版本,也需要安装仓库中的gRPC版本,即版本要匹配。)

pecl包地址:https://pecl.php.net/package/gRPC

目前gRPC-php的pecl扩展包是beta状态,0.6.1版本。

该版本能够与gRPC-0.11.1版本共存兼容。

编译安装过程在些不做详细说明了,与其他的pecl包安装一致。

编译安装过程还好,没有出现编译错误的问题。

简单客户示例代码:

$port = 5000;
$chan = new Grpc\Channel('127.0.0.1:'.$port);

$req_text = 'client_server_full_request_response';
$reply_text = 'reply:client_server_full_request_response';
$status_text = 'status:client_server_full_response_text';

{
    $call = new Grpc\Call($chan, '/foo/bar/1.0', Grpc\Timeval::infFuture());

    $batch = [
        Grpc\OP_SEND_INITIAL_METADATA => [],
        Grpc\OP_SEND_CLOSE_FROM_CLIENT => true,
        Grpc\OP_SEND_MESSAGE => ['message' => $req_text],
    ];

    $result = $call->startBatch($batch);

    $rbatch = [
        Grpc\OP_RECV_INITIAL_METADATA => true,
        Grpc\OP_RECV_MESSAGE => true,
        Grpc\OP_RECV_STATUS_ON_CLIENT => true,
    ];

    $evt = $call->startBatch($rbatch);
}

$r = $chan->close();
unset($chan);

这个示例是直接使用扩展提供的类和方法,直接执行了一个gRPC通信,不包括信息的格式化如protobuf。

完整示例:https://git.xiaojukeji.com/liuguangzhao/atapi/blob/master/dorpc.php

如果有一个简单的gRPC服务存在的话,这个示例能够运行,至于运行的情况,至少不会出现程序崩溃退出的情况。

但并不是没有问题,一个非常明显的问题是,程序在程序完成后,

即使$chan->close()了,控制流程达到程序结尾了,程序也不会退出,

而是等待约10秒后才会退出,这应该是个通信超时设置,应该是可以设置的。

不过这还是和程序流程执行到程序结尾会退出不一致,可能是还有实现与预期的执行结果不一致的问题。

这是gRPC-PHP扩展部分,编译安装执行没有大问题,但执行预期目前看来达不到能够正常使用的程度。

对gRPC-PHP扩展的进一步封装

源代码:https://github.com/grpc/grpc/tree/master/src/php/lib/Grpc

把这个目录放在PHP的include_paths中完成安装。

这个包相对来说还是比较基础的封装,没有涉及到gRPC通信消息格式化,如protobuf。

目前还没有直接测试这个包,但这个包为下一个封装度更高的包准备的,所以没有直接测试这个中间包。

protoc生成PHP代码的插件

源代码:https://github.com/stanley-cheung/Protobuf-PHP

把这个目录放在PHP的include_paths中完成安装。

该包提供了一个可执行程序protoc-gen-php,用来在protoc命令执行时生成gRPC调用的PHP代码。

不过,这里有个问题,Go语言版本的protoc-gen-go可执行程序,能够同时生成gRPC调用的服务端和客户端代码。

而protoc-gen-php目前只能生成gRPC调用的PHP客户端代码,并不支持生成胳服务端调用代码。

也就是说,对PHP的支持,目前仅限于客户端。对于服务端,至少在文档上的说明还是缺失的,并且没有示例代码可以参考。

至少不能像在Go语言中的那样,使用protoc-gen-go生成的服务端代码直接启动一个对应的gRPC服务。

另外,这个的安装最好在gRPC目录树中,使用php composer安装:

目录:https://github.com/grpc/grpc/tree/master/src/php/lib

这样能够通过composer的依赖管理功能,可以一同把依赖包安装了。

对PHP服务端的支持

在gRPC扩展中,已有实现了Server类,并且做了一点测试,确实能够接收请求,响应请求。

并且没有出现客户端的hangup的情况,一直能够良好提供服务处理与响应请求。

但是正如前一段对客户端中的说明一样,与PHP客户端并不太兼容,也许可以与其他语言的客户端共存使用,还需要点测试。

不过使用的是原始的gRPC协议拼装,没有用protobuf等高级封装。

还是提供一个简单示例吧:

$address = "127.0.0.1";
$port = '5001';

$srv = new Grpc\Server();

$port = $srv->addHttp2Port("0.0.0.0:".$port);
$srv->start();

$handler = function($srv, $evt) {
    $reply_text = 'reply:client_server_full_request_response';
    $status_text = 'status:client_server_full_response_text';

    $batch = [
        Grpc\OP_SEND_INITIAL_METADATA => [],
        Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
        Grpc\OP_SEND_STATUS_FROM_SERVER => [
            'metadata' => [],
            'code' => Grpc\STATUS_OK,
            'details' => $status_text,
        ],
        Grpc\OP_RECV_MESSAGE => false,
        Grpc\OP_RECV_CLOSE_ON_SERVER => true,
    ];

    $batch = [
        Grpc\OP_SEND_INITIAL_METADATA => [],
        Grpc\OP_SEND_MESSAGE => ['message' => $reply_text],
        Grpc\OP_SEND_STATUS_FROM_SERVER => [
            'metadata' => [],
            'code' => Grpc\STATUS_OK,
            'details' => $status_text,
        ],
        Grpc\OP_RECV_CLOSE_ON_SERVER => true,
    ];

    $nevt = $evt->call->startBatch($batch);
};

for (;;) {
    $evt = $srv->requestCall();
    $handler($srv, $evt);
}

本示例中,使用一个无限循环接收请求,一个函数处理请求与响应请求。

$srv->requestCall阻塞等待新的请求,有请求的时候才返回。

完整示例:https://git.xiaojukeji.com/liuguangzhao/atapi/blob/master/dorpc.php

由于PHP是单线程执行,可以看到这个示例无法并行处理请求的,这是PHP的特点,但却让PHP语言使用更简单直接不谈。

看上去这个原始的gRPC服务运行的挺好,并没有出现什么明显的问题。

只是封装度不够,目前不能够与protobuf联合使用。

gPRC端到端不同语言测试矩阵

目前的测试:

  • Go客户端,Go服务端:运行正常,支持protobuf协议封装
  • PHP客户端,PHP服务端:客户端退出时hangup超时,服务端运行良好,不支持protobuf协议封装
  • PHP客户端,Go服务端:客户端退出时hangup超时,服务端运行良好,支持protobuf协议封装
  • Go客户端,PHP服务端:尚未测试。

也许还可以有更多的组合测试,再补充。

总结

目前Go语言的支持最成熟,为beta状态,可以使用。

对PHP语言的支持很不完善,为alpha状态,并且官方没有对用PHP实现服务的支持。

反倒是有明确的暂不支持使用PHP写服务的说明:https://groups.google.com/forum/#!topic/grpc-io/Rz79JXrX4-M

PHP客户端:官方表示支持,有相应的protobuf封装,解决了目前发现的hangup问题可以使用。

PHP服务端:暂不支持。

目前来说如果要使用PHP,有可能的也只是使用PHP实现gRPC客户端调用,还需要找到正确的使用方式,也许要等待修复bug。

目前PHP用gRPC即使实现,也可能不稳定,不建议线上系统使用。

不过,可以跟进gRPC对PHP的支持情况,如果可能也可以通过阅读代码,更深入了解实现机制,尽快使用PHP实现gRPC功能。

gRPC-PHP扩展提供的API列表及简单说明

虽然还不太完善,还是先列出来,应该完善后变化不会太大了。

类Grpc\Server
  • __construct(array $args);
  • int addHttp2Port(string $address);
  • int addSecureHttp2Port(string $address);
  • bool start();
  • mixed requestCall();
类Grpc\Channel
  • __construct();
  • mixed getTarget();
  • mixed getConnectivityState();
  • mixed watchConnectivityState();
  • void close();
类Grpc\Call
  • __construct();
  • void startBatch(array $cmds);
  • string getPeer();
  • void cancel();
类Grpc\Timeval

添加新评论

Plain text

  • 不允许HTML标记。
  • 自动将网址与电子邮件地址转变为链接。
  • 自动断行和分段。
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.


Main menu 2

Story | by Dr. Radut