mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4mobile wallpaper 5mobile wallpaper 6mobile wallpaper 7mobile wallpaper 8mobile wallpaper 9mobile wallpaper 10mobile wallpaper 11mobile wallpaper 12
1830 字
5 分钟
如何应对海量Key带来的redis内存占用问题?
2025-08-23

目录

一、业务场景

二、解决方案

(一)合并小Key

(二)临时添加TTL

(三)集群模式

(四)Redis on Flash 方案

(五)冷热数据分离(MySQL + Redis)

三、总结


一、业务场景#

当前你的项目的内存不足,请你提供解决方案。


二、#

(一)合并小Key#

为什么大量小Key存在会占用大量空间?

(1)内存碎片化:

Redis使用内存分配器来管理内存。大量的小内存分配请求会导致内存分配器难以找到连续且大小合适的空闲块,从而产生大量内存碎片。这些碎片虽然总量可能不小,但由于不连续,无法被有效利用,导致实际可用内存减少。

虽然每个键存储的数据很小,但Redis为每个键分配内存时,会包含键本身的名字、Redis对象结构以及实际数据结构的开销。

(2)元数据开销占比过大:

每个 Redis 键值对都有固定的元数据开销,大约在 90-100 字节左右。

如果一个键存储的值只有 10 字节,那么元数据开销则几乎占了总内存的全部,有效的数据密度非常低。

同时大量小Key存在也会使遍历键操作的执行时间边长,影响整体性能。

所以我们才需要通过合并小key,让它们共享元数据开销并减少内存碎片的产生。

那么如何合并?我们通常会使用Hash结构,因为Hash结构底层是由优化的,使用的是压缩列表,占有的内存非常小。

不过缺点就是Hash无法给单个字段设置TTL,只能给整个Key设置,这样可能会发生雪崩问题,需要程序应用层上做相应的熔断降级限流处理。

(二)临时添加TTL#

我们需要给一些非关键业务数据Key加上TTL,一般是通过SCAN扫描过滤掉关键业务数据Key来操作。

但这只是救急,是为了在保证服务不中断的前提下为后续优化操作争取时间窗口。

(三)模式#

关于Redis的三种集群模式我在下面这篇博客的最后针对其原理做了详细讲解:

带你轻松学习Redis_redis的运行机制-CSDN博客https://blog.csdn.net/2401_88959292/article/details/149565343?spm=1001.2014.3001.5502

(四)Redis on Flash 方案#

Redis on Flash (RoF) 是Redis开发的专有解决方案,其核心目标是在保证较高性能的前提下,显著降低Redis存储海量数据的成本,从而解决由内存价格昂贵导致的内存不足或成本过高问题。

它本质上是一种内存 + 闪存( + SSD) 架构。

(1)架构组成

  • **RAM(内存层):**用于存储最热的键值数据以及所有键名和元数据。这是保证超低延迟访问的关键。
  • **Flash(闪存层):**使用SSD存储访问频率较低的数据。键名和指向在SSD上位置的指针仍然保存在RAM中。

(2)工作机制

A. 写入

所有新写入的数据首先进入RAM层,被视为热数据。

B. 读取

如果请求的Key的Value在RAM中,则直接从RAM返回。

如果请求的Key的Value在上(即已被降级),则触发数据升级策略。

C. 数据降级

当Redis的内存使用达到配置的 RAM 阈值时,RoF 的智能算法开始工作。基于访问频率、最近访问时间、数据大小等因素,识别 RAM 中相对冷的数据,并将这些冷数据异步移动到 SSD 层。

  • 关键点:
    • Key 永远不会被移除 RAM, 只有大的Value会被移动。
    • 移动后,RAM 中保留 Key 和一个指向 SSD 上 Value 的小指针,释放内存空间。

D. 数据升级

当一个被降级到SSD的Value被访问时,它会被加载回RAM。

如果该Value后续被频繁访问,它会保持在RAM中。

如果RAM空间不足,它可能再次成为降级的候选者。

(五)冷热数据分离( + Redis)#

这个方案和第四个的很像,都是一个思想。

可以提供两个方案,一个是MySQL存储全量数据,一个是MySQL只存储冷数据。

这两个方案都需要我们提前在MySQL中创建一张持久化表:

CREATE TABLE `redis_data`
(
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`key` varchar(255) NOT NULL COMMENT '键',
`value` varchar(255) NOT NULL COMMENT '值',
`todayAccessCount` int NOT NULL DEFAULT '0' COMMENT '今日访问次数',
`totalAccessCount` int NOT NULL DEFAULT '0' COMMENT '总访问次数',
`createTime` datetime NOT NULL COMMENT '创建时间'
) COMMENT 'redis数据表';

(1)Redis存储热数据,MySQL存储全量数据

当写入数据时,最先写入MySQL,再写入Redis,同时写入Redis的Key全部带有TTL。

当读取时先访问Redis,Redis不存在则继续查MySQL,若查到数据则开启异步线程给DB的该数据行的当日访问次数和累计访问次数+1(当日访问次数每日定时任务自动清零),然后检查访问次数是否达到阈值,若达到则写入Redis作为热数据。

然后每天会有定时任务定期扫描MySQL,根据createTime创建时间和totalAccessCount累计访问次数字段来判断无用数据并进行删除。

当然,异步线程和定期扫描只针对于存储在缓存持久化表里的数据,因为有些缓存数据是用于预热分担MySQL压力的,它们原本就是存储在MySQL当中的。

具体流程如下:

这样的话Redis中的冷数据直接随着TTL到期而被删除,而MySQL的冷数据升级也可以根据原本数据的用途而灵活配置。

(2)Redis存储热数据,MySQL只存储冷数据

跟上一个方案一样,Redis中的所有数据都带有TTL。

但是写入操作只需写入Redis即可。同时引入Redis过期监听器,在监听器中对非核心业务的Key进行过滤,将核心业务过期的Key存入MySQL作为冷数据存储。

读取操作如果Redis有值,则异步更新TTL;反之则直接查MySQL,后面与上个方案的流程一样。

这个方案优化的点就在于提升了写入速度以及降低了MySQL的占用空间。

流程图如下:


三、总结#

如果经费充裕的情况下肯定使用集群 + ROF方案是最佳选择。

但是反之就建议先临时添加TTL救急,然后合并小Key,最后使用冷热数据分离方案。


码文不易,留个赞再走吧


原文链接: 如何应对海量Key带来的redis内存占用问题? 作者: Yilena

分享

如果这篇文章对你有帮助,欢迎分享给更多人!

如何应对海量Key带来的redis内存占用问题?
https://blog.csdn.net/2401_88959292/article/details/150641500?spm=1001.2014.3001.5501
作者
Yilena
发布于
2025-08-23
许可协议
CC BY 4.0

部分信息可能已经过时

相关文章 智能推荐
1
布隆过滤器因内存上限无法处理超量数据的优化方案
业务拆解 本文针对布隆过滤器因数据量增加导致内存上限不足的问题,深入分析并提出了三种优化方案。首先是分片布隆过滤器,通过哈希取模将数据分散,简单高效但受限于单机内存且易引发GC问题;其次是分布式布隆过滤器,借助Redis摆脱单机限制,并结合一致性哈希实现分片以优化缓存空间;最后是可扩展布隆过滤器,通过动态增加层数和容量来应对数据增长,但查询效率会随层数增加而降低。综合对比,推荐单机项目使用分片方案,分布式架构采用Redis分布式分片方案,以有效解决超量数据处理难题。
2
116秒→6秒:Redis管道+批处理优化用户好友关系校验的方案
业务拆解 本文针对社交平台中用户好友关系数据一致性问题,提出了一种高效的定时任务解决方案。通过分析初版方案的性能瓶颈(单线程串行处理导致116秒耗时),逐步优化为多线程并行处理(70秒)和最终版批量预加载策略(6秒)。终版方案的核心改进包括:1)预加载所有关注关系并建立内存映射;2)批量处理好友数据更新;3)使用Redis管道技术减少网络请求。最终将请求次数从35万次降至常数级,同时提供了完整的Java实现代码,包含分片处理、批量数据库操作和Redis管道更新等关键优化技术。
3
360s→15s:近25倍的性能优化重构十万Excel券码批量导入方案
业务拆解 本文针对十万级Excel券码批量导入场景,将原逐行解析导致的20万次网络IO,通过Redis管道与MQ批处理优化至182次。方案兼顾了宕机恢复与库存扣减,最终将耗时从360秒大幅缩减至15秒左右。
4
基于MySQL + Redis + JWT的双令牌认证方案的实现
业务拆解 本文针对单令牌认证机制存在的安全隐患与用户体验痛点,设计并实现了一套基于MySQL、Redis与JWT的双令牌(访问令牌+刷新令牌)认证方案。文章详细分析了双令牌机制的优势,通过分离认证与状态维护职责,结合Redis黑名单与分布式锁限流,有效提升了系统安全性。同时,提供了完整的Java代码实现,包括JWT工具类、Redis令牌管理服务、全局过滤器及业务层Controller逻辑,展示了如何优雅地处理令牌刷新、单点互斥登录及异常响应,为构建安全可靠的Web应用认证体系提供了实践参考。
5
一个简单高效的秒杀方案的实现
业务拆解 本文详细设计并实现了一个简单高效的电商秒杀方案,核心目标是保证“一人一单”且“防止超卖”。方案通过新增秒杀商品表与订单表并进行水平分表来优化数据库结构;利用Redis预热库存数据、Lua脚本保证扣减原子性,结合Set结构实现一人一单校验,从而有效应对高并发。同时,引入RabbitMQ异步处理订单生成,并配置生产者确认与幂等性检查机制以防消息丢失或重复消费。文章还提供了完整的Java代码实现,包括Redis与MQ配置、雪花算法ID生成、拦截器校验及定时任务同步库存,为高并发秒杀场景提供了实用的工程参考。

目录

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00