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存储数据类型及存取值方法
May 08 Redis
Redis 配置文件重要属性的具体使用
May 20 Redis
详解缓存穿透击穿雪崩解决方案
May 28 Redis
解析Redis Cluster原理
Jun 21 Redis
Redis的字符串是如何实现的
Oct 24 Redis
分布式架构Redis中有哪些数据结构及底层实现原理
Mar 13 Redis
redis数据一致性的实现示例
Mar 18 Redis
Redis 操作多个数据库的配置的方法实现
Mar 23 Redis
Redis实现订单过期删除的方法步骤
Jun 05 Redis
基于redis+lua进行限流的方法
Jul 23 Redis
Redis实战之Lettuce的使用技巧详解
Dec 24 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
php递归删除目录下的文件但保留的实例分享
2014/05/10 PHP
PHP中通过fopen()函数访问远程文件示例
2014/11/18 PHP
php实现粘贴截图并完成上传功能
2015/05/17 PHP
PHP使用strtotime获取上个月、下个月、本月的日期
2015/12/30 PHP
jQuery EasyUI中对表格进行编辑的实现代码
2010/06/10 Javascript
Javascript匿名函数的一种应用 代码封装
2010/06/27 Javascript
jQuery最佳实践完整篇
2011/08/20 Javascript
JavaScript动态提示输入框输入字数的方法
2015/07/27 Javascript
基于bootstrap3和jquery的分页插件
2015/07/31 Javascript
值得分享和收藏的Bootstrap学习教程
2016/05/12 Javascript
JS实现关闭当前页而不弹出提示框的方法
2016/06/22 Javascript
js获取元素下的第一级子元素的方法(推荐)
2017/03/05 Javascript
认识jQuery的Promise的具体使用方法
2017/10/10 jQuery
Vue+jquery实现表格指定列的文字收缩的示例代码
2018/01/09 jQuery
解决Vue不能检测数组或对象变动的问题
2018/02/24 Javascript
JavaScript如何对图片进行黑白化
2018/04/10 Javascript
VueCli3.0中集成MockApi的方法示例
2019/07/05 Javascript
vue源码中的检测方法的实现
2019/09/26 Javascript
vue封装自定义指令之动态显示title操作(溢出显示,不溢出不显示)
2020/11/12 Javascript
Python通过解析网页实现看报程序的方法
2014/08/04 Python
Python中使用PyQt把网页转换成PDF操作代码实例
2015/04/23 Python
利用python生成一个导出数据库的bat脚本文件的方法
2016/12/30 Python
Python实现求两个csv文件交集的方法
2017/09/06 Python
numpy.std() 计算矩阵标准差的方法
2018/07/11 Python
使用matplotlib中scatter方法画散点图
2019/03/19 Python
pyqt5 使用label控件实时显示时间的实例
2019/06/14 Python
使用pyshp包进行shapefile文件修改的例子
2019/12/06 Python
tensorflow实现读取模型中保存的值 tf.train.NewCheckpointReader
2020/02/10 Python
Python获取excel内容及相关操作代码实例
2020/08/10 Python
HTML5里autofocus自动聚焦属性使用介绍
2016/06/22 HTML / CSS
运动会通讯稿150字
2014/02/15 职场文书
服务型党组织建设典型材料
2014/05/07 职场文书
会计求职信
2014/05/29 职场文书
小学安全工作汇报材料
2014/08/19 职场文书
JVM钩子函数的使用场景详解
2021/08/23 Java/Android
Python之matplotlib绘制折线图
2022/04/13 Python