发布时间:2025-11-04 12:43:19 来源:技术快报 作者:人工智能
兄弟们,对缓今天咱来唠唠缓存界的存C场 "神雕侠侣"——Redis 和 Caffeine。这俩货要是接炸组起 CP 来,那性能简直能让你的强强系统原地起飞。先别急着问原理,联手咱先从程序员的有多日常痛点说起:有没有试过凌晨三点被监控报警吵醒,发现是对缓缓存雪崩把数据库搞挂了?有没有遇到过热点数据把 Redis 压得喘不过气,网络延迟比你摸鱼时的存C场网速还慢?别慌,这对 CP 就是接炸来救场的。
先说说 Redis 这位老大哥,作为分布式缓存的有多扛把子,它就像一个超大的对缓仓库,能存海量数据,存C场还支持各种复杂操作。接炸但仓库嘛,毕竟离你的工位有点远(网络延迟),每次取东西都得跑一趟,要是赶上仓库管理员忙(高并发),还得排队。再看 Caffeine,这就是源码下载你桌上的抽屉,存的都是你最近常用的东西,伸手就能够到,速度那叫一个快。但抽屉容量有限,装不了太多东西,而且要是停电了(进程重启),里面的东西就没了。

就像食堂打饭,常用的菜(热数据)放在窗口附近,不常用的(冷数据)放在仓库。Caffeine 负责存最热的数据,让你秒取;Redis 作为二级缓存,存次热的数据;数据库作为保底。这样一来,大部分请求都能在本地解决,少部分去 Redis,极少部分才去数据库,系统压力直接砍半。
这里有个小细节:从 Redis 拿到数据后,要不要立即更新 Caffeine?要看你的数据更新频率。如果是读多写少,比如商品详情页,没问题;如果是写频繁,比如订单状态,就得考虑更新策略了。
适合对数据一致性要求不高的场景,比如日志记录。写操作先把数据扔进队列,后台异步更新两级缓存。但风险也不小,要是服务挂了,队列里的数据就没了,得配合持久化队列使用。
(3)订阅发布(Pub/Sub)利用 Redis 的发布订阅功能,当数据更新时,发布一个事件,所有订阅的服务实例收到事件后,删除本地缓存。就像班长通知全班交作业,每个人收到通知后把自己的旧作业删掉,下次重新拿新的。
Caffeine 支持三种淘汰策略,就像收拾抽屉时决定先扔哪个旧东西:
LRU(最近最少使用):很久没用过的东西,先扔掉,比如你去年用过一次的计算器。LFU(最不常用):用得少的东西,先扔掉,比如你抽屉里积灰的 U 盘。TTL(生存时间):不管用没用,到期就扔,比如过期的零食。实际使用中,推荐 LRU+TTL 组合,比如热点数据设置较长的 TTL,普通数据用 LRU 淘汰。Redis 这边也可以配置淘汰策略,比如 allkeys-lru,和 Caffeine 形成互补。
场景:用户用一个不存在的商品 ID 疯狂请求,每次都得查数据库,就像有人天天敲你家门问 "有人吗",但其实没人住。
解决方案:
布隆过滤器:在入口处加一个过滤器,先判断 key 是否存在,不存在直接返回。就像在门口装个猫眼,先看看是不是熟人。空值缓存:查数据库后,即使没数据,也在两级缓存存一个空值,设置短 TTL,比如 5 分钟。场景:凌晨三点,大量缓存同时过期,请求像潮水一样涌到数据库,就像全班同学同时找老师问问题,老师直接忙晕。
解决方案:
随机 TTL:给缓存过期时间加一个随机值,比如 10-15 分钟,避免集中失效。本地锁:当缓存失效时,用 synchronized 先锁住本地线程,只让一个线程去更新缓存,其他线程等待。注意,这只能解决单个实例的问题,分布式场景得用 Redis 分布式锁。场景:双 11 时,某个爆款商品的访问量是其他商品的 100 倍,Caffeine 里全是这个商品的数据,其他数据被挤出去了。
解决方案:
分片处理:把热点数据拆分成多个 key,比如 "product:123:1"、"product:123:2",分散到不同的 Caffeine 实例中。二级缓存限流:给 Caffeine 设置最大容量,超过后按淘汰策略删除,同时记录热点数据,动态调整容量。这是个经典问题,没有绝对正确的答案,得看具体场景:
读多写少:先更新数据库,再删缓存。如果先删缓存,此时有读请求进来,会从数据库查旧数据并更新缓存,导致脏数据。但先更新数据库后删缓存,如果删缓存失败,下次读会读到旧数据,不过可以通过异步任务补偿。写多读少:直接更新数据库,不维护缓存,读的时候再重新加载。比如后台管理系统,写操作多,读操作少,没必要维护缓存。为了验证这对 CP 的威力,我做了一组性能测试,环境如下:
服务器:4 核 8G,带宽 1Gbps客户端:JMeter,1000 并发,10 万次请求数据:1KB 的字符串,热点数据占比 20%指标
单 Redis
Redis+Caffeine
提升比例
平均响应时间
12ms
2ms
83.3%
吞吐量
8000req/s
45000req/s
462.5%
数据库压力
高
极低
-
可以看到,加上 Caffeine 后,响应时间直接降到原来的 1/6,吞吐量翻了 4 倍多,数据库基本没压力了。这就是本地缓存的威力,把大部分请求都在内存里解决了。
策略
缓存命中率
内存占用
复杂度
LRU
85%
中
低
LFU
88%
高
中
TTL+LRU
92%
低
高
实测发现,TTL+LRU 组合命中率最高,因为既考虑了数据的使用频率,又避免了长期不用的数据占用空间。不过复杂度也更高,需要合理设置 TTL 和容量。
秒杀时,热点商品的库存查询请求量极大,用 Caffeine 存最新的库存数据,Redis 存历史库存变化,既能保证速度,又能防止库存超卖。
每个用户的推荐列表都是热点数据,存在 Caffeine 里,快速返回;Redis 存全局的热点文章,当用户的推荐列表更新时,异步同步到 Redis。
风控系统需要实时获取用户的交易数据,Caffeine 存最近 10 分钟的交易记录,Redis 存最近 1 小时的,数据库存全量数据,分层处理,保证风控规则的实时性。
比如实时 PV、UV 统计,Caffeine 存当前分钟的统计数据,每分钟结束后同步到 Redis,Redis 按小时汇总,最后写入数据库,减少数据库压力。
Redis 和 Caffeine 的组合,就像程序员的左右手,左手快速处理日常任务(本地热点),右手搞定复杂问题(分布式存储)。别再让你的系统单打独斗了,赶紧组个 CP,让性能飞起来。
不过,缓存虽好,可不要贪杯哦。一定要根据业务场景选择合适的策略,做好监控和容灾,毕竟再厉害的 CP 也需要用心维护。