62

GitHub - swoole/grpc-client

 5 years ago
source link: https://github.com/swoole/grpc-client
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

README.md

Swoole-Grpc-Client

Latest Version Build Status Php Version Swoole Version Swoole License

Introduction

由Swoole驱动的Grpc协程客户端, 底层使用高性能协程Http2-Client客户端

  • 同步代码几乎无改动
    • 自动协程调度获得异步高性能
    • 提供Grpc代码生成器Plus版, 0成本迁移
  • 基于Channel实现的消息生产消费
    • 一个客户端连接即可同时hold住上万个请求响应
    • 支持跨协程并发, 多类型Client分享同一连接
  • Etcd的直接支持
    • 使用Http2协议全双工通信+Protobuf极限压缩, 告别同步阻塞与Json打包的低性能

Requirement


Usage

仓库已提供Etcd的生成代码, 如要自己根据proto文件生成代码, 请使用tools目录下的生成工具generator, 使用方法和protocal命令完全一样, 增强了支持以目录作为参数, 自动查找目录下的proto文件生成, 如: 该目录下已提供的grpc生成代码脚本:

# it's generate_grpc.sh
./generator \
--proto_path=./../src/Grpc/Proto \
--php_out=./../src/Grpc \
--grpc_out=./../src/Grpc \
--plugin=protoc-gen-grpc=$1 \
./../src/Grpc/Proto

只需要将proto文件放在Grpc/Proto下, 运行./generate_grpc.sh ../../grpc/bins/opt/grpc_php_plugin (参数是你的grpc php插件位置, 一般在grpc/bins/opt目录中), 即可生成相关代码


Examples

以下示例都可在examples目录下找到并直接运行

Grpc


HelloWorld

经典的Grpc官方示例, 代码更加简洁

$greeterClient = new GreeterClient('127.0.0.1:50051');
$greeterClient->start();
$request = new HelloRequest();
$request->setName('Swoole');
list($reply, $status) = $greeterClient->SayHello($request);
$message = $reply->getMessage();
echo "{$message}\n"; // Output: Hello Swoole

Etcd


Etcd的几个基本操作的使用

Put

$kvClient = new Etcdserverpb\KVClient('127.0.0.1:2379');
$kvClient->start();
$request = new Etcdserverpb\PutRequest();
$request->setPrevKv(true);
$request->setKey('Hello');
$request->setValue('Swoole');
list($reply, $status) = $kvClient->Put($request);
if ($status === 0) {
    echo "{$reply->getPrevKv()->getKey()}\n";
    echo "{$reply->getPrevKv()->getValue()}\n";
} else {
    echo "Error#{$status}\n";
}
$kvClient->close();

Watch

创建一个协程负责Watch, 创建两个协程定时写入/删除键值以便观察效果

// The Watcher
go(function () {
    $watchClient = new Etcdserverpb\WatchClient('127.0.0.1:2379');
    $watchClient->start();

    $watchCall = $watchClient->Watch();
    $request = new \Etcdserverpb\WatchRequest();
    $createRequest = new \Etcdserverpb\WatchCreateRequest();
    $createRequest->setKey('Hello');
    $request->setCreateRequest($createRequest);

    _retry:
    $watchCall->push($request);
    /**@var $reply Etcdserverpb\WatchResponse */
    while (true) {
        list($reply, $status) = $watchCall->recv();
        if ($status === 0) { // success
            if ($reply->getCreated() || $reply->getCanceled()) {
                continue;
            }
            foreach ($reply->getEvents() as $event) {
                /**@var $event Mvccpb\Event */
                $type = $event->getType();
                $kv = $event->getKv();
                if (FilterType::NOPUT === $type) {
                    echo "Put key {$kv->getKey()} => {$kv->getValue()}\n";
                    break;
                } elseif (FilterType::NODELETE === $type) {
                    echo "Delete key {$kv->getKey()}\n";
                    break;
                }
            }
        } else { // failed
            static $retry_time = 0;
            if ($watchClient->isConnected()) {
                $retry_time++;
                echo "Retry#{$retry_time}\n";
                goto _retry;
            } else {
                echo "Error#{$status}: {$reply}\n";
                break;
            }
        }
    }
    $watchClient->close();
});

// The Writer Put and Delete
go(function () {
    $kvClient = new Etcdserverpb\KVClient('127.0.0.1:2379');
    $kvClient->start();
    go(function () use ($kvClient) {
        $request = new Etcdserverpb\PutRequest();
        $request->setKey('Hello');
        $request->setPrevKv(true);
        while (true) {
            static $count = 0;
            co::sleep(.5);
            $request->setValue('Swoole#' . (++$count));
            list($reply, $status) = $kvClient->Put($request);
            if ($status !== 0) {
                echo "Error#{$status}: {$reply}\n";
                break;
            }
        }
        $kvClient->close();
    });
    go(function () use ($kvClient) {
        $request = new Etcdserverpb\DeleteRangeRequest();
        $request->setKey('Hello');
        $request->setPrevKv(true);
        while (true) {
            co::sleep(1);
            list($reply, $status) = $kvClient->DeleteRange($request);
            if ($status !== 0) {
                echo "Error#{$status}: {$reply}\n";
                break;
            }
        }
        $kvClient->close();
    });
});

Auth and Share Client

用户添加/展示/删除以及展示了如何让不同类型的EtcdClient能够使用同一个Grpc\Client创建的连接

go(function () {
    $grpcClient = new Grpc\Client('127.0.0.1:2379');
    $grpcClient->start();
    // use in different type clients

    go(function () use ($grpcClient) {
        $kvClient = new Etcdserverpb\KVClient('127.0.0.1:2379', ['use' => $grpcClient]);
        $request = new Etcdserverpb\PutRequest();
        $request->setPrevKv(true);
        $request->setKey('Hello');
        $request->setValue('Swoole');
        list($reply, $status) = $kvClient->Put($request);
        if ($status === 0) {
            echo "\n=== PUT KV OK ===\n";
        } else {
            echo "Error#{$status}: {$reply}\n";
        }
    });

    go(function () use ($grpcClient) {
        $authClient = new Etcdserverpb\AuthClient('127.0.0.1:2379', ['use' => $grpcClient]);

        $userRequest = new Etcdserverpb\AuthUserAddRequest();
        $userNames = ['rango', 'twosee', 'gxh', 'stone', 'sjl'];
        foreach ($userNames as $username) {
            $userRequest->setName($username);
            list($reply, $status) = $authClient->UserAdd($userRequest);
            if ($status !== 0) {
                goto _error;
            }
        }

        $useListRequest = new Etcdserverpb\AuthUserListRequest();
        list($reply, $status) = $authClient->UserList($useListRequest);
        if ($status !== 0) {
            goto _error;
        }
        echo "\n=== SHOW USER LIST ===\n";
        foreach ($reply->getUsers() as $user) {
            /**@var \Authpb\User */
            echo "* {$user}\n";
        }
        echo "=== SHOW USER LIST OK ===\n";

        $userRequest = new Etcdserverpb\AuthUserDeleteRequest();
        foreach ($userNames as $username) {
            $userRequest->setName($username);
            list($reply, $status) = $authClient->UserDelete($userRequest);
            if ($status !== 0) {
                goto _error;
            }
        }

        if (false) {
            _error:
            echo "Error#{$status}: {$reply}\n";
        }

        echo "\n=== SHOW ALL CLIENT STATS ===\n";
        var_dump(grpc_client_num_stats());
        $grpcClient->close();
    });

});

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK