百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

Redis 中 keys 命令带来的线上性能问题,怎么解决?

wptr33 2025-03-10 21:10 11 浏览

推荐学习

起因

下午接到运维反馈,生产redis有个执行keys的命令请求太慢了,要两三秒才能响应
涉及命令如下:
KEYS ttl_600::findHeadFootData-15349232-*-head

什么是keys命令?

keys官方文档 http://www.redis.cn/commands/keys.html

KEYS pattern

查找所有符合给定模式pattern(正则表达式)的 key 。
时间复杂度为O(N),N为数据库里面key的数量。
例如,Redis在一个有1百万个key的数据库里面执行一次查询需要的时间是40毫秒 。

警告: KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 KEYS, 你最好还是用 Redis 的集合结构 SETS 来代替。

支持的正则表达模式:

h?llo 匹配 hello, hallo 和 hxllo
h*llo 匹配 hllo 和 heeeello
h[ae]llo 匹配 hello 和 hallo, 但是不匹配 hillo
h[^e]llo 匹配 hallo, hbllo, … 但是不匹配 hello
h[a-b]llo 匹配 hallo 和 hbllo

返回值

所有符合条件的key

Redis提供的所有API操作,相对于服务端方面都是one by one执行的,命令是一个接着一个执行的,不存在并行执行的情况。

虽说REDIS执行KEYS命令很快,但是由于生产环境上有近六百万KEY,以至于KEYS命令需要两三秒,这两三秒就会导致其它命令阻塞着,这在生产中是灾难性的;

redis提供了一个scan的命令

scan命令官方文档 http://www.redis.cn/commands/scan.html

SCAN cursor [MATCH pattern] [COUNT count]

cursor 游标
[MATCH pattern] 需要正则匹配的字符串
count 扫描的key的个数

SCAN 命令及其相关的 SSCAN, HSCAN 和 ZSCAN 命令都用于增量迭代一个集合元素。

  • SCAN 命令用于迭代当前数据库中的key集合。
  • SSCAN 命令用于迭代SET集合中的元素。
  • HSCAN 命令用于迭代Hash类型中的键值对。
  • ZSCAN 命令用于迭代SortSet集合中的元素和元素对应的分值

栗子

redis 127.0.0.1:6379> scan 0 MATCH *11*
1) "288"
2) 1) "key:911"
redis 127.0.0.1:6379> scan 288 MATCH *11*
1) "224"
2) (empty list or set)
redis 127.0.0.1:6379> scan 224 MATCH *11*
1) "80"
2) (empty list or set)
redis 127.0.0.1:6379> scan 80 MATCH *11*
1) "176"
2) (empty list or set)
redis 127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
1) "0"
2)  1) "key:611"
    2) "key:711"
    3) "key:118"
    4) "key:117"
    5) "key:311"
    6) "key:112"
    7) "key:111"
    8) "key:110"
    9) "key:113"
   10) "key:211"
   11) "key:411"
   12) "key:115"
   13) "key:116"
   14) "key:114"
   15) "key:119"
   16) "key:811"
   17) "key:511"
   18) "key:11"
redis 127.0.0.1:6379>

在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。第二次迭代使用的是第一次迭代时返回的游标 17 ,作为新的迭代参数 。

显而易见,SCAN命令的返回值 是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了所有被迭代的元素。

在第二次调用 SCAN 命令时, 命令返回了游标 0 , 这表示迭代已经结束, 整个数据集已经被完整遍历过了。

以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0 , 我们称这个过程为一次完整遍历。

java代码实践一下

上面已经说了keys和scan的命令了,下面用jedis来进行实践一下,在本地编码自测:


            redis.clients
            jedis
            2.9.3
        
        
        
            cn.hutool
            hutool-all
            5.6.5
        
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.thread.ExecutorBuilder;
import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanParams;
import redis.clients.jedis.ScanResult;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class JedisService {


    public static Jedis getJedis(){
        return new Jedis("localhost",6379,1000000000);
    }

    volatile static Boolean testCycleSetExitFlag = Boolean.FALSE;
    /**
     * 初始化数据到redis
     */
    public static void initData() throws InterruptedException {
        TimeInterval timeInterval = DateUtil.timer();
        log.info("initData start");
        getJedis().set("111CCCCCCCCCCCCCC1111","1");//先把查找的key设置进去
        //初始化数据个数
        AtomicInteger count = new AtomicInteger(10000*2000);

        //开100个客户端去执行set命令
        Integer totalClientNum = 100;

        ExecutorService executor = ExecutorBuilder.create()
                .setCorePoolSize(10)
                .setMaxPoolSize(50)
                .setWorkQueue(new LinkedBlockingQueue<>(1024))
                .build();

        CountDownLatch countDownLatch = new CountDownLatch(totalClientNum);
        for (int i = 0; i < totalclientnum i executor.submit->{
                Jedis jedis = getJedis();
                while (true){
                    Integer crrentCount  = count.decrementAndGet();
                    if(crrentCount<=0){ break ifcrrentcount10000='=0){' log.info key: :crrentcounttimeinterval.interval jedis.setuuid.randomuuid.tostring.replaceall-1 countdownlatch.countdown countdownlatch.await log.infoinitdata end timeinterval.interval executor.shutdown public static void mainstring args throws exception jedis jedis='getJedis();' system.out.println: jedis.ping initdata log.inforediskeyjedis.dbsize string pattern='*CCCCCCCCCCCCCC*' keysscan keyspattern scanpattern log.info------------------------------- :keysscan new thread->{
            testCycleSet("1111","11");
        }).start();

        Thread.sleep(2000);//休眠两秒

        keys(pattern);
        scan(pattern);
        testCycleSetExitFlag = true;
        log.info("----------------我还是一条分割线---------------");
        //下面测试一下设置不同count的效率
        scan(pattern,100);
        scan(pattern,200);
        scan(pattern,300);
        scan(pattern,400);
        scan(pattern,500);
        scan(pattern,1000);
        scan(pattern,2000);
        scan(pattern,5000);
        scan(pattern,10000);
    }
    //循环设置一个key值 测试用的
    public static void testCycleSet(String key,String value){
        Jedis jedis = getJedis();
        while (true){
            if(testCycleSetExitFlag){
                break;
            }
            Long startTime = System.currentTimeMillis();
            log.info("testCycleSet key:{} value:{} start",key,value);
            try {
                jedis.set(key,value);
            }catch (Exception e){
                log.error("testCycleSet",e);
            }

            log.info("testCycleSet key:{} value:{} end 耗时:{}毫秒",key,value,(System.currentTimeMillis() - startTime));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    public static Set keys(String pattern){
        Long startTime = System.currentTimeMillis();
        log.info("jedis keys start 匹配的key:{}",pattern);
        Set keySet = getJedis().keys(pattern);
        log.info("jedis keys end   匹配的key:{}  结果集大小:{}  耗时:{}毫秒 ",pattern,keySet.size(),(System.currentTimeMillis() - startTime));
        return keySet;

    }
    public static Set scan(String pattern){
        return scan(pattern,300);
    }
    public static Set scan(String pattern,int count){
        Long startTime = System.currentTimeMillis();
        Jedis jedis = getJedis();
        log.info("jedis scan start 匹配的key:{} 每次遍历{}个key",pattern,count);
        String index = "0";
        Set keySet = new HashSet();//匹配到的结果集
        Integer scanNum = 0;
        try {
            ScanParams params = new ScanParams();
            params.match(pattern);
            params.count(count);
            while (true){
                ScanResult scanResult = jedis.scan(index,params);
                index = scanResult.getStringCursor();//下标重新赋值
                List result = scanResult.getResult();//扫描到的key值
                if(CollUtil.isNotEmpty(result)){
                    keySet.addAll(result);//扫描到的key放到Set
                }

                if("0".equals(index)){
                    break;
                }
                scanNum++;
            }
        } catch (Exception e) {
            log.info("redis异常" + e.getMessage());
        }
        log.info("jedis scan end   匹配的key:{} 每次遍历{}个key  scan执行了:{}次  结果集大小:{}  总耗时:{}毫秒",pattern,count,scanNum,keySet.size(),(System.currentTimeMillis() - startTime));
        return keySet;
    }
}

服务正在运行: PONG
00:34:30.776 [main] INFO com.test.JedisService - 现在redis服务有25000000个key
00:34:30.780 [main] INFO com.test.JedisService - jedis keys start 匹配的key:*CCCCCCCCCCCCCC*
00:34:41.493 [main] INFO com.test.JedisService - jedis keys end   匹配的key:*CCCCCCCCCCCCCC*  结果集大小:1  耗时:10713毫秒 
00:34:41.493 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key
00:35:09.307 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key  scan执行了:83231次  结果集大小:1  总耗时:27814毫秒
00:35:09.307 [main] INFO com.test.JedisService - ----------------我是一条分割线---------------
00:35:09.352 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:09.355 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:3毫秒
00:35:10.358 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:10.359 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:11.356 [main] INFO com.test.JedisService - jedis keys start 匹配的key:*CCCCCCCCCCCCCC*
00:35:11.360 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:22.724 [main] INFO com.test.JedisService - jedis keys end   匹配的key:*CCCCCCCCCCCCCC*  结果集大小:1  耗时:11368毫秒 
00:35:22.725 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:11365毫秒
00:35:22.725 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key
00:35:23.728 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:23.729 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:24.734 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:24.735 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:25.739 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:25.740 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:26.744 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:26.744 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:27.747 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:27.747 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:28.751 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:28.751 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:29.755 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:29.757 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:30.761 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:30.761 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:31.766 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:31.767 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:32.767 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:32.768 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:33.772 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:33.773 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:34.776 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:34.776 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:35.779 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:35.780 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:36.784 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:36.785 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:37.788 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:37.788 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:38.793 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:38.793 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:39.796 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:39.796 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:40.797 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:40.797 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:41.800 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:41.801 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:1毫秒
00:35:42.806 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:42.806 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:43.811 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:43.811 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:44.816 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:44.816 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:45.821 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:45.821 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:46.826 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:46.826 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:47.830 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:47.830 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:48.835 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:48.835 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:49.840 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:49.840 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:50.845 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 start
00:35:50.845 [Thread-0] INFO com.test.JedisService - testCycleSet key:1111 value:11 end 耗时:0毫秒
00:35:51.225 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key  scan执行了:83231次  结果集大小:1  总耗时:28500毫秒
00:35:51.225 [main] INFO com.test.JedisService - ----------------我还是一条分割线---------------
00:35:51.226 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历100个key
00:36:24.747 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历100个key  scan执行了:249070次  结果集大小:1  总耗时:33522毫秒
00:36:24.747 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历200个key
00:36:54.580 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历200个key  scan执行了:124768次  结果集大小:1  总耗时:29833毫秒
00:36:54.580 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key
00:37:23.674 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key  scan执行了:83231次  结果集大小:1  总耗时:29094毫秒
00:37:23.674 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历400个key
00:37:56.541 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历400个key  scan执行了:62441次  结果集大小:1  总耗时:32867毫秒
00:37:56.542 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历500个key
00:38:28.282 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历500个key  scan执行了:49962次  结果集大小:1  总耗时:31740毫秒
00:38:28.282 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历1000个key
00:39:00.211 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历1000个key  scan执行了:24990次  结果集大小:1  总耗时:31929毫秒
00:39:00.211 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历2000个key
00:39:31.754 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历2000个key  scan执行了:12497次  结果集大小:1  总耗时:31543毫秒
00:39:31.754 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历5000个key
00:40:03.548 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历5000个key  scan执行了:4999次  结果集大小:1  总耗时:31794毫秒
00:40:03.548 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历10000个key
00:40:36.329 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历10000个key  scan执行了:2499次  结果集大小:1  总耗时:32781毫秒

这是500万key  不同count执行的结果

服务正在运行: PONG
01:23:29.449 [main] INFO com.test.JedisService - 现在redis服务有5000000个key
01:23:29.452 [main] INFO com.test.JedisService - jedis keys start 匹配的key:*CCCCCCCCCCCCCC*
01:23:31.172 [main] INFO com.test.JedisService - jedis keys end   匹配的key:*CCCCCCCCCCCCCC*  结果集大小:1  耗时:1720毫秒 
01:23:31.172 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key
01:23:36.587 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key  scan执行了:16649次  结果集大小:1  总耗时:5415毫秒
01:23:36.587 [main] INFO com.test.JedisService - ----------------我还是一条分割线---------------
01:23:36.587 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历100个key
01:23:43.030 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历100个key  scan执行了:49851次  结果集大小:1  总耗时:6443毫秒
01:23:43.031 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历200个key
01:23:48.801 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历200个key  scan执行了:24963次  结果集大小:1  总耗时:5769毫秒
01:23:48.801 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key
01:23:54.355 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历300个key  scan执行了:16649次  结果集大小:1  总耗时:5554毫秒
01:23:54.355 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历400个key
01:23:59.711 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历400个key  scan执行了:12490次  结果集大小:1  总耗时:5356毫秒
01:23:59.711 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历500个key
01:24:05.016 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历500个key  scan执行了:9994次  结果集大小:1  总耗时:5305毫秒
01:24:05.016 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历1000个key
01:24:11.594 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历1000个key  scan执行了:4998次  结果集大小:1  总耗时:6578毫秒
01:24:11.594 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历2000个key
01:24:18.137 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历2000个key  scan执行了:2499次  结果集大小:1  总耗时:6543毫秒
01:24:18.137 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历5000个key
01:24:24.655 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历5000个key  scan执行了:999次  结果集大小:1  总耗时:6518毫秒
01:24:24.655 [main] INFO com.test.JedisService - jedis scan start 匹配的key:*CCCCCCCCCCCCCC* 每次遍历10000个key
01:24:31.257 [main] INFO com.test.JedisService - jedis scan end   匹配的key:*CCCCCCCCCCCCCC* 每次遍历10000个key  scan执行了:499次  结果集大小:1  总耗时:6602毫秒

小结

keys和scan是否会阻塞其他命令?

看日志显而易见
keys命令会阻塞其它命令
scan命令则相当于分批次遍历全部key,遍历一部分key后把,所在位置(游标)返回给客户端,下次客户端拿着上次返回的游标,继续执行scan命令往后遍历,直至遍历完成,所以不会长时间阻塞redis。

scan命令count设置多大合适

我们redis服务器上面key的数量通常在五百万到七百万这个范围

经过上面测试:

scan命令 count设置成300
两千五百万的key会执行八万次的scan,耗时30秒就能遍历完,每秒大概执行3000次
五百万的key 会执行16649次的scan,总耗时6秒,每秒大概执行3000次
而生产上redis的的qps很轻松地扛住10w,所以设置300会比较合适。

最终

本地自测通过,发到灰度环境,测试反馈业务无异常,发到生产观察了几天运维也没不良的反馈,问题解决~

原文链接:
https://www.cnblogs.com/x-kq/p/14782035.html

相关推荐

每天一个编程技巧!掌握这7个神技,代码效率飙升200%

“同事6点下班,你却为改BUG加班到凌晨?不是你不努力,而是没掌握‘偷懒’的艺术!本文揭秘谷歌工程师私藏的7个编程神技,每天1分钟,让你的代码从‘能用’变‘逆天’。文末附《Python高效代码模板》,...

Git重置到某个历史节点(Sourcetree工具)

前言Sourcetree回滚提交和重置当前分支到此次提交的区别?回滚提交是指将改动的代码提交到本地仓库,但未推送到远端仓库的时候。...

git工作区、暂存区、本地仓库、远程仓库的区别和联系

很多程序员天天写代码,提交代码,拉取代码,对git操作非常熟练,但是对git的原理并不甚了解,借助豆包AI,写个文章总结一下。Git的四个核心区域(工作区、暂存区、本地仓库、远程仓库)是版本控制的核...

解锁人生新剧本的密钥:学会让往事退场

开篇:敦煌莫高窟的千年启示在莫高窟321窟的《降魔变》壁画前,讲解员指着斑驳色彩说:"画师刻意保留了历代修补痕迹,因为真正的传承不是定格,而是流动。"就像我们的人生剧本,精彩章节永远...

Reset local repository branch to be just like remote repository HEAD

技术背景在使用Git进行版本控制时,有时会遇到本地分支与远程分支不一致的情况。可能是因为误操作、多人协作时远程分支被更新等原因。这时就需要将本地分支重置为与远程分支的...

Git恢复至之前版本(git恢复到pull之前的版本)

让程序回到提交前的样子:两种解决方法:回退(reset)、反做(revert)方法一:gitreset...

如何将文件重置或回退到特定版本(怎么让文件回到初始状态)

技术背景在使用Git进行版本控制时,经常会遇到需要将文件回退到特定版本的情况。可能是因为当前版本出现了错误,或者想要恢复到之前某个稳定的版本。Git提供了多种方式来实现这一需求。...

git如何正确回滚代码(git命令回滚代码)

方法一,删除远程分支再提交①首先两步保证当前工作区是干净的,并且和远程分支代码一致$gitcocurrentBranch$gitpullorigincurrentBranch$gi...

[git]撤销的相关命令:reset、revert、checkout

基本概念如果不清晰上面的四个概念,请查看廖老师的git教程这里我多说几句:最开始我使用git的时候,我并不明白我为什么写完代码要用git的一些列指令把我的修改存起来。后来用多了,也就明白了为什么。gi...

利用shell脚本将Mysql错误日志保存到数据库中

说明:利用shell脚本将MYSQL的错误日志提取并保存到数据库中步骤:1)创建数据库,创建表CreatedatabaseMysqlCenter;UseMysqlCenter;CREATET...

MySQL 9.3 引入增强的JavaScript支持

MySQL,这一广泛采用的开源关系型数据库管理系统(RDBMS),发布了其9.x系列的第三个更新版本——9.3版,带来了多项新功能。...

python 连接 mysql 数据库(python连接MySQL数据库案例)

用PyMySQL包来连接Python和MySQL。在使用前需要先通过pip来安装PyMySQL包:在windows系统中打开cmd,输入pipinstallPyMySQL ...

mysql导入导出命令(mysql 导入命令)

mysql导入导出命令mysqldump命令的输入是在bin目录下.1.导出整个数据库  mysqldump-u用户名-p数据库名>导出的文件名  mysqldump-uw...

MySQL-SQL介绍(mysql sqlyog)

介绍结构化查询语言是高级的非过程化编程语言,允许用户在高层数据结构上工作。它不要求用户指定对数据的存放方法,也不需要用户了解具体的数据存放方式,所以具有完全不同底层结构的不同数据库系统,可以使用相同...

MySQL 误删除数据恢复全攻略:基于 Binlog 的实战指南

在MySQL的世界里,二进制日志(Binlog)就是我们的"时光机"。它默默记录着数据库的每一个重要变更,就像一位忠实的史官,为我们在数据灾难中提供最后的救命稻草。本文将带您深入掌握如...