关于webman异步任务的连接创建的问题(workerman道理相同)

cqqjj1029

问题描述
截图
如图,calltask_init是异步任务服务端用来执行耗时任务,text协议,进程数开12,async_task_proxy为异步任务客户端,websocket协议,进程数开1,我在controller里做http接口,触发异步任务时直接连接async_task_proxy并指定要执行的异步任务。
结果我连接调接口8次,却只有5个任务开始执行了,另外3个任务为等待状态,具体哪个任务执行,目前没发现规律。
我希望得到的结果是:异步任务进程数开12的话,那么只有第13个调用时才会发生任务等待。

运行环境
cat /etc/redhat-release
CentOS Linux release 7.9.2009 (Core)
Workerman version:4.0.33 PHP version:7.4.28
{
"name": "workerman/webman-framework",
"version": "v1.3.9",
}

重现步骤

class TaskInit
{
    //...

    public function onMessage(TcpConnection $connection, $data)
    {
        $workerId = $connection->worker->id;
        // 只接收json字符串
        $data = json_decode($data, true);
        $taskService = new \app\service\CallTask();
        // 调\app\service\CallTask中的init方法(耗时)
        $taskRes = $taskService->init($data['task_id']);
        $connection->send(json_encode($taskRes, JSON_UNESCAPED_UNICODE));
    }

    //...
}
class AsyncTaskProxy
{
    // ...

    public function onMessage(TcpConnection $connection, $data)
    {
        $workerId = $connection->worker->id;
        var_dump("proxy: " . $data);
        // 接收客户端发来的指令
        $data = json_decode($data, true);
        if (isset($data['command']) && isset($data['payload'])) {
            switch ($data['command']) {
                case 'init':
                    // 指令为“初始化呼叫任务”
                    $taskId = $data['payload']['task_id'];
                    $taskConnection = new AsyncTcpConnection('text://127.0.0.1:9611');
                    $taskData = array(
                        'task_id' => $taskId,
                    );
                    $taskConnection->send(json_encode($taskData, JSON_UNESCAPED_UNICODE));
                    $taskConnection->onMessage = function (AsyncTcpConnection $taskConnection, $taskRes) use ($connection) {
                        var_dump('ws代理中的onMessage:');
                        var_dump($taskRes);
                        $taskConnection->close();
                        $connection->send($taskRes);
                    };
                    $taskConnection->connect();
                    break;
            }
        }
    }

    // ...
}
/* process.php */
return [
    // ...
    'calltask_init' => [
        // rabbitmq的消费者示例
        'handler' => process\TaskInit::class,
        // 监听的协议 ip 及端口 (可选)
        'listen'  => 'text://0.0.0.0:9611',
        // 进程数 (可选,默认1)
        'count' => 12,
        // 是否开启reusePort (可选,此选项需要php>=7.0,默认为true)
        'reusePort' => true,
    ],
    'async_task_proxy' => [
        // rabbitmq的消费者示例
        'handler' => process\AsyncTaskProxy::class,
        // 监听的协议 ip 及端口 (可选)
        'listen'  => 'websocket://0.0.0.0:9608',
        // 进程数 (可选,默认1)
        'count' => 1,
        // 是否开启reusePort (可选,此选项需要php>=7.0,默认为true)
        'reusePort' => true,
    ]
];

感谢walkor老大的及时回复
通过在TaskInit的onConnect中打印posix_getpid()确实发现了问题:
截图
发起9次请求,其中3次并没有触发onConnect方法。
我也继续排查一下。

1163 1 2
1个回答

walkor

给TaskInit 进程设置一个onConnect方法,onConnect里打印下进程pid,也能看出来连接的进程pid。

public function onConnect()
{
    echo posix_getpid()."\n";
}

或者
用命令netstat -nt | grep ESTABLISHED | grep 9611 能找出连接的本地端口,
然后用命令 lsof -i:本地端口 能找到连接的是哪个进程 pid

  • cqqjj1029 2022-05-24

    目前还没有找到解决的办法,已知有些异步任务被分配到了正在忙碌中的进程中了,而同时是存在空闲进程的。

  • walkor 2022-05-24

    calltask_init 进程把 'reusePort' => true, 改成 'reusePort' => false, 试下

  • cqqjj1029 2022-05-24

    确实reusePort设置为false后问题就解决了,只不过我还没想明白为什么,复用端口设置为false,就会优先选择空闲进程,而为true时就会优先选择已经连接上进程。

  • walkor 2022-05-24

    reusePort 为 true,由linux内核分配连接到进程,可能你的linux内核没有做到100%平均分配。
    reusePort为false,哪个进程空闲,哪个进程去认领连接

年代过于久远,无法发表回答
🔝