依赖的组件

hyperf/json-rpc 
hyperf/rpc-client  
hyperf/rpc-server  
hyperf/service-governance 
hyperf/consul 

以 HTTP协议 为例

json-rpc 即为基于json的rpc调用,原理就是 A 和 B 拥有同一套 interface I 的定义,A 就像调用自己的方法一样调用B的方法F,当然F必须是 insterface I 中的方法。

保存镜像

docker commit -p hyperf raoxiaoya/hyperf:v1

一、服务端

1.1、启动服务提供者容器
docker run --name hyperf-db  -p 9503:9503 --network host -v /data/www/hyperf-db:/hyperf-db -it --entrypoint /bin/sh raoxiaoya/hyperf:v1
cd /
composer create-project hyperf/hyperf-skeleton hyperf-db 
安装的时候选择 JSON-RPC 

cd /hyperf-db 
composer require hyperf/consul 
服务治理组件,不然 publishTo 不会生效
composer require hyperf/service-governance 

发布consul组件的配置到app
php bin/hyperf.php vendor:publish hyperf/consul
1.2、定义服务提供者

config/autoload/server.php

'servers' => [
	[
		'name' => 'jsonrpc-http',
		'type' => Server::SERVER_HTTP,
		'host' => '0.0.0.0',
		'port' => 9503,
		'sock_type' => SWOOLE_SOCK_TCP,
		'callbacks' => [
			SwooleEvent::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
		],
	],
],
1.3、定义接口

app/JsonRpc/CalculatorServiceInterface.php

<?php

namespace App\JsonRpc;


interface CalculatorServiceInterface
{
    public function add(int $a, int $b): int;
}

1.4、定义实现类

app/JsonRpc/CalculatorService.php

<?php

namespace App\JsonRpc;

use Hyperf\RpcServer\Annotation\RpcService;

/**
 * @RpcService(name="CalculatorService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="consul")
 */
class CalculatorService implements CalculatorServiceInterface
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }

}
1.5、发布到服务中心

此地址为服务中心的地址,在启动服务时,Hyperf 会自动地将 @RpcService 定义了 publishTo 属性为 consul 的服务注册到服务中心去。

config/autoload/consul.php

return [
    'uri' => 'http://127.0.0.1:8500',
];

二、客户端

2.1、启动服务消费者容器
docker run --name hyperf-api -p 9502:9502 --network host -v /data/www/hyperf-api:/hyperf-api -it --entrypoint /bin/sh raoxiaoya/hyperf:v1

cd /
composer create-project hyperf/hyperf-skeleton hyperf-api 
安装的时候选择 JSON-RPC 

cd /hyperf-api 
composer require hyperf/consul 
2.2、定义服务消费者

config/autoload/server.php

'servers' => [
	[
		'name' => 'http',
		'type' => Server::SERVER_HTTP,
		'host' => '0.0.0.0',
		'port' => 9502,
		'sock_type' => SWOOLE_SOCK_TCP,
		'callbacks' => [
			SwooleEvent::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
		],
	],
],
2.3、设置服务提供方地址,注册中心的地址

config/autoload/services.php

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://doc.hyperf.io
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
return [
    'consumers' => [
        [
            // name 需与服务提供者的 name 属性相同
            'name' => 'CalculatorService',
            // 服务接口名,可选,默认值等于 name 配置的值,如果 name 直接定义为接口类则可忽略此行配置,如 name 为字符串则需要配置 service 对应到接口类
            'service' => \App\JsonRpc\CalculatorServiceInterface::class,
            // 对应容器对象 ID,可选,默认值等于 service 配置的值,用来定义依赖注入的 key
            'id' => \App\JsonRpc\CalculatorServiceInterface::class,
            // 服务提供者的服务协议,可选,默认值为 jsonrpc-http
            // 可选 jsonrpc-http jsonrpc jsonrpc-tcp-length-check
            'protocol' => 'jsonrpc-http',
            // 负载均衡算法,可选,默认值为 random
            'load_balancer' => 'random',
            // 这个消费者要从哪个服务中心获取节点信息,如不配置则不会从服务中心获取节点信息
            'registry' => [
                'protocol' => 'consul',
                'address' => 'http://127.0.0.1:8500',
            ],
            // 如果没有指定上面的 registry 配置,即为直接对指定的节点进行消费,通过下面的 nodes 参数来配置服务提供者的节点信息
            'nodes' => [
                ['host' => '127.0.0.1', 'port' => 9503],
            ],
            // 配置项,会影响到 Packer 和 Transporter
            'options' => [
                'connect_timeout' => 5.0,
                'recv_timeout' => 5.0,
                'settings' => [
                    // 根据协议不同,区分配置
                    'open_eof_split' => true,
                    'package_eof' => "\r\n",
                    // 'open_length_check' => true,
                    // 'package_length_type' => 'N',
                    // 'package_length_offset' => 0,
                    // 'package_body_offset' => 4,
                ],
                // 当使用 JsonRpcPoolTransporter 时会用到以下配置
                'pool' => [
                    'min_connections' => 1,
                    'max_connections' => 32,
                    'connect_timeout' => 10.0,
                    'wait_timeout' => 3.0,
                    'heartbeat' => -1,
                    'max_idle_time' => 60.0,
                ],
            ],
        ],
    ],
];


2.4、定义接口,同服务端保持一致

app/JsonRpc/CalculatorServiceInterface.php

<?php

namespace App\JsonRpc;


interface CalculatorServiceInterface
{
    public function add(int $a, int $b): int;
}

指的注意的是,app/JsonRpc/CalculatorServiceInterface 接口应该发布到composer包,被多个服务所依赖。

2.5、定义路由
Router::addRoute(['GET'], '/testRpc', 'App\Controller\IndexController@testRpc');
2.7、控制器中调用
public function testRpc()
{
	$client = ApplicationContext::getContainer()->get(CalculatorServiceInterface::class);
	$res = $client->add(1, 2);
	
	return [
		'result' => $res,
	];
}

三、安装consul服务

然而文档中并没有说明如何安装 Consul 服务,以下对 Consul 做一个简单的安装。

docker pull consul

docker run --name=consul -p 8500:8500 -e CONSUL_BIND_INTERFACE=eth0 -d consul

访问页面
http://192.168.2.200:8500/

四、启动服务器

进入hyperf-db容器启动服务提供者

cd /hyperf-db 
php bin/hyperf.php start

在这里插入图片描述
发现consul页面已经出来了一个services
在这里插入图片描述

进入hyperf-api容器启动服务消费者

cd /hyperf-api 
php bin/hyperf.php start

访问接口
http://192.168.2.200:9502/testRpc

返回信息

{
    "result": 3
}

说明我们的服务已经搭建成功了。

优化的点

1、关于接口的管理

上面的示例中接口文件 app/JsonRpc/CalculatorServiceInterface.php 我是手动创建的,在实际应用中,或有很多个接口文件,且被不同的人管理,那么在这rpc架构中,这些接口又被多个服务所依赖,一旦接口被改动,都需要同步到其他依赖的服务,这是一件很抓狂的事情,所以我们应该将所有的接口整合到一个composer包,然后其他服务直接引入这个包,如果接口有改动,其他服务重新拉取即可。

创建composer包:https://blog.csdn.net/raoxiaoya/article/details/107759887

在 client 和 server 中都执行 composer require phprao/composer-test=v1.0.1 下载接口。然后删掉原先的接口文件
app/JsonRpc/CalculatorServiceInterface.php 然后把引用的 namespace 改一下就可以使用了。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐