Swoft websocket server cluster :叢集部署下推送也不是什麼問題

Polaris發表於2020-01-10

1. 介紹

基於swoole websocket server的swoft websocket已經很方便的開箱即用,但其無法直接支援多機器集場。

本元件可支援大多數web推送場景,IM互聊場景,IM群發場景等。

使用前請通讀Swot webdocket Server文件,配置習慣與其並無任何變化。

專案地址

流程請參見下圖

Swoft websocket server cluster :叢集部署下推送也不是什麼問題

  • ① 客戶端發起握手請求並建立連線
  • ② 當前服務端向資源管理State註冊並繫結當前使用者資訊
  • ③ 服務端A向服務B所在訊息佇列推送訊息
  • ④ 服務端B消費訊息並接收
  • ⑤ 服務端B向客戶端推送訊息

2. 特性

  • 高效能,水平擴容
  • 高可用,所有機器都為master,相互心跳檢測
  • 訊息佇列與狀態管理均採用介面卡模式,預設均為redis驅動,擴充性強
  • 事件均採用Aop切面技術,無感知,解耦
  • 與原Swoft Webdocket使用起來基本一致,習慣保持

3. 安裝

composer

composer require devweyes/ws-server-cluster

redis

預設使用redis記憶體伺服器作為狀態儲存,訊息佇列。所以你還需至少一臺redis伺服器或叢集

4. 使用

基本使用

使用命令,WsModule訊息控制器訊息解析器 請參見Swot webdocket Server文件

一個完整的WsModule需配置全部已知方法註解,用於實現切面。包括@OnHandshake().@OnOpen().@OnMessage().@OnClose() ,@OnMessage()可由訊息控制器代替,否則可能無法正常使用。

叢集配置

預設配置,如需自定義可覆蓋。

<?php

        return [
            Cluster::MANAGER => [  //主配置
                'class' => ClusterManager::class,
                'state' => bean(Cluster::STATE),  //狀態選擇
                'onHandshakeMiddleware' => [ //握手階段中間鍵
                    bean(DefaultAllowMiddleware::class)
                ],
                'onOpenMiddleware' => [ //onOpen階段中間鍵
                    bean(DefaultAuthMiddleware::class)
                ],
                'heartbeat' => 60 //伺服器心跳檢測,相互檢測
            ],
            Cluster::STATE => [ //狀態儲存配置
                'class' => RedisState::class,
                'redis' => bean('redis.pool'),
                'serializer' => bean(Cluster::SERIALIZER),
                'prefix' => 'swoft_ws_server_cluster',
            ],
            Cluster::SERIALIZER => [  //序列化配置
                'class' => PhpSerializer::class
            ]
        ];

bean.php新增非同步程式訊息處理

<?php

use Jcsp\WsCluster\Helper\Tool;
...
'wsServer' => [
    'class' => \Swoft\WebSocket\Server\WebSocketServer::class,
    ...
    //可配置多個訊息消費,視業務量而定
    'process' => array_merge(
                Tool::moreProcess('recvMessageProcess', bean(\Jcsp\WsCluster\Process\RecvMessageProcess::class), 3),
                [
                  //自定義程式
                ]
            )
]
...

bean.php新增訊息控制器中間鍵(如有用到訊息控制器,此選項必須

<?php
···
    'wsMsgDispatcher' => [
        'preMiddlewares' => [
            \Jcsp\WsCluster\Middleware\RecvMessageMiddleware::class
        ]
    ],
···

新增中間鍵概述

Swoft websocket server cluster :叢集部署下推送也不是什麼問題

onHandshakeMiddleware 中間鍵

  • 只需在主配置新增onHandshakeMiddleware集合,即可優雅完成@OnHandshake處的處理。此中間鍵集合一般可用作請求過濾等業務。

  • 類需繼Jcsp\WsCluster\Middleware\AbstracHandshakeMiddleware

  • 方法before為入,after為出,所有中間鍵先入後出順序,引數與@OnOpen一致。

  • 如需阻斷,則需return [false, $response],$response可垮中間鍵傳輸

<?php

namespace Jcsp\WsCluster\Middleware;

use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Http\Message\Request;
use Swoft\Http\Message\Response;

/**
 * @Bean()
 * Class DefaultAllowMiddleware
 * @package Jcsp\WsCluster\Middleware
 */
class DefaultAllowMiddleware extends AbstracHandshakeMiddleware
{
    /**
     * @param Request $request
     * @param int $fd
     */
    public function before(Request $request, Response $response)
    {
        if(!$request->getHeaderLine('auth')) {
            //return [false, $response];
        }
        return [true, $response->withAttribute('allow','true')];
    }
    /**
     * @param Request $request
     * @param int $fd
     */
    public function after(Request $request, Response $response)
    {

    }
}

onOpenMiddleware 中間鍵

  • 只需在主配置新增onOpenMiddleware集合,即可優雅完成@OnOpen處的處理。此中間鍵一般用作處理使用者繫結,頭部token解析等邏輯。

  • 類需繼Jcsp\WsCluster\Middleware\AbstractOpenMiddleware

  • 方法before為入,after為出,所有中間鍵先入後出順序,引數與@OnOpen一致。

內建使用者繫結中間鍵,替換此中間鍵一般需實現Cluster::register用於使用者繫結

<?php

namespace Jcsp\WsCluster\Middleware;

use Jcsp\WsCluster\Cluster;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Http\Message\Request;

/**
 * @Bean()
 * Class DefaultAuthMiddleware
 * @package Jcsp\WsCluster\Handle
 */
class DefaultAuthMiddleware extends AbstractOpenMiddleware
{
    /**
     * @param Request $request
     * @param int $fd
     */
    public function before(Request $request, int $fd)
    {
        //token解析+使用者繫結
        $auth = $request->getHeaderLine('auth');
        if ($auth) {
            Cluster::register($fd, $this->decodeToken($auth));
        }
    }
    /**
     * @param Request $request
     * @param int $fd
     */
    public function after(Request $request, int $fd)
    {
      //出
    }
    private function decodeToken(string $auth)
    {
        return $auth;
    }
}

訊息推送Api

Swoft對單機推送的支援,詳見 Swot webdocket Server訊息推送Api

Cluster支援對所有伺服器的任意客戶端直推訊息

<?php
//對繫結的uid精準推送,@onOpen中間鍵繫結
Cluster::transport(string $message, $uid = null)

Cluster::transportToUid(string $message, ...$uid)
<?php
//對所有在役服務端的客戶端廣播訊息
Cluster::transportToAll(string $message)

內建事件

訊息接收
Jcsp\WsCluster\Event::RECV_MESSAGE

使用者註冊
Jcsp\WsCluster\Event::REGISTER

使用者登出
Jcsp\WsCluster\Event::LOGOUT

server服務心跳
Jcsp\WsCluster\Event::DISCOVER

server服務離線
Jcsp\WsCluster\Event::SHUTDOWN

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章