0%

hyperf 服务注册与服务发现

前言

在 hyperf 里,支持 Consul 和 Nacos 作为服务中心的组件,本文使用 Consul 作为服务中心演示 hyperf 里面的服务注册与服务发现。

依赖的组件

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

docker 网络

在本文的实验环境下,服务提供者、服务消费者以及服务中心都在同一个 docker 网络下,下面的命令是创建 docker 网络的:

1
docker network create hyperf

启动 consul

下面的命令启动了一个 consul 容器,并且加入了名为 hyperf 的 docker 网络,这样就可以方便跟服务提供者、服务消费者进行网络通信:

1
docker run --rm --network="hyperf" -p 8500:8500 -p 8400:8400 -p 8600:8600 --name="consul" consul

服务提供者

新建项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 启动容器
docker run --name provider \
-v /workspace/skeleton:/data/project \
-p 9501:9501 -it \
--privileged -u root \
--entrypoint /bin/sh \
--network="hyperf" \
hyperf/hyperf:7.4-alpine-v3.11-swoole

# 在容器里面进行安装 hyperf,安装的时候需要选择的话全部回车,使用默认选项
composer create-project hyperf/hyperf-skeleton

cd hyperf-skeleton

# 安装依赖
composer require hyperf/json-rpc
composer require hyperf/rpc-server

# 安装服务注册与发现的依赖
composer require hyperf/service-governance
composer require hyperf/service-governance-consul

配置服务提供者

打开文件 config/autoload/server.php,在 servers 块里面添加:

1
2
3
4
5
6
7
8
9
10
[
'name' => 'jsonrpc-http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9503,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
Event::ON_REQUEST => [Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
],
],

定义服务接口类

创建接口类:app/Contracts/CalculatorServiceInterface.php:

1
2
3
4
5
6
7
8
<?php

namespace App\Contracts;

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

定义接口实现类

创建实现类:app/JsonRpc/CalculatorService.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace App\JsonRpc;

use App\Contracts\CalculatorServiceInterface;
use Hyperf\RpcServer\Annotation\RpcService; // 这个不能去掉

/**
* 注意,如希望通过服务中心来管理服务,需在注解内增加 publishTo 属性
* @RpcService(name="CalculatorService", protocol="jsonrpc-http", server="jsonrpc-http", publishTo="consul")
*/
class CalculatorService implements CalculatorServiceInterface
{
// 实现一个加法方法,这里简单的认为参数都是 int 类型
public function add(int $a, int $b): int
{
// 这里是服务方法的具体实现
return $a + $b;
}
}

@RpcService 有四个参数:

  • name 属性为定义该服务的名称,这里定义一个全局唯一的名字即可,Hyperf 会根据该属性生成对应的 ID 注册到服务中心去;
  • protocol 属性为定义该服务暴露的协议,目前仅支持 jsonrpc-httpjsonrpcjsonrpc-tcp-length-check,分别对应于 HTTP 协议和 TCP 协议下的两种协议,默认值为 jsonrpc-http,这里的值对应在 Hyperf\Rpc\ProtocolManager 里面注册的协议的 key, 它们本质上都是 JSON RPC 协议,区别在于数据格式化、数据打包、数据传输器等不同;
  • server 属性为绑定该服务类发布所要承载的 Server,默认值为 jsonrpc-http,该属性对应 config/autoload/server.php 文件内 servers 下所对应的 name,这里也就意味着我们需要定义一个对应的 Server
  • publishTo 属性为定义该服务所要发布的服务中心,目前仅支持 consulnacos 或为空,为空时代表不发布该服务到服务中心去,但也就意味着您需要手动处理服务发现的问题,要使用此功能需安装 hyperf/service-governance 组件及对应的 驱动依赖,比如,如果使用 consul,还需要安装 hyperf/service-governance-consul

配置服务驱动

修改文件 config/autoload/services.php,修改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
return [
'enable' => [
'discovery' => true,
'register' => true,
],
'consumers' => [],
'providers' => [],
'drivers' => [
'consul' => [
'uri' => 'http://consul:8500', // consul 的地址
'token' => '',
],
],
];

启动服务提供者

1
php bin/hyperf.php start

消费者

启动消费者服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 启动容器
docker run --name consumer \
-v /workspace/skeleton:/data/project \
-p 9501:9501 -it \
--privileged -u root \
--entrypoint /bin/sh \
--network="hyperf" \
hyperf/hyperf:7.4-alpine-v3.11-swoole

# 在容器里面进行安装 hyperf,安装的时候需要选择的话全部回车,使用默认选项
composer create-project hyperf/hyperf-skeleton

cd hyperf-skeleton

# 安装依赖
composer require hyperf/json-rpc
composer require hyperf/rpc-client

# 安装服务注册与发现的依赖
composer require hyperf/service-governance
composer require hyperf/service-governance-consul

配置服务提供者地址

新建文件 config/autoload/services.php,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

return [
'enable' => [
'discovery' => true,
'register' => true,
],
'consumers' => [
[
'name' => 'CalculatorService',
'registry' => [
'protocol' => 'consul',
'address' => 'http://consul:8500',
],
]
],
'drivers' => [
'consul' => [
'uri' => 'http://consul:8500',
'token' => '',
],
],
];

定义和服务端相同的接口类

app/Contracts/CalculatorServiceInterface.php:

1
2
3
4
5
6
7
8
<?php

namespace App\Contracts;

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

定义消费者实现类

app/JsonRpc/CalculatorServiceConsumer.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace App\JsonRpc;

use App\Contracts\CalculatorServiceInterface;
use Hyperf\RpcClient\AbstractServiceClient;

class CalculatorServiceConsumer extends AbstractServiceClient implements CalculatorServiceInterface
{
protected $serviceName = 'CalculatorService';

protected $protocol = 'jsonrpc-http';

public function add(int $a, int $b): int
{
return $this->__request(__FUNCTION__, compact('a', 'b'));
}
}

在控制器中使用服务消费者

app/Controller/IndexController.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php

declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Controller;

use App\JsonRpc\CalculatorServiceConsumer;
use Hyperf\Di\Annotation\Inject;

class IndexController extends AbstractController
{
/**
* 依赖注入
* @Inject
* @var CalculatorServiceConsumer
*/
protected $service;

public function index()
{
$user = $this->request->input('user', 'Hyperf');
$method = $this->request->getMethod();

return [
'sum' => $this->service->add(1, 2), // 调用消费者,最终是会通过 rpc 调用服务提供者的方法
'method' => $method,
'message' => "Hello {$user}.",
];
}
}

启动服务消费者

1
php bin/hyperf.php start

检验

  1. 打开 http://localhost:8500,在里面可以看到注册的 CalculatorService 服务
  2. 访问 http://localhost:9501,可以看到输出的结果里面有 sum

参考文档

  1. 安装文档 https://hyperf.wiki/2.2/#/zh-cn/quick-start/install
  2. json-rpc 文档 https://hyperf.wiki/2.2/#/zh-cn/json-rpc