redis 删除大key集合的方法

redis大key,这里指的是大的集合数据类型,如(set/hash/list/sorted set),一个key包含很多元素。由于redis是单线程,在删除大key(千万级别的set集合)的时候,或者清理过期大key数据时,主线程忙于删除这个大key,会导致redis阻塞、崩溃,应用程序异常的情况。

一个例子

线上redis作为实时去重的一个工具,里面有6千万的用户guid,这么一个set集合,如果直接使用del删除,会导致redis严重阻塞。

 1 10.1.254.18:6380> info memory
 2 # Memory
 3 used_memory:15175740016
 4 used_memory_human:14.13G
 5 used_memory_rss:22302339072
 6 used_memory_peak:22351749192
 7 used_memory_peak_human:20.82G
 8 used_memory_lua:36864
 9 mem_fragmentation_ratio:1.47
10 mem_allocator:jemalloc-3.6.0
11 10.1.254.18:6380> scard helper_2019-03-12
12 (integer) 64530980
13 10.1.254.18:6380> del helper_2019-03-12
14 (integer) 1
15 (81.23s)
16 10.1.254.18:6380> info memory
17 # Memory
18 used_memory:8466985704
19 used_memory_human:7.89G
20 used_memory_rss:10669453312
21 used_memory_peak:22351749192
22 used_memory_peak_human:20.82G
23 used_memory_lua:36864
24 mem_fragmentation_ratio:1.26
25 mem_allocator:jemalloc-3.6.0

可以看到,helper_2019-03-12这个key,是一个包含64530980个元素的集合,直接使用del删除命令,花的时间为:81.23s,在超时时间短的苛刻情况下,显然会发送超时,程序异常!好在,我们用的是连接池,没有出现问题。

分批删除

这种情况,应该使用sscan命令,批量删除set集合元素的方法。下面是一个Java代码分批删除redis中set集合的例子:

对于其它集合,也有对应的方法。

  • hash key:通过hscan命令,每次获取500个字段,再用hdel命令;
  • set key:使用sscan命令,每次扫描集合中500个元素,再用srem命令每次删除一个元素;
  • list key:删除大的List键,未使用scan命令; 通过ltrim命令每次删除少量元素。
  • sorted set key:删除大的有序集合键,和List类似,使用sortedset自带的zremrangebyrank命令,每次删除top 100个元素。

使用Python脚本批量删除

对于redis的监控和清理,通常会用一些Python脚本去做,简单、轻便。用java的话,再小的一个任务也要打包、发布,如果没有一套完善的开发、发布的流程,还是比较麻烦的。这时候,很多人倾向于写Python脚本,会Python的大部分人都是会Java的。

这里,还是以删除一个set集合为例:

 1 # -*- coding:utf-8 -*-
 2
 3 import redis
 4
 5 def test():
 6     # StrictRedis创建连接时,这个连接由连接池管理,所以我们无需关注连接是否需要主动释放
 7     re = redis.StrictRedis(host = "0.0.0.0",port = 6379,password = "123")
 8     key = "test"
 9     for i in range(100000):
10         re.sadd(key, i)
11
12         cursor = ‘0‘
13         cou = 200
14         while cursor != 0:
15             cursor,data = re.sscan(name = key, cursor = cursor, count = cou)
16             for item in data:
17                 re.srem(key, item)
18                 print cursor
19
20                 if __name__ == ‘__main__‘:
21                     test()

后台删除之lazyfree机制

为了解决redis使用del命令删除大体积的key,或者使用flushdb、flushall删除数据库时,造成redis阻塞的情况,在redis 4.0引入了lazyfree机制,可将删除操作放在后台,让后台子线程(bio)执行,避免主线程阻塞。

lazy free的使用分为2类:第一类是与DEL命令对应的主动删除,第二类是过期key删除、maxmemory key驱逐淘汰删除。

主动删除
UNLINK命令是与DEL一样删除key功能的lazy free实现。唯一不同时,UNLINK在删除集合类键时,如果集合键的元素个数大于64个(详细后文),会把真正的内存释放操作,给单独的bio来操作。

127.0.0.1:7000> UNLINK mylist
(integer) 1
FLUSHALL/FLUSHDB ASYNC

127.0.0.1:7000> flushall async //异步清理实例数据

被动删除
lazy free应用于被动删除中,目前有4种场景,每种场景对应一个配置参数; 默认都是关闭。

1 lazyfree-lazy-eviction no
2 lazyfree-lazy-expire no
3 lazyfree-lazy-server-del no
4 slave-lazy-flush no

lazyfree-lazy-eviction

针对redis内存使用达到maxmeory,并设置有淘汰策略时;在被动淘汰键时,是否采用lazy free机制;

因为此场景开启lazy free, 可能使用淘汰键的内存释放不及时,导致redis内存超用,超过maxmemory的限制。此场景使用时,请结合业务测试。

lazyfree-lazy-expire

针对设置有TTL的键,达到过期后,被redis清理删除时是否采用lazy free机制;

此场景建议开启,因TTL本身是自适应调整的速度。

lazyfree-lazy-server-del

针对有些指令在处理已存在的键时,会带有一个隐式的DEL键的操作。如rename命令,当目标键已存在,redis会先删除目标键,如果这些目标键是一个big key,那就会引入阻塞删除的性能问题。 此参数设置就是解决这类问题,建议可开启。

slave-lazy-flush

针对slave进行全量数据同步,slave在加载master的RDB文件前,会运行flushall来清理自己的数据场景,

参数设置决定是否采用异常flush机制。如果内存变动不大,建议可开启。可减少全量同步耗时,从而减少主库因输出缓冲区爆涨引起的内存使用增长。

expire及evict优化

redis在空闲时会进入activeExpireCycle循环删除过期key,每次循环都会率先计算一个执行时间,在循环中并不会遍历整个数据库,而是随机挑选一部分key查看是否到期,所以有时时间不会被耗尽(采取异步删除时更会加快清理过期key),剩余的时间就可以交给freeMemoryIfNeeded来执行。

参考链接:

http://mysql.taobao.org/monthly/2018/10/05/

https://blog.csdn.net/liu1390910/article/details/79728569

https://blog.csdn.net/wsliangjian/article/details/52329320

原文地址:https://www.cnblogs.com/data-magnifier/p/redis.html

时间: 2024-10-04 01:24:47

redis 删除大key集合的方法的相关文章

redis统计大key

–bigkeys redis-cli -h <host> -p <port> -n <db> --bigkeys 这条命令会从指定的 Redis DB 中持续采样,实时输出当时得到的 value 占用空间最大的 key 值,并在最后给出各种数据结构的 biggest key 的总结报告: user $ redis-cli -h myhost -p 12345 --bigkeys # Scanning the entire keyspace to find biggest

redis过期键删除策略以及大key删除方法

今天遇到了一个前同事挖的坑,刷新缓存中商品信息时先让key过期,然后从数据库里取最新数据然后再放到缓存中,他是这样写的 redisTemplate.expire(CacheConst.GOOGS_PREFIX,1,TimeUnit.MILLISECONDS); 设置key过期为一毫秒,导致缓存中有时没有商品信息,因为在这一毫秒内有可能已经从数据库中取到了最新数据,并且又放到了缓存中,一毫秒过后key过期了,缓存中就没了商品信息. 正确的应该这样写redisTemplate.expire(Cach

超大批量删除redis中无用key+配置

目前线上一个单实例redis中无用的key太多,决定删除一部分. 1.删除指定用户的key,使用redis的pipeline 根据一定条件把需要删除的用户统计出来,放到一个表里面,表为 del_user(int user_id),rows大约在1千万. 要删除的key为 "login:%s" %s匹配 user_id . 写sql文如下:把sql文保存在一个文件里面,命名为 1.sql SELECT CONCAT( "*2\r\n", '$3\r\n',    'D

Redis【知识点】批量删除指定Key

Redis中有删除单条数据的命令DEL但是他没有批量删除多条数据的方法,那我们怎么去批量删除多条数据呢! 第一种方式 /work/app/redis/bin/redis-cli -a youpassword keys 'Volume:*' | xargs /work/app/redis/bin/redis-cli -a youpassword del 注释: 通过:keys 'Volume'去匹配你要删除的Key:Value条目,然后把结果传给xargs然后删除数据 如果要删除指定的Redis库

如何提取Redis中的大KEY

工作中,经常有些Redis实例使用不恰当,或者对业务预估不准确,或者key没有及时进行处理等等原因,导致某些KEY相当大. 那么大Key会带来哪些问题呢? 如果是集群模式下,无法做到负载均衡,导致请求倾斜到某个实例上,而这个实例的QPS会比较大,内存占用也较多:对于Redis单线程模型又容易出现CPU瓶颈,当内存出现瓶颈时,只能进行纵向库容,使用更牛逼的服务器. 涉及到大key的操作,尤其是使用hgetall.lrange 0 -1.get.hmget 等操作时,网卡可能会成为瓶颈,也会到导致堵

统计redis大key信息(前topN)

相关包下载链接 https://github.com/sripathikrishnan/redis-rdb-tools/releaseshttps://pypi.org/project/python-lzf/https://pypi.python.org/simple/redis/ 安装 pip install python-lzf-0.2.4.tar.gzpip install redis-2.10.6.tar.gzpip install rdbtools-0.1.12.tar.gz 解析re

redis删除key

批量删除Key Redis 中有删除单个 Key 的指令 DEL,但好像没有批量删除 Key 的指令,不过我们可以借助 Linux 的 xargs 指令来完成这个动作 1 2 3 redis-cli keys "*" | xargs redis-cli del //如果redis-cli没有设置成系统变量,需要指定redis-cli的完整路径 //如:/opt/redis/redis-cli keys "*" | xargs /opt/redis/redis-cli

Redis总体 概述,安装,方法调用

1 什么是redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有序集合).这些数据类型都支持push/pop.add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的.在此基础上,redis支持各种不同方式的排序.与memcached一样,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写

Java 使用Redis缓存工具的图文详细方法

开始在 Java 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 Java redis 驱动,且你的机器上能正常使用 Java. (1)Java的安装配置可以参考我们的 Java开发环境配置 (2)安装了 redis 服务: 请参考:Windows环境下使用Redis缓存工具的图文详细方法 或是: 首先你需要下载驱动包,下载 jedis.jar,确保下载最新驱动包. 在你的classpath中包含该驱动包. 一.新建一个javaweb项目. 1. 新建一个Jedis的项目.