Redis 缓存
缓存问题
Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃
本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死
缓存穿透
缓存穿透是指用户请求的数据在缓存中不存在即没有命中,同时在数据库中也不存在,导致用户每次请求该数据都要去数据库中查询一遍,然后返回空
- 布隆过滤器
布隆过滤器(Bloom Filter,简称BF),是一种空间效率高的概率型数据结构,用来检测集合中是否存在特定的元素
布隆过滤器由一个长度为m比特的位数组(bit array)与k个哈希函数(hash function)组成的数据结构。位数组初始化均为0,所有的哈希函数都可以分别把输入数据尽量均匀地散列。当要向布隆过滤器中插入一个元素时,该元素经过k个哈希函数计算产生k个哈希值,以哈希值作为位数组中的下标,将所有k个对应的比特值由0置为1
当要查询一个元素时,同样将其经过哈希函数计算产生哈希值,然后检查对应的k个比特值:如果有任意一个比特为0,表明该元素一定不在集合中;如果所有比特均为1,表明该集合有可能性在集合中(哈希碰撞)
- 返回空对象
当缓存未命中,查询持久层也为空,可以将返回的空对象写到缓存中。为了避免存储过多空对象,通常会给空对象设置一个过期时间
缓存击穿
缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库
- 使用互斥锁(mutex key)
让一个线程回写缓存,其他线程等待回写缓存线程执行完,重新读缓存
- 热点数据永不过期
针对热点key不设置过期时间,或者把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建
缓存雪崩
缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,请求直接落到数据库上
- 均匀过期 设置不同的过期时间,让缓存失效的时间点尽量均匀。通常可以为有效期增加随机值或者统一规划有效期
- 双层缓存策略
- 加互斥锁
- 缓存永不过期
缓存预热
缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统
缓存降级
缓存降级是指缓存失效或缓存服务器挂掉的情况下,不去访问数据库,直接返回默认数据或访问服务的内存数据
Redis的内存淘汰机制
maxmemory 0
,在64位操作系统下最大内存为操作系统剩余内存
淘汰策略
- noeviction 默认策略,对于写请求直接返回错误,不进行淘汰
- allkeys-lru 从所有的key中使用近似LRU算法(最近最少使用)进行淘汰
- volatile-lru 从设置了过期时间的key中使用近似LRU算法进行淘汰
- allkeys-random 从所有的key中随机淘汰
- volatile-random 从设置了过期时间的key中随机淘汰
- volatile-ttl 在设置了过期时间的key中根据key的过期时间进行淘汰,越早过期的越优先被淘汰
- allkeys-lfu 从所有的key中使用近似LFU算法(最少使用频率)进行淘汰
- volatile-lfu 设置了过期时间的key中使用近似LFU算法进行淘汰
缓存更新机制
Cache aside 旁路缓存
读请求:应用首先会判断缓存是否有该数据,缓存命中直接返回数据,缓存未命中即缓存穿透到数据库,从数据库查询数据然后回写到缓存中,最后返回数据给客户端 写请求:首先更新数据库,然后从缓存中删除该数据
更新缓存的时间要远大于数据库,故如果读请求早于写请求读到数据库的旧值,则会更早地把旧值写到缓存中,紧接着,写请求从缓存删除该旧值
- 先更新数据库,再更新缓存:写请求冲突,旧的写请求会在更新缓存时覆盖新的写请求
- 先删缓存,再更新数据库(或先更新数据库,再删除缓存):旧的读请求会在新的写请求删完缓存中的旧值之后,又写入自己读取到的旧值
Read/Write through
将数据库的同步委托给缓存提供程序Cache Provider
Write behind/back
即延迟写入
,应用程序更新数据时只更新缓存,Cache Provider每隔一段时间将数据刷新到数据库中