等待下一个秋

  • Spark
  • Flink
  • Hive
  • 数据仓库
  • ClickHouse
  • 收徒弟
  • Java
    • Spring
    • Mybatis
    • SpringBoot
    • 面试题
  • Python
    • Python基础
    • 爬虫
    • Numpy
    • matplotlib
    • Flask
  • 技术杂谈
    • Linux知识
    • Docker
    • Git教程
    • Redis教程
    • mysql
    • 前端
    • R语言
    • 机器学习
  • 关于我
  • 其它
    • 副业挣钱
    • 资料下载
    • 资料文档
专注于Hadoop/Spark/Flink/Hive/数据仓库等
关注公众号:大数据技术派,获取更多学习资料。
  1. 首页
  2. Java
  3. 正文

redis 删除大key集合的方法

2019年4月3日 9262点热度 0人点赞 0条评论

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,在超时时间短的苛刻情况下,显然会发送超时,程序异常!好在,我们用的是连接池,没有出现问题。

分批删除

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

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 scanResult=jedis.sscan("testset", cursor, scanParams);
            // 返回0 说明遍历完成
            cursor = scanResult.getStringCursor();
            List 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来执行。
参考链接:
http://mysql.taobao.org/monthly/2018/10/05/
https://blog.csdn.net/liu1390910/article/details/79728569
https://blog.csdn.net/wsliangjian/article/details/52329320

标签: Java
最后更新:2019年4月5日

等待下一个秋

待我代码写成,便娶你为妻!专注于Hadoop/Spark/Flink/Hive/数据仓库等,关注公众号:大数据技术派,获取更多学习资料。

打赏 点赞
下一篇 >

文章评论

取消回复

等待下一个秋

待我代码写成,便娶你为妻!专注于Hadoop/Spark/Flink/Hive/数据仓库等,关注公众号:大数据技术派,获取更多学习资料。

搜一搜
微信
最新 热点 随机
最新 热点 随机
ChatGPT可以做什么 ClickHouse 自定义分区键 ClickHouse数据副本引擎 ClickHouse ReplacingMergeTree引擎 ClickHouse MergeTree引擎 clickhouse简介
十大经典排序算法——希尔排序 NumPy 基础知识 mysql索引不生效 ClickHouse数据副本引擎 推荐几个能挣钱的SpringBoot项目 2021,我这一年
标签聚合
Redis mysql 数据仓库 Hive 大数据 Flink 算法 Python R语言 Java 挣钱 书籍
文章归档
  • 2023年2月
  • 2022年12月
  • 2022年11月
  • 2022年9月
  • 2022年7月
  • 2022年6月
  • 2022年5月
  • 2022年4月
  • 2022年3月
  • 2022年2月
  • 2022年1月
  • 2021年12月
  • 2021年11月
  • 2021年10月
  • 2021年9月
  • 2021年8月
  • 2021年6月
  • 2021年5月
  • 2021年4月
  • 2021年3月
  • 2021年2月
  • 2021年1月
  • 2020年12月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2020年7月
  • 2020年5月
  • 2020年4月
  • 2020年1月
  • 2019年9月
  • 2019年8月
  • 2019年7月
  • 2019年6月
  • 2019年5月
  • 2019年4月
  • 2019年3月
  • 2019年1月
  • 2018年12月
  • 2017年5月

©2022 ikeguang.com. 保留所有权利。

鄂ICP备2020019097号-1

鄂公网安备 42032202000160号