行,但需权衡数据更新频率与一致性要求;高频低更主键查询如select * from user where id = 123适合缓存,而高实时性场景易引发脏读或雪崩。

MySQL查得慢,直接上Redis缓存行不行?
行,但不是所有查询都适合缓存。关键看数据更新频率和一致性要求:如果一条订单记录每秒被修改多次,又要求实时可见,那缓存反而会拖慢响应、引发脏读。SELECT * FROM user WHERE id = 123 这类高频、低更新、强主键的查询,才是Redis缓存的甜点区。
常见错误现象:Cache stampede(缓存雪崩)——大量请求同时发现缓存失效,全打到MySQL;或者stale read(读到过期数据)——缓存没及时删,用户看到旧余额。
- 缓存前先确认业务能否容忍秒级延迟(比如商品详情页可接受,支付结果页不可)
- 用
GET user:123查缓存,命中就返回;不命中再查MySQL,然后SET user:123 <data> EX 300</data>写入5分钟过期 - 避免用
SELECT *缓存整行——只缓存前端真正需要的字段,减少序列化开销和内存占用
缓存键怎么设计才不容易冲突或难维护?
键名不是随便拼的,它直接影响缓存隔离性、可读性和清理效率。用user_123不如user:id:123,后者能一眼看出类型和维度,也方便用KEYS user:id:*批量操作(生产环境慎用KEYS,建议用SCAN)。
常见错误现象:user:123 和 order:123 冲突(ID重复)、user_123_v2上线后老缓存不自动淘汰、键里带空格或特殊字符导致redis-cli解析失败。
- 统一格式:
<domain>:<type>:<id></id></type></domain>,例如product:sku:A12345 - ID必须做标准化处理:字符串ID要保留原样,数字ID别转成浮点(
123.0≠123) - 涉及多条件查询(如
SELECT * FROM article WHERE status=1 AND tag='tech' ORDER BY created_at DESC LIMIT 10),键里要包含所有影响结果的参数:article:list:status:1:tag:tech:page:1
MySQL数据改了,Redis缓存怎么同步?
没有银弹方案,只有权衡。最常用的是「写穿透 + 延迟双删」:应用层先删DEL product:sku:A12345,再更新MySQL,最后再删一次(防中间态脏数据)。比「更新缓存」更安全,因为删操作幂等,而更新可能因并发写乱序出错。
常见错误现象:只删不更新,下次读触发回源,但回源查到的是旧数据(事务未提交);或者用EXPIRE依赖过期自动清理,结果缓存时间设太长,用户长时间看不到新内容。
- 删除时机卡在MySQL事务提交后,不是执行SQL后——否则事务回滚,缓存已删,数据丢失
- 对高一致性场景(如库存),删缓存后加个短延时(100ms)再删第二次,覆盖主从延迟窗口
- 避免监听binlog做异步删——开发成本高,且Redis删失败无重试机制,容易漏
缓存命中的时候,怎么避免JSON序列化/反序列化拖慢PHP/Python?
序列化不是瓶颈本身,而是它暴露了结构设计问题。如果每次都要json_decode($redis->get('user:id:123')),说明你存的是通用JSON字符串;换成Redis Hash结构,用HGETALL user:id:123,PHP的redis->hGetAll()直接返回关联数组,零解析开销。
常见错误现象:Python里用pickle存对象,换版本后反序列化失败;或缓存大JSON(>100KB),网络传输+CPU解码双双吃紧。
- 简单对象优先用
HSET user:id:123 name "Alice" email "a@b.com",字段少时比JSON更省空间 - 必须用JSON时,PHP选
json_encode($data, JSON_UNESCAPED_UNICODE)减少体积;Python用ujson替代json库,快2–3倍 - 缓存值超50KB,先想是不是该拆分——比如把
user_profile和user_settings分开缓存,按需加载
缓存不是开关一开就完事,最麻烦的永远是“什么时候失效”和“失效时谁来负责”。线上跑着的缓存逻辑,八成问题出在边界没想全:主从延迟、事务回滚、批量更新漏删、缓存击穿没加互斥锁。这些地方不埋点、不压测,等流量上来就只能看监控抓狂。











