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 26 Redis
详解Redis集群搭建的三种方式
May 31 Redis
浅析Redis Sentinel 与 Redis Cluster
Jun 24 Redis
浅谈Redis中的RDB快照
Jun 29 Redis
Redis Cluster 集群搭建你会吗
Aug 04 Redis
Redis集群新增、删除节点以及动态增加内存的方法
Sep 04 Redis
SpringBoot集成Redis的思路详解
Oct 16 Redis
源码分析Redis中 set 和 sorted set 的使用方法
Mar 22 Redis
Redis中key的过期删除策略和内存淘汰机制
Apr 12 Redis
Redis数据同步之redis shake的实现方法
Apr 21 Redis
Redis实现短信验证码登录的示例代码
Jun 14 Redis
如何使用注解方式实现 Redis 分布式锁
Jul 23 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+SQL 注入攻击的技术实现以及预防办法
2010/12/29 PHP
php实现的RSS生成类实例
2015/04/23 PHP
php打包网站并在线压缩为zip
2016/02/13 PHP
PHP实现求连续子数组最大和问题2种解决方法
2017/12/26 PHP
JS性能优化笔记搜索整理
2013/08/21 Javascript
通过正则表达式实现表单验证是否为中文
2014/02/18 Javascript
浅析tr的隐藏和显示问题
2014/03/05 Javascript
js实现网站最上边可关闭的浮动广告条代码
2015/09/04 Javascript
使用jQuery调用XML实现无刷新即时聊天
2016/08/07 Javascript
JavaScript实现自定义媒体播放器方法介绍
2017/01/03 Javascript
简单实现nodejs上传功能
2017/01/14 NodeJs
jQuery表单设置值的方法
2017/06/30 jQuery
简单实现vue验证码60秒倒计时功能
2017/10/11 Javascript
微信小程序实现选项卡效果
2018/11/06 Javascript
bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?
2019/07/26 Javascript
[59:42]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
python网页请求urllib2模块简单封装代码
2014/02/07 Python
Python sorted函数详解(高级篇)
2018/09/18 Python
浅谈Python爬虫基本套路
2019/03/25 Python
python实现对图片进行旋转,放缩,裁剪的功能
2019/08/07 Python
python自动分箱,计算woe,iv的实例代码
2019/11/22 Python
TensorFlow梯度求解tf.gradients实例
2020/02/04 Python
python:删除离群值操作(每一行为一类数据)
2020/06/08 Python
Python 如何实现数据库表结构同步
2020/09/29 Python
html5+css3之动画在webapp中的应用
2014/11/21 HTML / CSS
html5指南-5.使用web storage存储键值对的数据
2013/01/07 HTML / CSS
浅析HTML5:'data-'属性的作用
2018/01/23 HTML / CSS
特步官方商城:Xtep
2017/03/21 全球购物
俄罗斯最大的隐形眼镜销售网站:Ochkov.Net
2021/02/07 全球购物
怎样创建、运行java程序
2014/08/01 面试题
学校四风对照检查材料
2014/08/28 职场文书
2014年工商所工作总结
2014/12/09 职场文书
实习生个人总结范文
2015/02/28 职场文书
2015年财务个人工作总结范文
2015/05/22 职场文书
小学毕业感言100字
2015/07/30 职场文书
SQLServer中exists和except用法介绍
2021/12/04 SQL Server