devweyes/ws-server-cluster

websocket cluster server for swoft

v1.0 2020-01-10 07:07 UTC

This package is not auto-updated.

Last update: 2020-08-08 10:14:26 UTC


README

1. 介绍

基于swoole websocket server的swoft websocket已经很方便的开箱即用,但其无法直接支持多机器集场。

本组件可支持大多数web推送场景,IM互聊场景,IM群发场景等。

使用前请通读Swot webdocket Server文档,配置习惯与其并无任何变化。

流程请参见下图

avatar

  • ① 客户端发起握手请求并建立连接
  • ② 当前服务端向资源管理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
        ]
    ],
···

新增中间键概述

avatar

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