Redis Cluster 字段模糊匹配及删除


Posted in Redis onMay 27, 2021

Questions

在数据库内我们可以通过like关键字、%、*或者REGEX关键字进行模糊匹配。而在Redis内我们如何进行模糊匹配呢?集群情况Redis Cluster的情况是否和单机一致呢?前段时间我对于这个议题进行了调查和研究。

单节点的情况

Jedis
参考stackoverflow上的解答,在Java内使用Jedis主要有如下2中写法:

### 方法1
Set<String> keys = jedis.keys(pattern);
for (String key : keys) {
    jedis.del(key);
} 

### 方法2
Jedis jedis = new Jedis("127.0.0.1");
ScanParams scanParams = new ScanParams();
scanParams.match("prifix*");
scanParams.count(1000);
ScanResult<String> result = jedis.scan(0,scanParams);
result.getResult().forEach(key -> {
    jedis.del(key);
});

### 注意scan方法由于某些bug在2.9版本内scan(int,ScanParams)改为了scan(String,ScanParams)。由于cursor的位数,方法有些调整。

方法1,通过keys命令先寻找到所有符合的key,然后把它们删除;
方法2,通过scan命令扫描所有符合的key,然后把它们删除。
注意: Redis饰单线程模式,全局扫描的话有可能会导致Redis在一段时间内的卡顿情况发生。

Redis-cli

redis-cli keys 1.cn*|xargs redis-cli del

Redis Cluster情况

在Redis Cluster情况与单节点多情况完全不太一样。

  • 首先,Redis Cluster是将整个Redis 的hash槽分布在三台机器上,要想一下全部扫描出来,显然是不太现实的。
  • Redis内提供Hash-Tag,将相类似的键放在一台机器上。可以通过Hash-Tag进行扫描,可以剪短时间消耗。
  • 最后需要考虑,主从集群节点的情况。

Hash-Tag

Hash-Tag 是用一个花括号将主要的Hash判断部分扩起来,例如{hello1}key1、{hello1}key2。一般Hash-tag一致的情况,键会存储在集群的同一台机器上。在Jedis 2.9版本提供了这样的扫描方法。
(PS . rediscluster是没有keys方法的)

public static void deleteRedisKeyStartWith(String redisKeyStartWith) {
        try{
            jedisCluster.getClusterNodes();

            ScanParams scanParams = new ScanParams();
//          scanParams.match("{123}keys*");

//          scanParams.count(1000);
            ScanResult<String> result = jedisCluster.scan("0", scanParams);
            result.getResult().forEach(key -> {
                jedisCluster.del(key);
            });
//          jedisCluster.del(wrapperKey(redisKeyStartWith)+".*");
            log.info("success deleted redisKeyStartWith:{}", redisKeyStartWith);
        }finally{
        }
    }

土办法 分别扫描各个hash槽

public static void deleteRedisKeyStartWith(String redisKeyStartWith) {
        try {
            Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();

            for (Map.Entry<String, JedisPool> entry : clusterNodes.entrySet()) {
                Jedis jedis = entry.getValue().getResource();
                // 判断非从节点(因为若主从复制,从节点会跟随主节点的变化而变化)
                if (!jedis.info("replication").contains("role:slave")) {
                    Set<String> keys = jedis.keys(redisKeyStartWith + "*");
                    if (keys.size() > 0) {
                        Map<Integer, List<String>> map = new HashMap<>();
                        for (String key : keys) {
                            // cluster模式执行多key操作的时候,这些key必须在同一个slot上,不然会报:JedisDataException:
                            // CROSSSLOT Keys in request don't hash to the same slot
                            int slot = JedisClusterCRC16.getSlot(key);
                            // 按slot将key分组,相同slot的key一起提交
                            if (map.containsKey(slot)) {
                                map.get(slot).add(key);
                            } else {
                                map.put(slot, Lists.newArrayList(key));
                            }
                        }
                        for (Map.Entry<Integer, List<String>> integerListEntry : map.entrySet()) {
                            jedis.del(integerListEntry.getValue().toArray(new String[integerListEntry.getValue().size()]));
                        }
                    }
                }
            }
            log.info("success deleted redisKeyStartWith:{}", redisKeyStartWith);
        } finally {
        }
    }
### 未使用slot批次提交(有可能效率略差于前者)
//获取jedis连接

         private JedisCluster jedisCluster=JedisClusterUtil.getJedisCluster();

         //@param pattern  获取key的前缀  全是是 * 

 public static TreeSet<String> keys(String pattern){  


       TreeSet<String> keys = new TreeSet<>();  
        //获取所有的节点

               Map<String, JedisPool> clusterNodes = jedisCluster.getClusterNodes();  
       //遍历节点 获取所有符合条件的KEY 

               for(String k : clusterNodes.keySet()){  
           logger.debug("Getting keys from: {}", k);  
           JedisPool jp = clusterNodes.get(k);  
           Jedis connection = jp.getResource();  
           try {  
               keys.addAll(connection.keys(pattern));  
           } catch(Exception e){  
               logger.error("Getting keys error: {}", e);  
           } finally{  
               logger.debug("Connection closed.");  
               connection.close();//用完一定要close这个链接!!!  
           }  
       }  
       logger.debug("Keys gotten!");  
       return keys;  
  }  

          //main方法

 public static void main(String[] args ){
 TreeSet<String> keys=keys("*");

 //遍历key  进行删除  可以用多线程

 for(String key:keys){

                          jedisCluster.del(key);
 System.out.println(key);
 }
 }

Reference

[1]. (码经)如何通过正则匹配删除Redis里的键
[2]. (Stackoverflow)Redis/Jedis - Delete by pattern?
[3]. (JavaDoc)Class JedisCluster
[4]. (csdn)redis cluster 模式如何批量删除指定前缀的key
[5]. redis cluster模式key的模糊删除-java操作
[6]. Jedis实现批量删除redis cluster
[6]. redis del命令支持正则删除(pattern)
[7]. Redis 批量删除Redis的key 正则匹配删除
[8]. (名字挺搞笑-蛋糕店老板)Redis集群下使用Jedis实现keys模糊查询

到此这篇关于Redis Cluster 字段模糊匹配及删除的文章就介绍到这了,更多相关Redis Cluster 字段模糊删除内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Redis 相关文章推荐
解决redis sentinel 频繁主备切换的问题
Apr 12 Redis
详解Redis实现限流的三种方式
Apr 27 Redis
浅谈redis缓存在项目中的使用
May 20 Redis
详解缓存穿透击穿雪崩解决方案
May 28 Redis
Django使用redis配置缓存的方法
Jun 01 Redis
压缩Redis里的字符串大对象操作
Jun 23 Redis
聊一聊Redis与MySQL双写一致性如何保证
Jun 26 Redis
Redis Cluster 集群搭建你会吗
Aug 04 Redis
Jedis操作Redis实现模拟验证码发送功能
Sep 25 Redis
Redis的字符串是如何实现的
Oct 24 Redis
CentOS8.4安装Redis6.2.6的详细过程
Nov 20 Redis
Redis中有序集合的内部实现方式的详细介绍
Mar 16 Redis
redis哨兵常用命令和监控示例详解
May 27 #Redis
Java Socket实现Redis客户端的详细说明
May 26 #Redis
redis实现共同好友的思路详解
详解Redis瘦身指南
May 26 #Redis
Redis高级数据类型Hyperloglog、Bitmap的使用
May 24 #Redis
redis实现排行榜功能
May 24 #Redis
分布式锁为什么要选择Zookeeper而不是Redis?看完这篇你就明白了
May 21 #Redis
You might like
我的论坛源代码(四)
2006/10/09 PHP
php设置静态内容缓存时间的方法
2014/12/01 PHP
yii的CURD操作实例详解
2014/12/04 PHP
PHP将session信息存储到数据库的类实例
2015/03/04 PHP
php实现html标签闭合检测与修复方法
2015/07/09 PHP
Json_decode 解析json字符串为NULL的解决方法(必看)
2017/02/17 PHP
javascript offsetX与layerX区别
2010/03/12 Javascript
EasyUI中的tree用法介绍
2011/11/01 Javascript
JQUERY 设置SELECT选中项代码
2014/02/07 Javascript
jquery中的$(document).ready()使用小结
2014/02/14 Javascript
jquery使用正则表达式验证email地址的方法
2015/01/22 Javascript
基于javascript实现全屏漂浮广告
2016/03/31 Javascript
javascript 定时器工作原理分析
2016/12/03 Javascript
基于jquery实现的鼠标悬停提示案例
2016/12/11 Javascript
深入解析js轮播插件核心代码的实现过程
2017/04/14 Javascript
关于jquery layui弹出层的使用方法
2018/04/21 jQuery
vue translate peoject实现在线翻译功能【新手必看】
2018/06/07 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
2019/09/11 Javascript
vue 解除鼠标的监听事件的方法
2019/11/13 Javascript
一篇不错的Python入门教程
2007/02/08 Python
Python 出现错误TypeError: ‘NoneType’ object is not iterable解决办法
2017/01/12 Python
Python迭代器和生成器定义与用法示例
2018/02/10 Python
Python解析命令行读取参数之argparse模块
2019/07/26 Python
使用已经得到的keras模型识别自己手写的数字方式
2020/06/29 Python
aec加密 php_php aes加密解密类(兼容php5、php7)
2021/03/14 PHP
全球速卖通法国在线交易平台:AliExpress法国
2017/07/07 全球购物
英国浴室洗脸盆购物网站:Click Basin
2018/06/08 全球购物
如何保障Web服务器安全
2014/05/05 面试题
Java语言的优势
2015/01/10 面试题
英语专业毕业生自荐信范文
2013/12/31 职场文书
给学校建议书范文
2014/05/13 职场文书
孝敬父母的活动方案
2014/08/31 职场文书
房屋买卖委托书格式范本格式
2014/10/13 职场文书
三方股东合作协议书
2014/10/28 职场文书
个人总结与自我评价
2015/02/14 职场文书
mysql中关键词exists的用法实例详解
2022/06/10 MySQL