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 IP地址的绑定的实现
May 08 Redis
redis实现排行榜功能
May 24 Redis
Redis缓存-序列化对象存储乱码问题的解决
Jun 21 Redis
Redis 彻底禁用RDB持久化操作
Jul 09 Redis
Jedis操作Redis实现模拟验证码发送功能
Sep 25 Redis
Redis中缓存穿透/击穿/雪崩问题和解决方法
Dec 04 Redis
分布式架构Redis中有哪些数据结构及底层实现原理
Mar 13 Redis
Redis 哨兵机制及配置实现
Mar 25 Redis
Redis分布式锁的7种实现
Apr 01 Redis
redis sentinel监控高可用集群实现的配置步骤
Apr 01 Redis
redis复制有可能碰到的问题汇总
Apr 03 Redis
windows安装 redis 6.2.6最新步骤详解
Apr 26 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
Access数据库导入Mysql的方法之一
2006/10/09 PHP
php中serialize序列化与json性能测试的示例分析
2013/04/27 PHP
PHP弹出对话框技巧详细解读
2015/09/26 PHP
php伪静态验证码不显示的解决方案
2019/09/26 PHP
jQuery 工具函数学习资料
2010/04/29 Javascript
javascript 按键事件(兼容各浏览器)
2013/12/20 Javascript
手机号码,密码正则验证
2014/09/04 Javascript
JavaScript检测鼠标移动方向的方法
2015/05/22 Javascript
JavaScript对Cookie进行读写操作实例
2015/07/25 Javascript
jQuery ajax提交Form表单实例(附demo源码)
2016/04/06 Javascript
超链接怎么正确调用javascript函数
2016/05/23 Javascript
Bootstrap选项卡与Masonry插件的完美结合
2016/07/06 Javascript
JS实现用户注册时获取短信验证码和倒计时功能
2016/10/27 Javascript
EasyUI 中combotree 默认不能选择父节点的实现方法
2016/11/07 Javascript
关于Function中的bind()示例详解
2016/12/02 Javascript
基于jQuery实现照片墙自动播放特效
2017/01/12 Javascript
JS获取鼠标坐标并且根据鼠标位置不同弹出不同内容
2017/06/12 Javascript
React Native中的RefreshContorl下拉刷新使用
2017/10/09 Javascript
bmob js-sdk 在vue中的使用教程
2018/01/21 Javascript
jQuery无冲突模式详解
2019/01/17 jQuery
python写的ARP攻击代码实例
2014/06/04 Python
在Python中使用base64模块处理字符编码的教程
2015/04/28 Python
详解Python中break语句的用法
2015/05/14 Python
python中使用PIL制作并验证图片验证码
2018/03/15 Python
Python入门必须知道的11个知识点
2018/03/21 Python
Numpy截取指定范围内的数据方法
2018/11/14 Python
Python3使用TCP编写一个简易的文件下载器功能
2019/05/08 Python
Python 实用技巧之利用Shell通配符做字符串匹配
2019/08/23 Python
Python sklearn库实现PCA教程(以鸢尾花分类为例)
2020/02/24 Python
python 删除excel表格重复行,数据预处理操作
2020/07/06 Python
h5实现获取用户地理定位的实例代码
2017/07/17 HTML / CSS
会展策划与管理专业大学生职业生涯规划
2014/02/07 职场文书
十八届三中全会学习方案
2014/02/16 职场文书
超市客服工作职责
2014/06/11 职场文书
python自动化测试之Selenium详解
2022/03/13 Python
mysql sock 文件解析及作用讲解
2022/07/15 MySQL