补充一下,前一段时间因为项目中使用keys导致redis卡死,于是在网上搜索解决方法,基本都是使用scan替代keys命令。然后就上线了scan替代keys。。。然后就踩坑了

结果就是redis的cpu飙升,scan操作同样是扫描表操作,会导致cpu飙高,也同样会阻塞请求

scan和keys的区别在于:keys是全表扫描,会导致阻塞,scan类似分页扫描表,通过游标接着往下扫,所以扫的数据比keys少,

相对于keys比较不容易阻塞,但不代表它不会导致阻塞,如果key数量很多,快速连续调用 SCAN,那么对 CPU 的压力会增大,会造成cpu飙升,有性能问题。

所以keys和scan在生产环境都应该禁用,最后的解决方法还是记录缓存的key,然后直接获取key。

测试环境之所以redis使用keys和scan命令没有性能问题,是因为测试环境的的key数量很少,就算整体扫描也不会有问题,所以就是:

1、缓存key时设定过期时间,这样redis就不会有大量的未失效的key

2、线上禁止使用keys和scan

下面的就不用看了 总之keys不能用,scan也不能用!!!!!!

PHP实现 Redis使用SCAN 和 SSCAN

因为大家都知道的原因(线上禁止使用keys smembers 命令

所以用了scan 和 sscan命令获取redis中的值

取出来的数据记得去重


//使用scan匹配all key
    function scanAllForMatch($pattern, $cursor=null, $results=[]) {

        if ($cursor === "0") {
            return $results;
        }

        if ($cursor === null) {
            $cursor = "0";
        }

        $redis = Cache::getRedis();
        list($cursor, $result) = $redis->scan($cursor, 'match', $pattern, 'count', 1000);

        $results = array_merge($results, $result);

        return scanAllForMatch($pattern, $cursor, $results);

    }

//使用sscan匹配 set 集合中 all key
    function setScanAllForMatch($key, $pattern='*', $cursor=null, $count = 3000, $results=[]) {

        if ($cursor === "0") {
            return $results;
        }

        if ($cursor === null) {
            $cursor = "0";
        }

        $redis = Cache::getRedis();
        list($cursor, $result) = $redis->sscan($key, $cursor, 'match', $pattern, 'count', $count);

        $results = array_merge($results, $result);


        return setScanAllForMatch($key, $pattern, $cursor, $count, $results);

    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐