智汇 IT
城启新篇

缓存策略实战踩坑手记

上周跟以前在阿里做电商的老陈喝酒,他吐槽去年双11前的糗事——他们当时给首页商品流做缓存,怕扛不住流量,直接把全量商品数据塞了三层缓存,本地堆、Redis、CDN全拉满,算下来QPS扛个百万都没问题。 结果上线第三天就崩了。 不是被流量打崩的。是运营改了个商品标题,缓存没刷干净,一半用户看到的是去年的旧款羽绒服,另一半看到的是刚上的夏装T恤,客诉直接爆了三个小时。他说当时值班的小姑娘抱着电话哭,连喝了三瓶冰镇可乐才缓过来。
电商商品页缓存不一致报错截图
电商商品页缓存不一致报错截图
很多人对缓存策略的误解,就是觉得缓存层数越多越好,键值对设上随机过期时间就万事大吉。哪有那么简单。之前见过有团队给所有接口都套个缓存,连用户每次刷新的实时账户余额都缓存10秒,用户刚转完账看余额还是老数,差点打客服电话报警。

先搞清楚什么数据值得缓存

说实话,不是所有数据都配走缓存。 你得先把手上要存的东西分个类。一类是几百年都不变的,比如网站的备案号、底部的公司介绍,这种甚至直接烧到静态页里就行,犯不上去占Redis的宝贵内存。 另一类是变的频率极低的,比如商品的分类目录、首页的轮播图配置,这种缓存个几小时甚至一天都没问题,就算偶尔延迟个几分钟更新,用户根本感知不到。 最麻烦的是那种变的频率不高不低,但是一变就必须马上让所有用户看到的——比如商品的价格、活动的实时库存。这种才是缓存策略最容易踩坑的地方。 之前有个做社区团购的团队,给商品库存做了缓存,设置了5分钟固定过期。结果某次做秒杀,实际库存剩3件的时候,缓存里显示还有200件,超卖了197单,最后赔了快十万块钱的优惠券。想想都肉疼。

写好缓存失效的兜底逻辑

很多人写缓存的时候,只想着怎么把数据读出来,根本没想过缓存失效了怎么办。 正常的读流程大家都懂:先查本地缓存,没有就查Redis,再没有就去查数据库,查完再塞回缓存。 但这里有个大坑——如果某个热点key突然过期了,瞬间几千个请求同时打到数据库,数据库直接被打懵。 之前我们团队就遇过这种事,当时有个爆款文章的详情页,缓存设了10分钟固定过期,刚好到点的时候,某个短视频平台给带了波流量,瞬间几万请求砸进来,数据库CPU直接冲到99%,卡了快两分钟才缓过来。
服务端热点key失效请求洪峰监控图
服务端热点key失效请求洪峰监控图
那怎么解决?很简单,别搞固定过期时间。比如给每个缓存的过期时间加个随机偏移量,本来应该10分钟过期的,改成10分钟上下浮动2分钟的随机值,就不会出现所有key同时集体过期的情况。 还有更稳妥的做法,就是给访问量特别高的热点key加个永不过期的标记,然后在后台开个单独的异步线程,每隔固定时间去把最新的数据刷到缓存里,根本不让它有失效的空窗期。 哦对,还有那个最烦的缓存不一致的问题。很多人觉得只要在更新数据库的时候,顺手把对应的缓存删了,就万事大吉。哪有那么顺。万一删缓存的时候网络抖了一下,没删掉呢? 那不如加个二次校验。写完数据库之后,先把缓存的值设成一个临时空标记,等个几百毫秒,再重新从数据库读最新的值塞回去。这点延迟,用户根本感觉不到,但是能避免八成的缓存不一致问题。

别为了缓存牺牲核心体验

我见过不少团队为了追求缓存的命中率,把很多本来应该实时返回的用户数据也塞到缓存里。 比如用户的未读消息数、购物车的实时数量。这些东西缓存个几秒,看起来好像省了不少数据库的压力,但是用户体验是真的差。你想啊,用户刚点了个赞,退回去发现未读消息数还是老的,是不是会觉得APP卡成狗? 缓存从来不是性能优化的银弹。 上次老陈他们团队后来改的策略就很实在:所有和用户实时状态相关的数据,一概不做缓存,直接查数据库。非实时的公共数据,才分层做缓存。缓存的过期时间也不搞统一配置,不同的数据按实际的更新频率单独设。 就这么改完之后,他们去年双11扛住了平时12倍的流量,客诉率反而比前一年降了40%。 对吧?技术从来不是越复杂越好。很多时候你把那些花里胡哨的冗余缓存砍掉,把核心的失效逻辑做扎实,比你堆再多的中间件都管用。 前阵子我整理之前踩过的缓存坑,发现十次有八次的问题,根本不是缓存技术本身不行,是一开始就想错了——把缓存当成了性能救命的万能药,没搞清楚什么数据该存,什么逻辑该兜底。 毕竟嘛,缓存本质上就是拿空间换时间的买卖。你算不清这笔账的时候,与其硬堆服务器配置,不如先坐下来把要存的东西捋明白。
免责声明:市场有风险,选择需谨慎!此文仅供参考,不作买卖依据。如有侵权请联系删除。
文章名称:缓存策略实战踩坑手记
文章链接:https://www.itcdj.com/it/407.html