Redis真的比MySQL快吗?聊聊那些被忽略的Redis性能陷阱

🔑 关键词:Redis性能,Redis缓存,Redis面试,Redis持久化,内存数据库

📖 摘要:深入对比Redis与MySQL的真实性能差异,分享实践中遇到的Redis变慢的坑,以及独立的技术观点。

很多人一提到Redis,脑子里闪过的第一个词就是“快”。确实,官方性能报告里单实例读写可以轻松破10万QPS,但这只是理想数字。我自己做压测时发现,当value大小从几百字节涨到几十KB,Redis的吞吐量直接腰斩再腰斩。原因很朴素,它虽然把数据放在内存里,但内存到网络缓冲区之间的数据拷贝、JSON序列化开销根本没省掉。反倒是MySQL,在大量小查询场景下,Buffer Pool命中后也就一两微秒,和Redis差距远没有想象中大。

图片

再说一个反直觉的体验:Redis单线程模型在普通请求下确实很稳,但一旦你的zset里有几千个元素,再加个ZREVRANGEBYSCORE,那一瞬间其他所有redis客户端都会卡住。我排查过一个线上事故,就是用ZSET做排行榜,每次读全量Top50,高峰期Redis CPU直接被一条复杂命令占满,队列里堆积的请求全在等。这才意识到所谓“快”是有限定条件的,慢命令才是单线程最大的敌人。这也解释了为什么Redis官方后来引入Lua脚本时,也要警告你脚本别做耗时操作。

图片

持久化对性能的影响也常被忽略。我见过一个项目为了追求数据安全,开了AOF everysec加RDB,结果每过几个小时Redis就会抖一下。当时监控显示延迟波动巨大,最后定位到是RDB fork子进程时,内存页表拷贝耗了快一秒。当实例的数据量到几十GB时,fork不是微秒级操作了。相比之下,MySQL的InnoDB在刷脏页时有自适应机制,虽然运行曲线也不太平滑,但起码它不会因为一个随机快照把整个服务堵住。有时候我会跟人讲,Redis的持久化设计更像是一个“缓存变慢的bug源”,而不是真正的存储层。

图片

我的观点可能跟主流不太一样:Redis的价值从来不是“快”,而是它的数据结构。就算你换用Memcached,同样的缓存写读也差不了太多。真正不可替代的是那套list、hash、set、zset的操作原语,让业务逻辑可以围绕内存模型直接展开。比如秒杀场景,用list做队列,用zset做时间排序,比用MySQL拼SQL高效得多。所以设计上应该把Redis当成一个“功能引擎”,而不是一把万能的钥匙。我见过太多团队只用它做string缓存,结果既没利用到特性,又得额外处理过期、淘汰、雪崩问题,最后还怪它不稳定。

图片

最后一个提醒:Redis的过期淘汰并不是即时发生的,它在主线程里周期随机抽样,遇到大key惰性删除还会卡一下。我自己踩过坑,设置了过期时间12小时,但内存持续增长,后来才发现是大量写入触发了内存淘汰,而不是主动过期。真实项目里,你得把maxmemory、淘汰策略、键值大小、公平调度都设计好,才能接近文档里那个“快”字。否则它就是个脆皮内存进程,压垮它只需要一条慢命令或一个忘了处理的key。

图片