使用GatewayWorker框架,多个workerman进程(businessworker)负载不均衡的问题解决过程

公司搭建一套智慧社区、智能对讲管控云平台时,使用GatewayWorker框架搭建app端外推送的服务。发现性能比预期的低。也就是GatewayWorker(https://github.com/walkor/GatewayWorker/)中的workerman组件往google fcm 服务和ios apns服务推送消息的性能不及预期。经过netstat -lanp后发现只有其中一个workerman进程的Recv-Q有堆积数据,表明只有该进程收到来自gateway组件的网络消息堆积来不及处理,其他几个workerman进程不会。是什么原因造成的呢?

经过一番定位,通过在workerman组件的onMessage回调函数中增加日志:打印出workerman自己的进程id,发现每次都是其中一个进程id而已,也就是说gateway将客户端的消息全部推送给这一个workerman进程,并没有对多个业务workerman进程做负载均衡。进过分析源码发现在:\GatewayWorker\vendor\workerman\gateway-worker\src\Gateway.php文件中的class Gateway构造函数如下:

    /**
     * 构造函数
     *
     * @param string $socket_name
     * @param array  $context_option
     */
    public function __construct($socket_name, $context_option = array())
    {
        parent::__construct($socket_name, $context_option);
		$this->_gatewayPort = substr(strrchr($socket_name,':'),1);
        //added by chenyc,更改负载均衡的方式。由routerBind改成routerRand.因为routerBind的路由选择是根据client_id来的,
        //akcs的业务推送客户端一般只有一个,所以出现负载不均衡的问题
        $this->router = array("\\GatewayWorker\\Gateway", 'routerRand');

        $backrace                = debug_backtrace();
        $this->_autoloadRootPath = dirname($backrace[0]['file']);
    }

原先gateway的负载均衡策略是routerBind(上述的代码已经修改过来了,看修改记录),相应的函数定义如下:

    /**
     * client_id 与 worker 绑定
     *
     * @param array         $worker_connections
     * @param TcpConnection $client_connection
     * @param int           $cmd
     * @param mixed         $buffer
     * @return TcpConnection
     */
    public static function routerBind($worker_connections, $client_connection, $cmd, $buffer)
    {
        if (!isset($client_connection->businessworker_address) || !isset($worker_connections[$client_connection->businessworker_address])) {
            $client_connection->businessworker_address = array_rand($worker_connections);
        }
        return $worker_connections[$client_connection->businessworker_address];
    }

即负载均衡算法跟客户端的client_id绑定的,对于我们的业务,推送客户端就是我们的业务逻辑服务器,当前只有一台,所以每次负载均衡算法都映射到唯一的一个workerman进程,导致上面提出的现象。

问题原因查出来了,修改就很简单,框架也有另一个负载均衡算法,是每次客户端消息过来,gateway随机选择一个workerman进程来处理,对应的算法是routerRand,定义如下:

    /**
     * 随机路由,返回 worker connection 对象
     *
     * @param array         $worker_connections
     * @param TcpConnection $client_connection
     * @param int           $cmd
     * @param mixed         $buffer
     * @return TcpConnection
     */
    public static function routerRand($worker_connections, $client_connection, $cmd, $buffer)
    {
        return $worker_connections[array_rand($worker_connections)];
    }

          修改后问题解决!

你可能感兴趣的:(php)