【😁已解决😁】关于webman的swoole中session存redis的问题【😁已解决😁】

青鱼

问题描述

如果session用redis的话在swoole环境中,只要并发上来就报错。

我用的ab -n10000 -c100 测试的

但是默认的是文件保存,就没一点问题。
感觉是连接池的问题,但是没找到关于session方面对于redis的文档和文章

有没有大佬讲解一下这是为啥🤔🤔🤔🤔🤔🤔
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖

昨天提问之后,大佬给了个方案。但是作为新手的俺有点不咋会。但是我能懂是啥意思。

然后我就按照这个思路去鞭打我的Ai牛马。。。。。

然后我彻底明白了,因为默认的RedisSessionHandler没有复用webman/redis

然后ai牛马给我个解决方案是自己写一个redis处理器给session用

然后就有了下面的代码⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇

<?php
declare(strict_types=1);
namespace app\support\Session;

use Illuminate\Redis\Connections\PhpRedisConnection;
use RuntimeException;
use Throwable;
use support\Redis as UseRedis;
use Workerman\Protocols\Http\Session;

class RedisSessionHandler implements \Workerman\Protocols\Http\Session\SessionHandlerInterface
{
    protected array $config;
    protected string $sessionPrefix;

    public function __construct(array $config)
    {
        // 检查 Redis 扩展
        if (false === extension_loaded('redis')) {
            throw new RuntimeException('Please install redis extension.');
        }

        //初始化配置:指定用 Session 专属连接池
        $this->config = $config + [
            'connection' => 'session', 
            'prefix'     => 'webman_session:',
        ];

        $this->sessionPrefix = $this->config['prefix'];
    }

    /**
     * 每次操作都重新获取 Redis 连接
     * 避免协程间连接竞争
     */
    protected function getRedis(): PhpRedisConnection
    {
        return UseRedis::connection($this->config['connection']);
    }

    // ------------------- 修改所有方法,使用 getRedis() 获取连接 -------------------
    public function open(string $savePath, string $name): bool
    {
        return true;
    }

    public function read(string $sessionId): string|false
    {
        try {
            $redis = $this->getRedis(); // 每次操作获取新连接
            $key = $this->sessionPrefix . $sessionId;
            $data = $redis->get($key);
            return $data ?: '';
        } catch (Throwable $e) {
            throw $e;
        }
    }

    public function write(string $sessionId, string $sessionData): bool
    {
        $redis = $this->getRedis(); // 每次操作获取新连接
        $key = $this->sessionPrefix . $sessionId;
        return true === $redis->setex($key, Session::$lifetime, $sessionData);
    }

    public function updateTimestamp(string $sessionId, string $data = ""): bool
    {
        $redis = $this->getRedis(); // 每次操作获取新连接
        $key = $this->sessionPrefix . $sessionId;
        return true === $redis->expire($key, Session::$lifetime);
    }

    public function destroy(string $sessionId): bool
    {
        $redis = $this->getRedis(); // 每次操作获取新连接
        $key = $this->sessionPrefix . $sessionId;
        $redis->del($key);
        return true;
    }

    public function close(): bool
    {
        return true;
    }

    public function gc(int $maxLifetime): bool
    {
        return true;
    }
}

然后修改config/redis.php增加一个session的专属连接配置

然后再修改config/session.php把处理器改成这个就行

结论:目前我测试的时候没一点问题,也木有出现抢socket的导致swoole报错的问题了😏😏😏

不过作为新人,我还是必须要请教一下各位大佬。这样的做法可不可行?或者大佬有啥其他更好的方法呢😆😆😆

➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖
➖➖➖➖➖➖➖➖➖以上代码已没啥用,仅供学习➖➖➖➖➖➖➖➖➖➖➖➖➖➖
➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖

2025.10.13

昨天更新了workerman5.1.4
这个问题解决了。再也不用自己单独写一个处理了🎉🎉🎉🎉🎉🎉

424 1 1
1个回答

hiwork

workermanV5.1.4添加了redis连接池功能 升级下即可 composer require -W workerman/workerman:~5.1

🔝