高并发架构 --- 缓存相关问题解析

0、热点数据集中失效问题redis

说明:对于一些热点的数据来讲,当缓存失效之后会存在大量的请求过来,而后打到数据库去,从而可能致使数据库崩溃的状况。数据库

解决方案:一、设置不一样缓存时间,好比在一个基础的时间上加上或者减去一个范围内的随机值。缓存

     二、第一个请求去查询数据库的时候对他加一个互斥锁,其他的查询请求都会被阻塞住,直到锁被释放,从而保护数据库。可是也是因为它会阻塞其余的线程,此时系统吞吐量会降低。安全

一、缓存穿透并发

说明:缓存穿透是指查询一个必定不存在的数据,因为缓存是不命中时被动写的,而且出于容错考虑,若是从存储层查不到数据则不写入缓存,这将致使这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在的key频繁攻击咱们的应用,这就是漏洞。高并发

解决方案:有不少种方法能够有效地解决缓存穿透问题工具

     一、最多见的则是采用布隆过滤器,将全部可能存在的数据哈希到一个足够大的bitmap中,一个必定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。spa

     二、另外也有一个更为简单粗暴的方法(咱们采用的就是这种),若是一个查询返回的数据为空(不论是数 据不存在,仍是系统故障),咱们仍然把这个空结果进行缓存,但它的过时时间会很短,最长不超过五分钟。线程

 

二、缓存雪崩设计

说明:缓存雪崩是指在咱们设置缓存时采用了相同的过时时间,致使缓存在某一时刻同时失效,请求所有转发到DB,DB瞬时压力太重雪崩。

解决方案:一、缓存失效时的雪崩效应对底层系统的冲击很是可怕。大多数系统设计者考虑用加锁或者队列的方式保证缓存的单线 程(进程)写,从而避免失效时大量的并发请求落到底层存储系统上。这里分享一个简单方案就时讲缓存失效时间分散开,好比咱们能够在原有的失效时间基础上增长一个随机值,好比1-5分钟随机,这样每个缓存的过时时间的重复率就会下降,就很难引起集体失效的事件。

     二、事前:这种方案就是在发生雪崩前对缓存集群实现高可用,若是是使用 Redis,可使用 主从+哨兵 ,Redis Cluster 来避免 Redis 全盘崩溃的状况。

     三、事中:使用 Hystrix进行限流 & 降级 ,好比一秒来了5000个请求,咱们能够设置假设只能有一秒 2000个请求能经过这个组件,那么其余剩余的 3000 请求就会走限流逻辑。而后去调用咱们本身开发的降级组件(降级),好比设置的一些默认值呀之类的。以此来保护最后的 MySQL 不会被大量的请求给打死。

     四、过后:开启Redis持久化机制,尽快恢复缓存集群

 

 

三、缓存击穿

说明:对于一些设置了过时时间的key,若是这些key可能会在某些时间点被超高并发地访问,是一种很是“热点”的数据。这个时候,须要考虑一个问题:缓存被“击穿”的问题,这个和缓存雪崩的区别在于这里针对某一key缓存,前者则是不少key。

解决方案:一、使用互斥锁:业界比较经常使用的作法,是使用mutex。简单地来讲,就是在缓存失效的时候(判断拿出来的值为空),不是当即去load db,而是先使用缓存工具的某些带成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操做返回成功时,再进行load db的操做并回设缓存;不然,就重试整个get缓存的方法。

来个示例代码

 

public String get(key) {
      String value = redis.get(key);
      if (value == null) { //表明缓存值过时
          //设置3min的超时,防止del操做失败的时候,下次缓存过时一直不能load db
          if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //表明设置成功
               value = db.get(key);
                      redis.set(key, value, expire_secs);
                      redis.del(key_mutex);
              } else {  //这个时候表明同时候的其余线程已经load db并回设到缓存了,这时候重试获取缓存值便可
                      sleep(50);
                      get(key);  //重试
              }
          } else {
              return value;      
          }
 }

对比其他解决方案

 

 

总结

 

针对业务系统,永远都是具体状况具体分析,没有最好,只有最合适。

 

最后,对于缓存系统常见的缓存满了和数据丢失问题,须要根据具体业务分析,一般咱们采用LRU策略处理溢出,Redis的RDB和AOF持久化策略来保证必定状况下的数据安全。

相关文章
相关标签/搜索