9、Hyperf 3 微服务系列 - Consul 集群

作者: 温新

分类: 【Hyperf 3 微服务系列】

阅读: 2042

时间: 2023-05-20 12:35:56

hi,我是温新,一名 PHPer

Hyperf 3 微服务代码已上传至 Github:https://github.com/ziruchu/hyperf3-microservice-code

学习目标:学习 consul 集群

生产环境中,服务一般都是以集群方式部署,服务部分一般是在 3~5 台服务器。本篇文章将使用 4 台服务器(虚拟机)来演示,其中有 3 台是 consul 服务器。

准备工作

项目说明

如果是一步一步来走,不出意外,你的项目和我的应该是一样的。本次集群的部署就是复制下面某个应用的代码。

note
note_consumer_user
note_consumer_user_9501
note_provider_user
note_provider_user_9601
准备 4 台服务器

注意:这 4 台服务器我全部使用的是 Rocky Linux 9.1。

服务器 IP Consul 类型 Node 节点 服务类型
192.168.31.92 server server-01 服务者
192.168.31.93 server server-02 服务者
192.168.31.94 server server-03 服务者
192.168.31.90 client client-01 消费者

注意:确保 92、93、94 这三台服务器安装了 PHP。

Consul 集群部署

第一步:安装 Consul

我们需要在 929394 这三台服务安装 Consul 服务,关于怎么安装这里就不再啰嗦了,参考:Hyperf 3 快速使用 - Hyperf 3 微服务系列 - Consul 服务注册与发现 - Rocky Linux 9.1 安装 Consul

第二步:复制项目代码

把 note_provider_user_9601 整体复制到其他 3 台服务器并重命名。

$ scp -r ./note_provider_user_9601/ hy@192.168.31.92:/www/note_provider_user_9602
$ scp -r ./note_provider_user_9601/ hy@192.168.31.93:/www/note_provider_user_9603
$ scp -r ./note_provider_user_9601/ hy@192.168.31.94:/www/note_provider_user_9604
第三步:修改 3 台服务器中代码

1、修改 note_provider_user_9602

# 修改 .env 文件
APP_NAME=node_provider_user_9602
DB_HOST=192.168.31.90
    
# 修改 config/autoload/server.php
'servers' => [
    [
        'name' => 'jsonrpc-http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9602,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
        ],
    ],
],

2、修改 note_provider_user_9603

# 修改 .env 文件
APP_NAME=node_provider_user_9603
DB_HOST=192.168.31.90
    
# 修改 config/autoload/server.php
'servers' => [
    [
        'name' => 'jsonrpc-http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9603,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
        ],
    ],
],

3、修改 note_provider_user_9604

# 修改 .env 文件
APP_NAME=node_provider_user_9604
DB_HOST=192.168.31.90

# 修改 config/autoload/server.php
'servers' => [
    [
        'name' => 'jsonrpc-http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9604,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::class, 'onRequest'],
        ],
    ],
],

4、分别为这 3 台服务提供者添加如下代码,用于区分调用的是哪台服务器的服务

添加接口

<?php
// app/JsonRpc/Interface/UserServiceInterface.php
public function test();

实现接口

<?php
// app/JsonRpc/Service/UserService.php

use Hyperf\Utils\ApplicationContext;
use Hyperf\Contract\ConfigInterface;
    
public function test()
{
    $host = '';

    $config = ApplicationContext::getContainer()->get(ConfigInterface::class);
    $servers = $config->get('server.servers');
    $appName = $config->get('app_name');

    foreach ($servers as $server) {
        if ($server['name'] == 'jsonrpc-http') {
            $host = $server['host'];
            break;
        }
    }

    return ResponseTool::success([
        'app_name' => $appName,
        'host'     => $host,
    ]);
}
第四步:启动 Consul

1、服务端启动 consul

# 
consul agent -server -bind=192.168.31.92 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/software/consul/data/ -node=server-01
    
consul agent -server -bind=192.168.31.93 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/software/consul/data/ -node=server-02
    
consul agent -server -bind=192.168.31.94 -client=0.0.0.0 -ui -bootstrap-expect=3 -data-dir=/usr/local/software/consul/data/ -node=server-03

2、消费端以 client 模式启动

consul agent -client=0.0.0.0 -data-dir=/usr/local/software/consul/data/ -ui -bind=192.168.31.90 -node=client-01
第五步:加入集群
# 位置 192.168.31.93(服务者)
# 显示认为 92 这台服务器是主节点
consul join 192.168.31.92
    
# 位置 192.168.31.94(服务者)
consul join 192.168.31.92
    
# 位置 192.168.31.90 (消费者)
consul join 192.168.31.92

所有 consul 加入 92 这台服务器,把它当作主节点。

服务启动后,每台服务可以访问 web 管理界面。

第六步:查看集群
$ consul members
Node       Address             Status  Type    Build   Protocol  DC   Partition  Segment
server-01  192.168.31.92:8301  alive   server  1.15.1  2         dc1  default    <all>
server-02  192.168.31.93:8301  alive   server  1.15.1  2         dc1  default    <all>
server-03  192.168.31.94:8301  alive   server  1.15.1  2         dc1  default    <all>
client-01  192.168.31.90:8301  alive   client  1.15.1  2         dc1  default    <default>

消费者调用服务者

消费者继续使用 note_consumer_user_9501 这个项目。

第一步:修改接口

<?php
// app/JsonRpc/Interface/UserServiceInterface.php
public function test();

第二步:实现接口方法

<?php
// app/JsonRpc/Service/UserService.php
public function test()
{
    return $this->__request(__FUNCTION__);
}

第三步:控制器调用

<?php
// app/Controller/UserController.php

use App\Tools\ResponseTool;
    
#[GetMapping('/users/test')]
public function test()
{
    return ResponseTool::success($this->userService->test());
}

第四步:测试 consule 集群

先调用获取用户方法

# 通过浏览器访问,刷新 N 次,都是一样的结果
http://192.168.31.90:9501/users/show?id=1

{
  "code": 200,
  "message": "success",
  "data": {
    "id": 1,
    "name": "李四",
    "gender": 1,
    "created_at": "2023-03-21 04:37:43",
    "updated_at": "2023-03-21 04:37:43"
  }
}

测试调用的哪个 consul 服务

# 多刷新几次,注意 app_name 的变化
http://192.168.31.90:9501/users/test

{
  "code": 200,
  "message": "success",
  "data": {
    "code": 200,
    "message": "success",
    "data": {
      "app_name": "node_provider_user_9602",
      "host": "0.0.0.0"
    }
  }
}

http://192.168.31.90:9501/users/test
{
  "code": 200,
  "message": "success",
  "data": {
    "code": 200,
    "message": "success",
    "data": {
      "app_name": "node_provider_user_9604",
      "host": "0.0.0.0"
    }
  }
}

从这个测试结果中,我们可以看到集群已经生效,而且正被我们使用者。

现在继续测试,断开一台 consul 服务器,然后进行测试,服务还是正常运行。

集群策略

集群已经搭建完成,也可以正常使用了,通过尽情的测试,它会在 92、93、94 这三个服务者中不断轮转,有点像 nginx 的负载均衡。现在回顾一下配置文件,来看看其中策略。

<?php
// 位置:note_consumer_user_9501 消费者服务
// config/autoload/services.php
$services = [
    'UserService' => \App\JsonRpc\Interface\UserServiceInterface::class,
];

return [
    'consumers' => value(function () use($services) {
        $consumers = [];
        foreach ($services as $name => $interface) {
            $consumers[] = [
                'name'          => $name,
                'service'       => $interface,
                'load_balancer' => 'random',
                'registry'      => [
                    'protocol' => 'consul',
                    'address'  => 'http://192.168.31.90:8500'
                ]
            ];
        }
        return $consumers;
    }),
];

load_balancer 为负载均衡算法,默认值为 random

我是温新,本篇文章到此结束。

请登录后再评论