• 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 删除缓存”场景的解决方案。但该方案并不能彻 底解决数据不一致的状况,其只可能降低发生数据不一致的概率。

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

  • 相关阅读:
    wireshark——解密加密报文
    picoctf_2018_can_you_gets_me
    前端分片和生成md5方法
    JDK21新特性
    机器学习算法——分类问题1(类别不平衡问题--欠采样方法)
    阿里云优惠券(代金券)免费领取方法及使用教程分享
    mac-“准备安装时发生错误,请尝试重新运行此应用程序” + mac未能安装所需的固件更新
    分享记账软件 设置账本密码防止收支被他人修改
    MySQL性能优化实践:SQL查询优化之使用只读索引、IN方法和临时表分批查询(附加:索引的创建删除命令)
    【Node.js】Node.js入门(七):Express接口覆盖、模板引擎、错误处理、调试
  • 原文地址:https://blog.csdn.net/dougongzi/article/details/132723000