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 19 Redis
redis使用不当导致应用卡死bug的过程解析
Jul 01 Redis
Redis Cluster集群动态扩容的实现
Jul 15 Redis
浅谈Redis位图(Bitmap)及Redis二进制中的问题
Jul 15 Redis
Redis分布式锁Redlock的实现
Aug 07 Redis
Redis 常见使用场景
Aug 30 Redis
Redis中有序集合的内部实现方式的详细介绍
Mar 16 Redis
Redis 哨兵机制及配置实现
Mar 25 Redis
muduo TcpServer模块源码分析
Apr 26 Redis
Redis高并发缓存架构性能优化
May 15 Redis
Redis入门基础常用操作命令整理
Jun 01 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学习笔记之一
2011/01/17 PHP
php页面函数设置超时限制的方法
2014/12/01 PHP
php实现登陆模块功能示例
2016/10/20 PHP
PHP防止sql注入小技巧之sql预处理原理与实现方法分析
2019/12/13 PHP
Javascript写了一个清除“logo1_.exe”的杀毒工具(可扫描目录)
2007/02/09 Javascript
一些mootools的学习资源
2010/02/07 Javascript
js冒泡法和数组转换成字符串示例代码
2013/08/14 Javascript
jquery实现div阴影效果示例代码
2013/09/16 Javascript
简单的JavaScript互斥锁分享
2014/02/02 Javascript
JS实现很酷的EMAIL地址添加功能实例
2015/02/28 Javascript
浅析javascript的return语句
2015/12/15 Javascript
聊一聊JS中的prototype
2016/09/29 Javascript
Vue中的Vux配置指南
2017/12/08 Javascript
vue配置接口域名方法总结
2019/05/12 Javascript
Python 深入理解yield
2008/09/06 Python
在python3环境下的Django中使用MySQL数据库的实例
2017/08/29 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
对pandas中时间窗函数rolling的使用详解
2018/11/28 Python
使用Django2快速开发Web项目的详细步骤
2019/01/06 Python
python批量修改文件夹及其子文件夹下的文件内容
2019/03/15 Python
Python yield的用法实例分析
2020/03/06 Python
python如何操作mysql
2020/08/17 Python
python爬虫利用代理池更换IP的方法步骤
2021/02/21 Python
10种CSS3实现的loading动画,挑一个走吧?
2020/11/16 HTML / CSS
Zavvi美国:英国娱乐之家
2017/03/19 全球购物
瑞士最大的图书贸易公司:Orell Füssli
2019/12/28 全球购物
音乐学个人的自荐书范文
2013/11/26 职场文书
师范学院教师自荐书
2014/01/31 职场文书
实习生评语
2014/04/26 职场文书
力学专业求职信
2014/07/23 职场文书
单位工资证明范本
2015/06/12 职场文书
投诉书范文
2015/07/02 职场文书
干部考核工作总结2015
2015/07/24 职场文书
2016年优秀教师先进事迹材料
2016/02/26 职场文书
Go语言基础map用法及示例详解
2021/11/17 Golang
sqlserver连接错误之SQL评估期已过的问题解决
2022/03/23 SQL Server