redis 删除大key集合的方法

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: redis大key,这里指的是大的集合数据类型,如(set/hash/list/sorted set),一个key包含很多元素。由于redis是单线程,在删除大key(千万级别的set集合)的时候,或者清理过期大key数据时,主线程忙于删除这个大key,会导致redis阻塞、崩溃,应用程序异常的情况。

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


一个例子


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

10.1.254.18:6380> info memory
# Memory
used_memory:15175740016
used_memory_human:14.13G
used_memory_rss:22302339072
used_memory_peak:22351749192
used_memory_peak_human:20.82G
used_memory_lua:36864
mem_fragmentation_ratio:1.47
mem_allocator:jemalloc-3.6.0
10.1.254.18:6380> scard helper_2019-03-12
(integer) 64530980
10.1.254.18:6380> del helper_2019-03-12
(integer) 1
(81.23s)
10.1.254.18:6380> info memory
# Memory
used_memory:8466985704
used_memory_human:7.89G
used_memory_rss:10669453312
used_memory_peak:22351749192
used_memory_peak_human:20.82G
used_memory_lua:36864
mem_fragmentation_ratio:1.26
mem_allocator:jemalloc-3.6.0


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


Java 分批删除


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


private static void test2(){
    // 连接redis 服务器
    Jedis jedis = new Jedis("0.0.0.0",6379);
    jedis.auth("123456");
    // 分批删除
    try {
        ScanParams scanParams = new ScanParams();
        // 每次删除 500 条
        scanParams.count(500);
        String cursor = "";
        while (!cursor.equals("0")){
            ScanResult<String> scanResult=jedis.sscan("testset", cursor, scanParams);
            // 返回0 说明遍历完成
            cursor = scanResult.getStringCursor();
            List<String> result = scanResult.getResult();
            long t1 = System.currentTimeMillis();
            for(int m = 0;m < result.size();m++){
                String element = result.get(m);
                jedis.srem("testset", element);
            }
            long t2 = System.currentTimeMillis();
            System.out.println("删除"+result.size()+"条数据,耗时: "+(t2-t1)+"毫秒,cursor:"+cursor);
        }
    }catch (JedisException e){
        e.printStackTrace();
    }finally {
        if(jedis != null){
            jedis.close();
        }
    }
}


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


  • 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集合为例:

# -*- coding:utf-8 -*-
import redis
def test():
    # StrictRedis创建连接时,这个连接由连接池管理,所以我们无需关注连接是否需要主动释放
    re = redis.StrictRedis(host = "0.0.0.0",port = 6379,password = "123")
    key = "test"
    for i in range(100000):
        re.sadd(key, i)
    cursor = '0'
    cou = 200
    while cursor != 0:
        cursor,data = re.sscan(name = key, cursor = cursor, count = cou)
        for item in data:
            re.srem(key, item)
            print cursor
if __name__ == '__main__':
                    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种场景,每种场景对应一个配置参数; 默认都是关闭。


lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
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来执行。



相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
2月前
|
存储 NoSQL 关系型数据库
Redis 集合(Set)
10月更文挑战第17天
40 5
|
1月前
|
消息中间件 缓存 NoSQL
Redis 高并发竞争 key ,如何解决这个难点?
本文主要探讨 Redis 在高并发场景下的并发竞争 Key 问题,以及较为常用的两种解决方案(分布式锁+时间戳、利用消息队列)。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Redis 高并发竞争 key ,如何解决这个难点?
|
21天前
|
存储 监控 NoSQL
Redis大Key问题如何排查?如何解决?
Redis大Key问题如何排查?如何解决?
52 0
Redis大Key问题如何排查?如何解决?
|
22天前
|
存储 NoSQL 算法
面试官:Redis 大 key 多 key,你要怎么拆分?
本文介绍了在Redis中处理大key和多key的几种策略,包括将大value拆分成多个key-value对、对包含大量元素的数据结构进行分桶处理、通过Hash结构减少key数量,以及如何合理拆分大Bitmap或布隆过滤器以提高效率和减少内存占用。这些方法有助于优化Redis性能,特别是在数据量庞大的场景下。
面试官:Redis 大 key 多 key,你要怎么拆分?
|
1月前
|
存储 缓存 监控
利用 Redis 缓存特性避免缓存穿透的策略与方法
【10月更文挑战第23天】通过以上对利用 Redis 缓存特性避免缓存穿透的详细阐述,我们对这一策略有了更深入的理解。在实际应用中,我们需要根据具体情况灵活运用这些方法,并结合其他技术手段,共同保障系统的稳定和高效运行。同时,要不断关注 Redis 缓存特性的发展和变化,及时调整策略,以应对不断出现的新挑战。
64 10
|
1月前
|
缓存 监控 NoSQL
Redis 缓存穿透的检测方法与分析
【10月更文挑战第23天】通过以上对 Redis 缓存穿透检测方法的深入探讨,我们对如何及时发现和处理这一问题有了更全面的认识。在实际应用中,我们需要综合运用多种检测手段,并结合业务场景和实际情况进行分析,以确保能够准确、及时地检测到缓存穿透现象,并采取有效的措施加以解决。同时,要不断优化和改进检测方法,提高检测的准确性和效率,为系统的稳定运行提供有力保障。
50 5
|
2月前
|
NoSQL Unix Redis
Redis 键(key)
10月更文挑战第15天
35 1
|
2月前
|
缓存 监控 负载均衡
如何解决Redis热点Key问题?技术干货分享
【10月更文挑战第2天】在Redis的使用过程中,热点Key问题是一个常见的性能瓶颈。热点Key指的是那些被频繁访问的Key,它们可能导致Redis服务器的负载不均衡,进而影响整体性能。本文将深入探讨热点Key问题的成因、影响以及多种解决方案,帮助读者在实际工作中有效应对这一挑战。
101 3
|
2月前
|
存储 分布式计算 NoSQL
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
大数据-40 Redis 类型集合 string list set sorted hash 指令列表 执行结果 附截图
28 3
|
2月前
|
消息中间件 分布式计算 NoSQL
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
27 2