MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
一位粉丝在美团三面时被问懵。
一、问题本质:缓存系统的“生存游戏”
2000万数据中,只有20万是高频访问的“顶流”,剩下1980万都是“冷数据”。这像一场生存游戏——如何让Redis精准淘汰“冷数据”,长期保留“热数据”?
以下数据暴露核心矛盾:
Redis内存成本太高
80%请求集中在20%数据(二八法则)
热点数据动态变化(如突发新闻、秒杀商品)
二、三级缓存治理体系
1. 第一层:智能淘汰策略(守门员)
Redis配置黄金法则:
# redis.conf关键配置maxmemory 20gb # 按20万数据*1KB计算maxmemory-policy allkeys-lfu # 使用LFU算法(Least Frequently Used)
淘汰策略对比:
allkeys-lfu | ||
volatile-ttl | ||
allkeys-random |
2. 第二层:实时热点探测(雷达系统)
DataStream<ItemViewCount> windowData = data.keyBy("itemId").window(SlidingProcessingTimeWindows.of(Time.minutes(5), Time.minutes(1))).aggregate(new CountAgg(), new WindowResultFunction());windowData.keyBy("windowEnd").process(new TopNHotItems(200000)) // 取Top20万.addSink(new ZkConfigUpdater()); // 上报配置中心
3. 第三层:多级缓存架构(防御矩阵)
// Caffeine本地缓存(第一级)LoadingCache<String, Object> localCache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(30, TimeUnit.SECONDS).build(key -> {// Redis查询(第二级)Object val = redis.get(key);if(val == null) {val = mysql.get(key);redis.setex(key, 3600, val); // 回填Redis}return val;});
三、四大核心优化技巧
1. 热点标记与保护
// 热点标记ConcurrentHashMap<String, AtomicLong> hotKeyCounter = new ConcurrentHashMap<>();public Object getData(String key) {hotKeyCounter.compute(key, (k,v) ->v == null ? new AtomicLong(1) : v.incrementAndGet());if(hotKeyCounter.get(key).get() > 1000) { // 判定为热点redis.persist(key); // 取消过期时间zkClient.registerHotKey(key); // 上报监控}return localCache.get(key);}
2. 冷热数据分离存储
MySQL表优化:
ALTER TABLE productsADD COLUMN hot_score INT DEFAULT 0 COMMENT '热度值',ADD INDEX idx_hot_score (hot_score);
Redis存储优化:
# 使用Hash结构压缩存储HMSET product:1234data "{...json...}"hot 1expire 1735689600
3. 智能预热机制
# 定时预热脚本(每日凌晨执行)def preheat_cache():# 获取昨日Top20万热点hot_items = mysql.query("""SELECT item_idFROM access_logWHERE date = CURDATE() - INTERVAL 1 DAYGROUP BY item_idORDER BY COUNT(*) DESCLIMIT 200000""")# 批量写入Redispipeline = redis.pipeline()for item in hot_items:data = mysql.get(item.id)pipeline.setex(item.id, 86400, data) # 缓存24小时pipeline.execute()
4. 动态策略调整
四、压测数据对比
| 98.5% | 2.1ms | 1.5% |
五、面试加分项
1.缓存雪崩防护:
// 随机过期时间避免集体失效public void setCache(String key, Object value) {int expire = 3600 + new Random().nextInt(600); // 3600~4200秒随机redis.setex(key, expire, value);}
2.热点Key分片:
def get_cache_key(item_id):shard = item_id % 10 # 分10个片return f"item_{shard}_{item_id}"
3.多级降级策略:
六、实战建议
1.每日运维:
凌晨低峰期执行缓存分析脚本
使用
redis-cli --hotkeys主动探测热点
2.监控预警:
对缓存击穿率设置分级报警(>5%触发警告)
Redis内存使用超过80%时自动扩容
3.业务隔离:
不同业务线使用独立缓存实例(如商品、订单分离)
- END -
IT168与ITPUB技术社区强强联手,收集数百款主流数据库产品,重磅推出“数据库全景图”,旨在打造一款集知识普及、产品对比、选型参考于一体的综合性资源平台。“数据库全景图(11月版)”可扫描上方左侧二维码回复关键词获取,识别右侧二维码直达“数据库全景图”链接(右上角浏览器打开获取更好体验)。