已到问题所在,但是不知道为什么大佬帮忙看看 这边人气高,大佬多,麻烦帮我看看是不是多进程导致变量污染啊

排骨苏

问题已找到 $this->clearRedisCache(); 删掉就没事了 我不知道为什么会出现这个情况,如果加上 ,高并发时候 就会出现fd1 发送到fd2里面,但是只是定义了一个清理redis的方法啊

<?php

require __DIR__ . '/vendor/predis/predis/autoload.php';
require __DIR__ . '/app/functions.php';
use Predis\Client;
class WebSocket{
    private $server;
    private $redis;
    private $host = '127.0.0.1:6379?read_write_timeout=0';

    public function __construct(){
        $this->redis = new Client('tcp://'.$this->host);
        //重新启动时删除所有redis缓存
        $this->clearRedisCache();

        $this->server = new Swoole\WebSocket\Server("0.0.0.0", 8088);
        echo 'websocket ...' . PHP_EOL;
        $this->server->set([
            'worker_num' => 4
        ]);
        $this->server->on('open', function (Swoole\WebSocket\Server $server, $request) {
            $fd = $request->fd;
            $param = $request->get;
            $dmId = $param['id'] ?? 0;
            $redisKey1 = "lottery-swoole-".$dmId;
            $this->redis->setex($redisKey1,3600*24,$fd);
            $this->redis->setex('websocket-id' . $fd,3600 * 24,$redisKey1);
            $this->server->push($fd,json_encode([
                'action' => 'heartbeat',
                'mess' => '连接心跳'
            ]));
        });
        $this->server->on('message', function (Swoole\WebSocket\Server $server, $frame) {

        });
        $this->server->on('close', function ($ser, $fd) {
            echo "{$fd} 关闭连接\n";
            $redisKey3 = $this->redis->get('websocket-id' . $fd);
            if($redisKey3){
                $this->redis->del($redisKey3);
                $this->redis->del('websocket-id' . $fd);
            }

        });
        $this->server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) {

            $dm_id = $request->get['dm_id'] . PHP_EOL;

            $redisKey4 = trim("lottery-swoole-" . $dm_id);
            $data = [
                'id' => (int)$request->get['uid'],
                'nickname' => $request->get['nickname'],
                'img' => $request->get['img']
            ];
            $fdId = $this->redis->get($redisKey4);
            if($fdId){

                echo $fdId . "-待发送" . PHP_EOL;
                if($this->server->isEstablished($fdId)) {
                    echo $fdId . "-发送成功" . PHP_EOL;
                    $this->server->push($fdId, json_encode($data));
                }

            }

            $response->header('Content-Type', 'text/html; charset=utf-8');
            $response->end('success');
        });

        $this->server->start();
    }

    private function clearRedisCache(){
        $patterns = ['dm-swoole-*', 'lottery-swoole-*', 'websocket-id*'];
        foreach ($patterns as $pattern) {
            $this->deleteRedisKeys($pattern);
        }
    }

    private function deleteRedisKeys($pattern) {
        $keys = $this->redis->keys($pattern);
        foreach ($keys as $key) {
            $this->redis->del($key);
        }
    }

}

new WebSocket();
523 2 0
2个回答

邬綵唔惪

use Predis\Client;这个客户端换成swoole那边有连接池的试试

  • 排骨苏 28天前

    有可能是这个原因,我今天特地把代码该删的删了,然后再试,还会出现变量被污染,当并发高时候fd1 发送到fd2上去了,但是当我把进程改成1 ,就没事了,话说不是有进程隔离的吗,怎么还会有这种情况出现呢

  • 邬綵唔惪 28天前

    删后的代码发出来看看

  • 排骨苏 28天前

    大佬 ,删除后的代码已经贴上去了 ,问题帮我看看,就是第17行,我不知道这个为什么会影响这么大

  • 排骨苏 28天前

    $this->clearRedisCache(); 这一行

  • 邬綵唔惪 27天前

    试了下,父进程执行到new Client,不会建立链接,但$this->clearRedisCache();这个在父进程中会建立链接,导致后面建立的4个子进程复用了父进程的这个链接导致数据污染,如果去掉这个$this->clearRedisCache();,父进程就没有建立链接,每个子进程接收请求的时候才会建立链接,所以数据不会污染 。

大古

需要在WorkerStart里面初始化Redis连接。

$this->server->on('WorkerStart', function (\Swoole\Server $serv) {
    //TODO 初始化Redis连接
});
  • 大古 28天前
    $server = new Swoole\Server('0.0.0.0', 9502);
    
    //必须在onWorkerStart回调中创建redis/mysql连接
    $server->on('workerstart', function($server, $id) {
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        $server->redis = $redis;
    });
    
    $server->on('receive', function (Swoole\Server $server, $fd, $reactor_id, $data) {    
        $value = $server->redis->get("key");
        $server->send($fd, "Swoole: ".$value);
    });
    
    $server->start();
  • 排骨苏 28天前

    还有这种情况啊,我现在改成单进程了,问题解决了,先这样吧,谢谢了,还是这个论坛活跃些,那边 我的帖子还没过审核

🔝