redis缓存

本质

大量查询直接打到后面的数据库,方法如下:

  • 提高容灾能力
  • 限制查询的数量

针对某个key的大量查询,导致缓存击穿

  • 加锁,一次只能一个现场访问数据库,将访问结果放到缓存,后面的查询走缓存

大量key击穿缓存:缓存雪崩

  • 启动限流
  • 提高集群的性能

缓存穿透

什么是缓存穿透?
一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。【感觉应该用的不多吧】

开发提示:
有关布隆过滤器的相关知识,可以参考:https://en.wikipedia.org/wiki/Bloom_filter
可以利用 Redis 的 Bitmaps 实现布隆过滤器,GitHub 上已经开源了类似的方案,读者可以进行参考:
https://github.com/erikdubbelboer/Redis-Lua-scaling-bloom-filter

BloomFilter
类似于一个hbase set 用来判断某个元素(key)是否存在于某个集合中。
这种方式在大数据场景应用比较多,比如 Hbase 中使用它去判断数据是否在磁盘上。还有在爬虫场景判断url 是否已经被爬取过。
这种方案可以加在第一种方案中,在缓存之前在加一层 BloomFilter ,在查询的时候先去 BloomFilter 去查询 key 是否存在,如果不存在就直接返回,存在再走查缓存 -> 查 DB。
流程如下:
2016-11-25 12 12 28

缓存雪崩

什么是缓存雪崩?
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

如何避免?

事前

  • 保证缓存层服务高可用性(多个节点)
  • 不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
  • 从缓存层面来看,不设置过期时间,每个 value 设置一个逻辑过期时间
  • 可以通过缓存reload机制,预先去更新缓存,再即将发生大并发访问前手动触发加载缓存
  • 做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
  • 提前演练

事中:

  • ehcache本地缓存 + Hystrix限流&降级,避免MySQL被打死

事后

  • 在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 依赖隔离组件为后端限流并降级

缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样避免,用户请求的时候,再去加载相关的数据。

解决思路:

  1. 直接写个缓存刷新页面,上线时手工操作下。
  2. 数据量不大,可以在WEB系统启动的时候加载。
  3. 定时刷新缓存

缓存数据的淘汰

缓存淘汰的策略有两种: (1) 定时去清理过期的缓存。 (2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂,具体用哪种方案,大家可以根据自己的应用场景来权衡。

淘汰机制

  • LRU
  • TTL

Redis数据淘汰机制

参考

缓存穿透与缓存雪崩
Redis架构之防雪崩设计:网站不宕机背后的兵法