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集羣中服務查看頁面

在這裏插入圖片描述

配置項:
  • -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

<?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"}}
發佈了101 篇原創文章 · 獲贊 27 · 訪問量 24萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章