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限流的实际应用
Apr 24 Redis
Windows下redis下载、redis安装及使用教程
Jun 02 Redis
Redis 彻底禁用RDB持久化操作
Jul 09 Redis
关于redisson缓存序列化几枚大坑说明
Aug 04 Redis
聊聊redis-dump工具安装问题
Jan 18 Redis
解决Redis启动警告问题
Feb 24 Redis
Redis调用Lua脚本及使用场景快速掌握
Mar 16 Redis
Redis安装使用RedisJSON模块的方法
Mar 23 Redis
muduo TcpServer模块源码分析
Apr 26 Redis
如何使用注解方式实现 Redis 分布式锁
Jul 23 Redis
Redis主从复制操作和配置详情
Sep 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中实现进程间通讯
2006/10/09 PHP
php面向对象全攻略 (五) 封装性
2009/09/30 PHP
PHP高级编程实例:编写守护进程
2014/09/02 PHP
详解WordPress开发中get_header()获取头部函数的用法
2016/01/08 PHP
javascript 清除输入框中的数据
2009/04/13 Javascript
javascript预加载图片、css、js的方法示例介绍
2013/10/14 Javascript
jquery插件jquery.dragscale.js实现拖拽改变元素大小的方法(附demo源码下载)
2016/02/25 Javascript
JS中创建函数的三种方式及区别
2016/03/13 Javascript
基于jQuery下拉选择框插件支持单选多选功能代码
2016/06/07 Javascript
zTree异步加载展开第一级节点的实现方法
2017/09/05 Javascript
VUE饿了么树形控件添加增删改功能的示例代码
2017/10/17 Javascript
基于javascript中的typeof和类型判断(详解)
2017/10/27 Javascript
vue-cli webpack模板项目搭建及打包时路径问题的解决方法
2018/02/26 Javascript
详解使用jQuery.i18n.properties实现js国际化
2018/05/04 jQuery
vue element upload组件 file-list的动态绑定实现
2019/10/11 Javascript
Node.js创建一个Express服务的方法详解
2020/01/06 Javascript
Vue使用vue-draggable 插件在不同列表之间拖拽功能
2020/03/12 Javascript
[01:39:42]Fnatic vs Mineski 2018国际邀请赛小组赛BO2 第一场 8.17
2018/08/18 DOTA
Python中使用hashlib模块处理算法的教程
2015/04/28 Python
Python中使用装饰器时需要注意的一些问题
2015/05/11 Python
微信小程序跳一跳游戏 python脚本跳一跳刷高分技巧
2018/01/04 Python
Python内置模块ConfigParser实现配置读写功能的方法
2018/02/12 Python
Python函数参数操作详解
2018/08/03 Python
django之自定义软删除Model的方法
2019/08/14 Python
解决在pycharm运行代码,调用CMD窗口的命令运行显示乱码问题
2019/08/23 Python
Python如何优雅获取本机IP方法
2019/11/10 Python
python3中sorted函数里cmp参数改变详解
2020/03/12 Python
踩坑:pytorch中eval模式下结果远差于train模式介绍
2020/06/23 Python
Tensorflow中批量读取数据的案列分析及TFRecord文件的打包与读取
2020/06/30 Python
解析python 类方法、对象方法、静态方法
2020/08/15 Python
Html5饼图绘制实现统计图的方法
2020/08/05 HTML / CSS
美国社交购物市场:MassGenie
2019/02/18 全球购物
校园活动策划方案
2014/06/13 职场文书
2015商场元旦促销活动策划方案
2014/12/09 职场文书
python基础入门之字典和集合
2021/06/13 Python
在虚拟机中安装windows server 2008的图文教程
2022/06/28 Servers