当前位置:首页 > 问答 > 正文

Redis在高并发下的那些事儿,性能到底怎么提升的呢?

主要综合自互联网技术社区如CSDN、博客园、InfoQ等平台的常见讨论和Redis官方文档的实践建议)

Redis在高并发场景下确实是个利器,但用不好也容易出问题,咱们就聊聊它可能遇到的坎儿,以及怎么迈过去。

高并发下Redis容易遇到的“事儿”

高并发来的时候,最直接的压力就是大量的读写请求涌向Redis,如果Redis扛不住,第一个表现就是响应变慢,请求超时,这背后可能有好几个原因。

一个是缓存穿透,这指的是用户疯狂请求一个数据库中根本不存在的数据,有人故意请求一个ID为-1的商品,Redis里肯定没有,这个请求就会直接打到后端的数据库上,如果这种恶意请求非常多,数据库压力巨大,可能就直接被拖垮了,这就像一群人不停地问你一个你根本不知道答案的问题,你每次都得去翻书(查数据库),很快就累趴下了。

另一个是缓存击穿,这个更危险,它指的是一个热点key(比如某个秒杀商品的信息)在某个时刻过期了,就在这时,海量的并发请求发现缓存失效,全部涌向数据库,瞬间就把数据库打穿了,这个key就像防洪大坝上的一个关键闸门,闸门一开,洪水瞬间冲垮下游。

还有一个是缓存雪崩,这是缓存击穿的升级版,不是说某一个key失效,而是大量的key在同一时间段内集中失效,或者Redis服务本身直接宕机了,这就好比大坝不是开了一个闸门,而是整个坝体出现了裂缝,导致大量数据请求像雪崩一样砸向数据库,后果可想而知。

除了这些缓存本身的问题,大key和热key也是性能杀手。大key指的是一个key对应的value非常大,比如一个包含了几十万个元素的List或Hash,在读取、删除这个key时,会耗费大量内存和网络带宽,导致操作延迟增高,甚至可能阻塞Redis的其他请求。热key指的是某个key被访问的频率极高,所有的请求都集中打在一台Redis服务器的一个数据分片上,导致该分片CPU负载极高,成为整个系统的瓶颈。

性能到底怎么提升?

面对这些问题,提升性能的思路就是“预防”和“优化”双管齐下。

解决缓存穿透: 核心思路是不让无效请求打到数据库,一个简单的方法是,如果查数据库发现数据不存在,也在Redis里缓存一个空值(比如null),并设置一个较短的过期时间,这样后续的相同请求在Redis层面就直接返回空值了,更高级一点可以用布隆过滤器(Bloom Filter) 这种数据结构,在访问Redis之前先过一遍布隆过滤器,如果判断数据肯定不存在,就直接返回,有效拦截大部分恶意请求。

解决缓存击穿和雪崩: 对于缓存击穿,要对热点key的过期时间管理得更精细,可以设置逻辑过期时间,即key本身不过期,但value里存一个过期时间戳,当发现数据逻辑上过期时,只允许一个请求去数据库加载新数据,其他请求继续使用旧数据并等待,这通常需要用Redis的SETNX命令(或Lua脚本)来实现互斥锁,防止大量请求同时重建缓存。 对于缓存雪崩,关键是避免大量key同时失效,可以在设置key的过期时间时,在原定过期时间的基础上,加上一个随机的短时间(比如1-5分钟),让key的失效时间点均匀分布,避免集体失效。

应对大key和热key: 大key要进行拆分,比如一个大的Hash可以按字段前缀拆成多个小的Hash,或者对于List/Set,在业务允许的情况下进行分片存储。 热key的解决方案主要是分散压力,可以通过在业务层做本地缓存(如Guava Cache, Caffeine),降低对Redis的访问频率,更根本的方法是做数据备份,即把一个热key复制多份,比如原本叫product:1001,可以多存几份叫product:1001:copy1product:1001:copy2,访问时随机选一个,把压力分摊开。

架构和配置层面的优化:

  • 使用连接池:避免频繁创建和关闭连接的开销,使用连接池复用连接。
  • 升级硬件/使用更高效数据结构:使用更快的CPU、更大内存,或者使用更节省内存的数据结构(比如用Hash代替多个String)。
  • 持久化策略选择:根据业务对数据安全性和性能的要求,权衡RDB和AOF两种持久化方式,在超高并发写场景下,可以牺牲一部分数据安全性(比如降低AOF刷盘频率)来换取更高的写入性能。
  • 搭建集群:当单实例性能达到瓶颈时,必须使用Redis Cluster或Codis等方案进行分片集群部署,将数据分散到多个节点上,实现水平扩展,这是应对极高并发最有效的手段。

Redis在高并发下表现好坏,很大程度上取决于如何使用它,理解了可能遇到的问题,并针对性地采取预防和优化措施,才能让它真正成为支撑高并发系统的稳定基石。

Redis在高并发下的那些事儿,性能到底怎么提升的呢?