• Redis删除特定前缀key的优雅实现


    还在用keys命令模糊匹配删除数据吗?这就是一颗随时爆炸的炸弹!

    Redis中没有批量删除特定前缀key的指令,但我们往往需要根据前缀来删除,那么究竟该怎么做呢?可能你一通搜索后会得到下边的答案

    redis-cli --raw keys "ops-coffee-*" | xargs redis-cli del
    

    直接在linux下通过redis的keys命令匹配到所有的key,然后调用系统命令xargs来删除,看似非常完美,实则风险巨大

    因为Redis的单线程服务模式,命令keys会阻塞正常的业务请求,如果你一次keys匹配的数量过多或者在del的时候遇到大key,都会直接导致业务的不可用,甚至造成redis宕机的风险

    所以我们在生产环境中应当避免使用上边的方法,那有什么优雅的方法来解决呢?SCAN!

    SCAN介绍及使用

    Redis从2.8版本开始支持scan命令,SCAN命令的基本用法如下:

    SCAN cursor [MATCH pattern] [COUNT count]
    

    cursor: 游标,SCAN命令是一个基于游标的迭代器,SCAN命令每次被调用之后,都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为SCAN命令的游标参数,以此来延续之前的迭代过程,直到服务器向用户返回值为0的游标时,一次完整的遍历过程就结束了

    MATCH: 匹配规则,例如遍历以ops-coffee-开头的所有key可以写成ops-coffee-*,中间包含-coffee-的可以写成*-coffee-*

    COUNT: COUNT选项的作用就是让用户告知迭代命令,在每次迭代中应该从数据集里返回多少元素,COUNT只是对增量式迭代命令的一种提示,并不代表真正返回的数量,例如你COUNT设置为2有可能会返回3个元素,但返回的元素数据会与COUNT设置的正相关,COUNT的默认值是10

    以下是一个SCAN命令的迭代过程示例:

    127.0.0.1:6379> scan 0 MATCH ops-coffee-* 
    1) "38"
    2)  1) "ops-coffee-25"
        2) "ops-coffee-19"
        3) "ops-coffee-29"
        4) "ops-coffee-10"
        5) "ops-coffee-23"
        6) "ops-coffee-5"
        7) "ops-coffee-14"
        8) "ops-coffee-16"
        9) "ops-coffee-11"
       10) "ops-coffee-15"
       11) "ops-coffee-7"
       12) "ops-coffee-1"
    127.0.0.1:6379> scan 38 MATCH ops-coffee-* COUNT 1000
    1) "0"
    2)  1) "ops-coffee-13"
        2) "ops-coffee-9"
        3) "ops-coffee-21"
        4) "ops-coffee-6"
        5) "ops-coffee-30"
        6) "ops-coffee-20"
        7) "ops-coffee-2"
        8) "ops-coffee-12"
        9) "ops-coffee-28"
       10) "ops-coffee-3"
       11) "ops-coffee-26"
       12) "ops-coffee-4"
       13) "ops-coffee-31"
       14) "ops-coffee-8"
       15) "ops-coffee-22"
       16) "ops-coffee-27"
       17) "ops-coffee-18"
       18) "ops-coffee-24"
       19) "ops-coffee-17"
    

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

    上面这个例子的意思是扫描所有前缀为ops-coffee-的key

    第一次迭代使用0作为游标,表示开始一次新的迭代,同时使用了MATCH匹配前缀为ops-coffee-的key,返回了游标值38以及遍历到的数据

    第二次迭代使用的是第一次迭代时返回的游标,也即是命令回复第一个元素的值38,同时通过将COUNT选项的参数设置为1000,强制命令为本次迭代扫描更多元素

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

    KEYS命令的时间复杂度为O(n),而SCAN命令会将遍历操作分解成m次时间复杂度为O(1)的操作来执行,从而解决使用keys命令遍历大量数据而导致服务器阻塞的情况,使用下边的指令可以达到优雅删除的目的:

    redis-cli --scan --pattern "ops-coffee-*" | xargs -L 2000 redis-cli del
    

    其中xargs -L指令表示xargs一次读取的行数,也就是每次删除的key数量,一次读取太多xargs会报错

    其他几种数据结构的优雅删除

    类似的SCAN命令,对于Redis不同的数据类型还有另外几个SSCANHSCANZSCAN,使用方法类似:

    > sscan ops-coffee 0 MATCH v1*
    1) "7"
    2) 1) "v15"
       2) "v13"
       3) "v12"
       4) "v10"
       5) "v14"
       6) "v1"
    

    与SCAN命令不同的是这几个命令需要多加一个key的参数,例如上边的ops-coffee

    对于一个大的set key,借助sscan使用下边的代码可以实现优雅的批量删除:

    import redis
    
    def del_big_set_key(key_name):
        r = redis.StrictRedis(host='localhost', port=6379)
        
        # count表示每次删除的元素数量,这里每次删除300元素
        for key in r.sscan_iter(name=key_name, count=300):
            r.srem(key_name, key)
    
    del_big_set_key('ops-coffee')
    

    对于一个大的hash key,则可借助hscan使用下边的代码实现优雅的删除:

  • 相关阅读:
    Java Thread系列(七)死锁
    Java Thread系列(六)volatile
    Java Thread系列(四)线程通信
    Java Thread系列(三)线程安全
    Java Thread系列(二)线程状态
    Java Thread系列(一)线程创建
    设计模式之美
    设计模式之美目录
    设计模式之美
    Executor(二)ThreadPoolExecutor、ScheduledThreadPoolExecutor 及 Executors 工厂类
  • 原文地址:https://www.cnblogs.com/exmyth/p/15841098.html
Copyright © 2020-2023  润新知