现在的软件一般都有redis缓存的应用,缓存的作用就是减少数据库的查询,提升系统的性能。
一般的请求执行流程:从客户端发送请求,首先先在redis中查询当前数据是否在缓存中,若存在的话,直接返回,若不存在,就会检索数据库,如果数据库中存在对应的数据,就会更新缓存并返回结果,若数据库中不存在数据,返回空或者错误。
热key:用户访问量高,高并发集中对一个点进行访问。
缓存击穿
概念
单个热key,在不停的扛着大并发,在这个key失效的瞬间,持续的大并发请求就会击破缓存,直接请求到数据库,这种情况就是缓存击穿。缓存击穿和缓存缓存雪崩是类似的,只不过前者是单个key失效,后者是多个key同时失效。
解决方法
- 使用互斥锁,只让一个线程构建缓存,其他线程等待构建缓存执行完毕,重新从缓存中获取数据。
- 对于热key,不设置过期的时间。
- 使用分布式锁,在缓存快失效的时候,不立刻去查询数据库,在value的内部设置一个比缓存过期时间更短的时间标识,当异步线程发现该值快要过期的时候,拿上重置这个时间,并且重新从数据库中加载数据,保存到缓存中去。
缓存穿透
概念
缓存穿透指的是数据既不在缓存中,也不在数据库中,每次进行请求的时候都需要查询数据库,这样的话就会使性能降低,缓存就会失去其意义。如果这时一直向服务端发送不存在的数据,每条数据都要进行查询,就会导致数据库的崩溃。
解决方法
- 对空值进行缓存(null或默认值):无论查询的数据是否存在,都对该结果进行缓存处理,其过期时间会非常短。
- 业务合法性校验:在业务的请求入口处进行数据的合法性校验,校验数据是否合理,是否含有非法值。针对非合理数据进行判断。
- 实时监控:对于redis缓存命中率急速下降的时候,进行监控排查,排查访问对象和访问的数据,并设置为黑名单。
- 采用布隆过滤器(Bloom Filter):可以判断请求的数据是否存在,避免直接查询数据库,减轻数据库的压力。使用布隆过滤器可以更高效的插入和查询,而且占用的空间资源会更少。布隆过滤器相当于设置白名单,请求的时候发现缓存中无对应的数据,可以先通过布隆过滤器判断数据是否在白名单内,如果不在的话,就会直接返回空或者失败。
缓存雪崩
概念
缓存雪崩指的是,在某一情况下,缓存不可用,导致大量的请求直接打到了数据库上,最终由于数据库的压力过大可能导致系统崩掉, 缓存不可用一般指的是以下两个方面:
- 缓存服务器宕机,系统将请求直接打到了数据库上。
- 缓存数据突然大范围的集中过期失效,导致大量请求打到数据库上重新加载数据。
缓存击穿与雪崩的区别是:前者针对某一个key,后者针对的是很多key缓存。
解决方法
-
给缓存的过期时间设置上随机数,避免缓存同时过期。
-
构架多级缓存架构:nginx+redis+其他缓存
-
设置过期标志对缓存进行更新:如果过期会触发通知另外的线程在后台去更新实际key的缓存。
-
缓存服务采用集群方式:比如redis的主从复制集群,这样就可以降低宕机的概率。
-
缓存永不过期,这个感觉不太好,一般不建议使用。
-
互斥锁:同一时间只让一个线程构建缓存,其他线程阻塞排队。
-
双Key策略:对缓存数据可以使用两个key,一个是主key,设置过期时间,一个是备份的key,不设置过期时间,只是key不一样,但是value值是一样的,相当于给缓存数据做了一个副本。
当业务线程访问不到主key数据的时候,就会直接返回备用key的缓存数据。
在更新缓存的时候同时更新主key和备份的key。
redis主从集群
redis的主从复制集群会在之后详细讲述,下面这个有助于进行理解。
哨兵模式
redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复,哨兵的模式结构如下:
- Sentinel会不断的进行监听和检查master和slave是否正常的进行工作。
- 自动故障恢复:当master故障后,哨兵会将一个slave提升为master,当故障实例恢复后也以新的master为主。
- 通知:哨兵的主要作用就是监听服务是否正常,当集群发生故障转移的时候,会发送信息给redis的客户端。
心跳机制
Sentinel基于心跳机制检测服务,每隔1s向集群的每一个实例发送ping命令,就是看它是否还活着。
- 主观下线:如果某个哨兵节点发现某个实例未在规定的响应时间内,就认为该实例主观下线。
- 客观下线:若超过指定数量的哨兵都认为该实例主观下线,则认为该实例客观下线。
参考博文:https://blog.csdn.net/cristiadol/article/details/125418289