Redis缓存的高并发问题

Redis 做缓存虽减轻了 DBMS 的压力,减小了 RT,但在高并发情况下也是可能会出现各 种问题的。

1 缓存穿透

当用户访问的数据既不在缓存也不在数据库中 时,就会导致每个用户查询都会"穿透" 缓存"直抵 "数据库。这种情况就称为缓存穿透 。一个两个请求无所谓,当高并发的访问 请求到达时,缓存穿透不 仅增加了响应时间 ,而且还会引发对 DBMS 的高并发查询,这种高并发查询很可能会导致DBMS 的崩溃。
缓存穿透产生的主要原因 有两个:一是在数据库中没有相应的查询结果 ,二是查询结果为空 时,不对查询结果进行缓存。所以,针对以上两点,解决方案也有两个:
 对非法请求进行限制 。
 对结果为空的查询给出默认值 。

可以使用布隆过滤器解决缓存穿透的问题

  • 把已存在数据的key存在布隆过滤器中,相当于redis前面挡着一个布隆过滤器。
  • 当有新的请求时,先到布隆过滤器中查询是否存在:
  • 如果布隆过滤器中不存在该条数据则直接返回;
  • 如果布隆过滤器中已存在,才去查询缓存redis,如果redis里没查询到则再查询Mysq|数据库

2 缓存击穿

  • 对于某一个缓存 ,在高并发 情况下若其访问量特别巨大,当该缓存的有效时限到达时(即刚好达到设置的时间,此数据在缓存消失了 (key到期了),此时大量用户来访问它), 可能会出现大量 的访问都要重建该缓存
  • 即这些访问请求发现缓存中没有该数据 ,则立即到DBMS 中进行查询,那么这就有可能会引发对 DBMS 的高并发查询 ,从而接导致 DBMS 的崩 溃
  • 这种情况称为缓存击穿 ,而该缓存数据称为热点数据 。 对于缓存击穿的解决方案,较典型的是使用"双重检测锁"机制。 类似于高并发下安全的单例

3 缓存雪崩

对于缓存中的数据,很多都是有过期时间的。

  • 大量缓存的过期时间在同一很短的时间 段内几乎同时到达,那么在高并发访问场景下就可能会引发对 DBMS 的高并发查询,而这将 可能直接导致 DBMS 的崩溃。这种情况称为缓存雪崩。
  • 对于缓存雪崩没有很直接的解决方案,最好的解决方案就是预防,即提前规划好缓存的 过期时间。要么就是让缓存永久有效,当 DB 中数据发生变化时清除相应的缓存。
  • 如果 DBMS采用的是分布式部署,则将热点数据 均匀分布在不同数据库节点中,将可能到来的访问负载均衡开来。

解决办法

事前:尽量保证整个 Redis 集群的高可用性,发现机器宕机尽快补上,选择合适的内存淘汰策略。

事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL崩掉, 通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

事后:利用 Redis 持久化机制保存的数据尽快恢复缓存

4 数据库缓存双写不一致

以上三种情况都是针对高并发 场景中可能会出现的问题,而数据库缓存双写不一致问 题,则是在高并发写场景下可能会出现的问题。 对于数据库缓存双写不一致问题,以下两种场景下均有可能会发生:

1 "修改 DB 更新缓存 "场景

对于具有缓存 warmup 功能的系统,DBMS 中常用数据的变更,都会引发缓存中相关数 据的更新。在高并发写请求 场景下,若多个请求要对 DBMS 中同一个数据进行修改 ,修改后 还需要更新缓存 中相关数据,那么就有可能会出现缓存与数据库中数据不一致的情况。


第一种没有问题。

第二种:a修改DB中的数据后stock=7,刚想从本地缓存 写入redis缓存,此时出问题了(有可能是时间片到了也有可能redis出现问题),这是b过来了,也修改了数据stock=2,然后更新缓存也是2,然后出现问题的a请求又好了,更新redis stock为7。(覆盖了2)

解决方案:

最经典的缓存+数据库读写的模式,就是 预留缓存模式Cache Aside Pattern。

  • 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
  • 更新的时候,先删除缓存 ,然后再更新数据库,这样读的时候就会发现缓存中没有数据而直接去数据库中拿数据了。

题外话:

本地缓存Redis缓存是两种不同的缓存方式。
本地缓存是指将数据缓存在本地内存 中,通常使用内存缓存库(如Memcached、Ehcache等)来实现。本地缓存的优点是访问速度快,缓存的数据可以快速地被读取,同时数据在本地内存中,可以减轻数据库的压力。然而,本地缓存的缺点是容易受到服务器重启、应用重启等因素的影响,同时可用空间有限。
Redis缓存是一种基于内存的(也可以持久化到磁盘)键值对存储系统,具有高性能、高可用性和可扩展性等优点。Redis可以作为分布式缓存来使用,可以减轻数据库的压力并提高应用程序的响应速度。Redis还提供了多种数据结构,如字符串、哈希、列表、集合和有序集合等,还可以设置过期时间,可以满足复杂的应用场景。

相比之下,本地缓存通常只适用于单机环境,适用于只有一个应用程序使用的数据,而Redis适用于分布式、多应用程序场景下的数据缓存。虽然Redis的性能和可用性优于本地缓存,但是使用Redis也需要考虑到数据一致性、网络延迟等问题。因此,具体的缓存方案应该根据应用场景来选择。

2 "修改 DB 删除缓存 "场景

在很多系统中是没有缓存 warmup 功能的,为了保持缓存与数据库数据的一致性,一般 都是在对数据库执行了写操作后,就会删除相应缓存。

在高并发读写请求 场景下,若这些请求对 DBMS 中同一个数据 的操作既包含写也包含读 , 且修改后还要删除缓存中相关数据,那么就有可能会出现缓存与数据库中数据不一致的情况。

问题:

  • b先查询 redis中无数据 ,到DB查为10,然后写入本地缓存,此时出现问题中断了。
  • 然后a过来修改DB中的数据,并将redis中相关数据删除。
  • 然后b恢复执行,将本地缓存的10写入redis。

3) 解决方案:延迟双删

延迟双删方案是专门针对于"修改 DB 删除缓存"场景的解决方案。但该方案并不能彻 底解决数据不一致的状况,其只可能降低发生数据不一致的概率。

延迟双删方案是指,在写操作完毕后会立即执行一次缓存的删除 操作,然后再停上一段 时间 (一般为几秒)后再进行一次删除 。而两次删除中间的间隔时长,要大于一次缓存写操作的时长。

相关推荐
掘金-我是哪吒36 分钟前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
ketil273 小时前
Ubuntu 安装 redis
redis
王佑辉4 小时前
【redis】redis缓存和数据库保证一致性的方案
redis·面试
Karoku0664 小时前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
gorgor在码农5 小时前
Redis 热key总结
java·redis·热key
想进大厂的小王5 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
Java 第一深情5 小时前
高性能分布式缓存Redis-数据管理与性能提升之道
redis·分布式·缓存
minihuabei10 小时前
linux centos 安装redis
linux·redis·centos
monkey_meng12 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
hlsd#12 小时前
go 集成go-redis 缓存操作
redis·缓存·golang