Linux下搭建Consul微服务注册中心并结合swoft框架使用

Consul

Consul是一个服务发现和注册的工具,其具有分布式、高扩展性能特点,它是HashiCorp公司推出的一款实用开源工具,支持Linux等平台。
Consul主要包含如下功能:

  • 服务发现: 支持 http 和 dns 两种协议的服务注册和发现方式。
  • 监控检查: 支持多种方式的健康检查。
  • Key/Value存储: 支持通过HTTP API实现分布式KV数据存储。
  • 多数据中心支持:支持任意数量数据中心。

swoft-consul 组件,整合了 consul 功能,开发者可以直接通过该组件使用 consul 功能。

首先下载consul文件包

wget https://releases.hashicorp.com/consul/1.6.2/consul_1.6.2_linux_amd64.zip
unzip consul_1.6.2_linux_amd64.zip

解压之后实际上是一个单一的文件 ./consul

然后配置consul集群

主服务器: 192.168.56.107
备份服务器:
192.168.56.108
192.168.56.102

192.168.56.107的服务启动命令
./consul agent -server -data-dir=/tmp/consul -bootstrap-expect=3 \
-node=agent-one -bind 192.168.56.107 -enable-script-checks=true \
-config-dir=/etc/consul.d -datacenter=sunny -client 0.0.0.0 \ -ui &
192.168.56.108的服务启动命令
./consul agent -server -data-dir=/tmp/consul \
-node=agent-two   \
-bind=192.168.56.108 -enable-script-checks=true \
-config-dir=/etc/consul.d -datacenter=sunny \
-ui  -client 0.0.0.0 \
-join 192.168.56.107 &
192.168.56.109的服务启动命令
./consul agent -server -data-dir=/tmp/consul \
-node=agent-three   \
-bind=192.168.56.109 -enable-script-checks=true \
-config-dir=/etc/consul.d -datacenter=sunny \
-ui  -client 0.0.0.0 \
-join 192.168.56.107 &
192.168.56.102的客户端服务启动命令
./consul agent -data-dir=/tmp/consul \
-node=client   \
-bind=192.168.56.102 -enable-script-checks=true \
-config-dir=/etc/consul.d -datacenter=sunny \
-ui  -client 0.0.0.0 \
-join 192.168.56.107 &

注意:

  • Consul集群如果想要实现故障转移,必须要配置统一的数据中心名称 示例:-datacenter
  • Consul能够实现自动故障转移,也就是说如果当前leader服务器不可用了,会重新选举出一个leader服务器。
    查询集群中leader节点命令:./consul operator raft list-peers
  • 服务端集群的节点数目最好达到奇数个比较好,不然会导致选举leader失败。根据raft算法,需要有N/2+1个节点才能正常选举leader。
  • 注意这里consul客户端应该跟应用在同一台服务器上部署,然后consul配置项不用添加 host 即可。
Consul集群中服务查看页面

Linux下搭建Consul微服务注册中心并结合swoft框架使用_第1张图片

配置项:
  • -bootstrap-expect 这个就是表示期望提供的SERVER节点数目,数目一达到,它就会被激活,然后就是LEADER了。 这不能与传统-bootstrap标志一起使用。此标志需要在服务端模式下运行。
  • -server 以服务端模式启动
  • -data-dir 数据存放位置,这个用于持久化保存集群状态
  • -node 群集中此节点的名称。这在群集中必须是唯一的。默认情况下,这是计算机的主机名。
  • -bind 绑定服务器的ip地址
  • -config-dir 指定配置文件服务,当这个目录下有 .json 结尾的文件就会加载进来,更多配置可以参考 consul api文档
  • -enable-script-checks 检查服务是否处于活动状态,类似开启心跳检测
  • -datacenter 数据中心名称
  • -client 客户端可访问ip,包括HTTP和DNS服务器。如果是“127.0.0.1”,仅允许环回连接;这里改为“0.0.0.0”,允许外网访问。
  • -ui 开启web的ui界面
  • -join加入到已有的集群中

配置http server中的consul相关项

/app/bean.php

return [
//其他配置项

//consul配置项 若本地起了consul客户端代理服务,就不用填host和port
‘consul’=> [
// ‘host’ => ‘192.168.56.107’,
// ‘port’ => 8500,
‘timeout’=> 3,
]
]

启动 swoft http 服务
php /var/www/html/swoft/bin/swoft http:start
如果发现swoft http服务启动失败,可以先杀掉这些swoft-http进程,具体命令如下:
sudo ps -ef|grep "swoft-http"|grep -v "grep" |awk '{print $2}'|xargs kill -9
http服务启动时将当前服务注册到Consul

无论是 http / rpc / ws 服务,启动的时候只需监听 SwooleEvent::START 事件,即可把启动的服务注册到第三方集群。

文件: app/listener/RegisterServiceListener.php

 declare(strict_types=1);
/**
 * This file is part of Swoft.
 *
 * @link     https://swoft.org
 * @document https://swoft.org/docs
 * @contact  [email protected]
 * @license  https://github.com/swoft-cloud/swoft/blob/master/LICENSE
 */

namespace App\Listener;

use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Consul\Agent;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Http\Server\HttpServer;
use Swoft\Log\Helper\CLog;
use Swoft\Server\SwooleEvent;

/**
 * Class RegisterServiceListener
 *
 * @since 2.0
 *
 * @Listener(event=SwooleEvent::START)
 */
class RegisterServiceListener implements EventHandlerInterface
{
    /**
     * @Inject()
     *
     * @var Agent
     */
    private $agent;

    /**
     * @param EventInterface $event
     * @throws
     */
    public function handle(EventInterface $event): void
    {
        /** @var HttpServer $httpServer */
        $httpServer = $event->getTarget();

        $service = [
            'ID'                => 'swoft',
            'Name'              => 'swoft',
            'Tags'              => [
                'http'
            ],
            'Address'           => '192.168.56.102',
            'Port'              => $httpServer->getPort(),
            'Meta'              => [
                'version' => '1.0'
            ],
            'EnableTagOverride' => false,
            'Weights'           => [
                'Passing' => 10,
                'Warning' => 1
            ]
        ];


        // Register
        $this->agent->registerService($service);
        CLog::info('Swoft http register service success by consul!');
    }
}

该listener能起作用,这一句不可少 @Listener(event=SwooleEvent::START)

http服务关闭时,在Consul中心取消注册该服务

app/Listener/DeregisterServiceListener.php

namespace App\Listener;

use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Consul\Agent;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Http\Server\HttpServer;
use Swoft\Log\Helper\CLog;
use Swoft\Server\SwooleEvent;

/**
 * Class DeregisterServiceListener
 *
 * @since 2.0
 *
 * @Listener(SwooleEvent::SHUTDOWN)
 */
class DeregisterServiceListener implements EventHandlerInterface
{
    /**
     * @Inject()
     *
     * @var Agent
     */
    private $agent;

    /**
     * @param EventInterface $event
     * @throws
     */
    public function handle(EventInterface $event): void
    {
        /** @var HttpServer $httpServer */
        $httpServer = $event->getTarget();

        $this->agent->deregisterService('swoft');
        CLog::info("arrive in here, ".__METHOD__."\n");
    }
}

onShutdown事件 (@Listener(SwooleEvent::SHUTDOWN))
此事件在Server正常结束时发生
函数原型:function onShutdown(swoole_server $server);

在此之前Swoole\Server已进行了如下操作

  • 已关闭所有Reactor线程、HeartbeatCheck线程、UdpRecv线程
  • 已关闭所有Worker进程、Task进程、User进程(用户自定义的进程)
  • 已close所有TCP/UDP/UnixSocket监听端口
  • 已关闭主Reactor
agent默认注入的consul对象

文件: /vendor/swoft/consul/src/Consul.php

/**
 * Class Consul
 *
 * @since 2.0
 *
 * @Bean("consul")
 */
class Consul
{
    /**
     * @var string
     */
    private $host = '127.0.0.1';

    /**
     * @var int
     */
    private $port = 8500;

    /**
     * Seconds
     *
     * @var int
     */
    private $timeout = 3;
    //下面代码省略...... 
}

可以看出 listener里注入的agent默认使用的本地客户端作为代理

consul读写kv及服务发现代码示例

文件: app/Model/Logic/ConsulLogic.php

public function kv(): void
    {
        $value = 'value content';
        $this->kv->put('/test/my/key', $value);

        $response = $this->kv->get('/test/my/key');
        var_dump($response->getBody(), $response->getResult());
    }

    /**
     * 根据服务名称获取微服务注册信息
     * @param string $serviceName 服务名称
     * @return array
     * @throws ClientException
     * @throws ServerException
     */
    public function getServiceList(string $serviceName): array
    {
        $services = $this->agent->services();
        $bodyContent = $services->getBody();
        CLog::info(var_export($bodyContent, true));

        $arrJson = JsonHelper::decode($bodyContent, true);
        if (!isset($arrJson[$serviceName])) {
            return [];
        }
        CLog::info(var_export($arrJson, true));
        return $arrJson[$serviceName];
    }

######测试服务发现及KV

	/**
  * @RequestMapping()
  * @param Request $request
  * @return Response
  * @throws Swoft\Bean\Exception\ContainerException
  * @throws Swoft\Consul\Exception\ClientException
  * @throws Swoft\Consul\Exception\ServerException
  * @throws \ReflectionException
  */
 public function consulKv(Request $request): Response
 {
     $arrReq = $request->getParsedQuery();
     $value = $arrReq['value'];
     $this->consulBean->kv();
     return context()->getResponse()->withData(['code' => 200, 'msg'=>'ok', 'data'=>['value'=>$value]]);
 }

 /**
  * @RequestMapping()
  *
  * @param Request $request
  * @return Response
  * @throws Swoft\Consul\Exception\ClientException
  * @throws Swoft\Consul\Exception\ServerException
  */
 public function serviceList(Request $request): Response
 {
     $arrReq = $request->getParsedQuery();
     $service = $arrReq['service'];
     $output = $this->consulBean->getServiceList($service);
     return context()->getResponse()->withData(['code' => 200, 'msg'=>'ok', 'data'=>$output]);
 }

测试:
http://192.168.56.102:18306/test/serviceList?service=swoft
运行结果:

{"code":200,"msg":"ok","data":{"ID":"swoft","Service":"swoft","Tags":["http"],"Meta":{"version":"1.0"},"Port":18306,"Address":"192.168.56.102","Weights":{"Passing":10,"Warning":1},"EnableTagOverride":false}}

http://192.168.56.102:18306/test/consulKv?value=howareyou
运行结果:

{"code":200,"msg":"ok","data":{"value":"howareyou"}}

你可能感兴趣的:(php,编程框架)