文章目录
- MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?
- 一、什么是热点数据?
- 二、方法一:日志分析法
- 1. 基本思路
- 2. 实际操作
- 3. 缺点
- 三、方法二:实时统计法
- 1. 基本思路
- 2. 实际操作
- 3. 缺点
- 四、方法三:混合策略
- 1. 基本思路
- 2. 实际操作
- 3. 优点
- 五、如何保证 Redis 中的数据都是最新的?
- 1. 定时刷新
- 2. 实时更新
- 六、总结
- 希望这篇博客对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。
- 📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?
大家好,我是都叫我闫工!今天我们要聊一个非常有意思的问题:MySQL里有2000万数据,而Redis中只存了20万的数据,如何保证这20万都是热点数据?
这个问题看起来有点复杂,但其实它背后隐藏着一个核心问题:如何从海量数据中筛选出最“热”的那部分数据,并将其高效地加载到Redis中?
一、什么是热点数据?
在开始之前,我们先明确一下什么是热点数据。热点数据是指那些被频繁访问、查询次数多的数据。比如,在电商系统中,某些商品可能因为促销活动而被疯狂点击,这些商品的数据就是热点数据。
那么,问题来了:如何从2000万数据中找到这20万的热点数据呢?
二、方法一:日志分析法
1. 基本思路
日志分析法的核心思想是通过分析用户的行为日志(比如访问日志、点击日志等),找出那些被频繁访问的数据。
具体步骤如下:
- 收集日志:将用户的访问行为记录下来,存储到一个日志文件中。
- 统计频率:对日志进行分析,计算每个数据的访问次数。
- 筛选热点数据:根据访问次数排序,选取前20万的数据作为热点数据。
2. 实际操作
假设我们的 MySQL 数据表结构如下:
CREATETABLE`user`(`id`INT(11)NOTNULLAUTO_INCREMENT,`name`VARCHAR(255)DEFAULTNULL,`age`INT(11)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;我们的日志表结构如下:
CREATETABLE`access_log`(`id`INT(11)NOTNULLAUTO_INCREMENT,`user_id`INT(11)DEFAULTNULL,`access_time`DATETIMEDEFAULTCURRENT_TIMESTAMP,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8mb4;我们需要统计每个用户的访问次数:
SELECTuser_id,COUNT(*)ASaccess_countFROMaccess_logGROUPBYuser_idORDERBYaccess_countDESCLIMIT200000;然后,将这些用户的数据加载到 Redis 中。
3. 缺点
- 延迟性:日志分析法需要定期运行,无法实时反映最新的热点数据。
- 资源消耗:如果日志量非常大(比如每天几亿条),统计过程可能会非常耗时。
三、方法二:实时统计法
1. 基本思路
实时统计法的核心思想是在每次用户请求时,实时记录该数据的访问次数,并动态地维护一个“热点数据”列表。
具体步骤如下:
- 监听页面请求:在应用层(比如Spring Boot)监听每个用户请求。
- 统计频率:使用 Redis 的
INCR命令来增加相应数据的计数器。 - 维护热点数据:定期遍历所有数据,筛选出访问次数最高的前20万条数据。
2. 实际操作
假设我们的应用是一个电商系统,每个商品都有一个 ID。我们可以在 Redis 中为每个商品创建一个计数器:
# 初始化商品计数器 SET product:123456:count 0 # 用户访问商品时增加计数器 INCR product:123456:count然后,定期遍历所有商品的计数器,找出前20万条数据:
publicvoidrefreshHotData(){// 获取所有商品IDList<String>productIdList=getAllProductIds();// 统计访问次数Map<String,Long>countMap=newHashMap<>();for(StringproductId:productIdList){longcount=redisTemplate.opsForValue().get(productId+":count");countMap.put(productId,count);}// 根据访问次数排序,选取前20万条数据List<Map.Entry<String,Long>>sortedEntries=newArrayList<>(countMap.entrySet());sortedEntries.sort((a,b)->b.getValue().compareTo(a.getValue()));// 将前20万条数据加载到Redis中for(inti=0;i<200000&&i<sortedEntries.size();i++){StringproductId=sortedEntries.get(i).getKey();// 加载到Redis的hash结构中redisTemplate.opsForHash().put("hot_products",productId,getProductDetails(productId));}}3. 缺点
- 性能问题:如果商品数量非常多(比如几千万),遍历所有商品的计数器会非常耗时。
- 内存占用:Redis 中存储所有商品的计数器可能会占用大量内存。
四、方法三:混合策略
1. 基本思路
结合日志分析法和实时统计法,先通过日志分析法预加载一批热点数据到 Redis 中,然后在运行时通过实时统计法动态调整热点数据列表。
2. 实际操作
- 初始化阶段:通过日志分析法,将前20万的热点数据加载到 Redis 中。
- 运行阶段:使用实时统计法,动态维护热点数据列表,及时淘汰冷门数据,加入新的热点数据。
3. 优点
- 高效性:结合了两种方法的优点,既能快速预加载热点数据,又能动态调整。
- 灵活性:可以根据业务需求调整预加载和动态调整的频率。
五、如何保证 Redis 中的数据都是最新的?
在实际应用中,我们需要确保 Redis 中的热点数据是最新的。为此,我们可以采用以下策略:
1. 定时刷新
定期(比如每小时一次)重新计算热点数据,并更新 Redis 中的内容。
publicvoidscheduleRefresh(){// 每小时执行一次ScheduledExecutorServicescheduler=Executors.newSingleThreadScheduledExecutor();scheduler.scheduleAtFixedRate(this::refreshHotData,0,1,TimeUnit.HOURS);}2. 实时更新
在每次用户请求时,动态调整热点数据列表。例如,在某个商品的访问次数超过一定阈值时,将其加入到 Redis 的热点数据中。
publicvoidhandleRequest(StringproductId){// 增加计数器redisTemplate.opsForValue().increment(productId+":count",1);// 如果访问次数达到阈值,加入热点数据longcount=redisTemplate.opsForValue().get(productId+":count");if(count>THRESHOLD){redisTemplate.opsForHash().put("hot_products",productId,getProductDetails(productId));}}六、总结
通过以上方法,我们可以有效地将热点数据加载到 Redis 中,并确保这些数据是最新的。具体选择哪种方法取决于业务需求和系统资源:
- 如果需要实时反映最新的热点数据,可以采用实时统计法。
- 如果对延迟性要求不高,但希望减少系统开销,可以采用日志分析法。
- 如果希望兼顾高效性和灵活性,可以采用混合策略。
希望这篇博客对你有所帮助!如果你有任何问题或建议,欢迎在评论区留言。
📚 领取 | 1000+ 套高质量面试题大合集(无套路,闫工带你飞一把)!
你想做外包吗?闫工就是外包出身,但我已经上岸了!你也想上岸吗?
闫工精心准备了程序准备面试?想系统提升技术实力?闫工精心整理了1000+ 套涵盖前端、后端、算法、数据库、操作系统、网络、设计模式等方向的面试真题 + 详细解析,并附赠高频考点总结、简历模板、面经合集等实用资料!
✅ 覆盖大厂高频题型
✅ 按知识点分类,查漏补缺超方便
✅ 持续更新,助你拿下心仪 Offer!
📥免费领取👉 点击这里获取资料
已帮助数千位开发者成功上岸,下一个就是你!✨