文章目录
缓存的处理流程
请求数据时,先从缓存中取数据,取到就返回结果,没有则从数据库中取,数据库取到后更新缓存,并返回结果,数据库中没有数据,那就返回空结果。
1. 缓存穿透
通俗地说缓存穿透就是用户对不存在的数据发起请求.比如用户请求 id = -1 的数据,缓存中当然不会有这条数据, 那就只能去数据库查找,而数据库也不会有,只能全表扫描. 当用户不断发起该类请求,那就很可能是攻击者, 攻击会导致数据库压力过大.
解决方法:
- 对请求进行过滤校验, 对 id<=0 的不合法请求直接拦截, 可使用布隆过滤器.
- 对不存在的数据缓存一个空数据,如果在缓存和数据库中都找不到请求的数据,就返回这个空数据.
Reference: 布隆过滤器
原理是对一个key进行k个不同hash算法获取k个值,在比特数组中将这k个值在数组中的下标置为1,查的时候如果某个key的在数组中k个位置都为1,那么布隆过滤器判断该key可能存在(并不一定存在)。
布隆过滤器可能会误判,如果它说不存在那肯定不存在,如果它说存在,那数据有可能实际不存在.
例如: 比特数组 Bytearray 大小为 16, 则其原始数据为 [ 0000 0000 0000 0000 ].
- 添加:
对 “Hello” 经过 2 个不同hash算法获得在该数组中两个下标(3,5), 则比特数组改变为 [0001 0100 0000 0000], 下标位置Bytearray[3] = 1, Bytearray[5] = 1.- 查找:
对 “Hello” 经过 2 个不同hash算法获得值为(3,5),去查找Bytearray[3] 和 Bytearray[5] 的值, 都为1, 则可能存在. 因为下标 Bytearray[3] 和 Bytearray[5]等于1可能是其他元素经过hash 留下的标记, 故 “Hello” 实际可能不存在.
由上可知,如果每个元素k次hash后在数组中的下标都不相同, 则可认为布隆过滤器的准确率为 100%.
Bloom Filter的核心思想
- 多个hash,增大随机性,减少hash碰撞的概率.
- 扩大数组范围,使hash值均匀分布,进一步减少hash碰撞的概率.
Google 的开源工具
Guava
中包含了 Bloom Filter 实现,另外传统的布隆过滤器只能添加数据不能删除数据,其变种Counting Bloom Filter
给Bloom Filter增加了删除操作,代价是多占用几倍存储空间
Counting Bloom Filter
的思想是将标准 Bloom Filter 位数组的每一位扩展为一个小的计数器(Counter),在插入元素时给对应的 k(k为哈希函数个数)个 Counter 的值分别加1,删除元素时给对应的 k 个Counter 的值分别减1
2. 缓存击穿
缓存击穿是指缓存中没有但数据库中有的单条数据(通常由缓存过期造成)被并发查询,并发请求非常多,同时读缓存没有读到又同时去读数据库,造成数据库压力过大.
解决方法:
- 设置热点数据永不过期.
- 加互斥锁,读数据库时需要获取锁,一条请求拿到锁之后读取数据并更新缓存,其他未获得锁请求延时后再去读取缓存数据.
3. 缓存雪崩
缓存雪崩发生时说明缓存中大批量的数据过期,而查询量巨大,请求直接到达数据库,造成数据库压力剧增.
解决方法:
- 随机设置缓存数据过期是时间,防止大规模缓存数据同时间过期.
- 设置热点数据永不过期.
- 分布式部署的缓存将热点数据均匀分布在不同的缓存数据库中.
4. 缓存一致性
要求数据库数据更新时缓存中的数据也能实时更新.
解决方法:
- 数据库更新时立即去更新缓存.
- 数据库更新前先删除缓存,更新完成后再次删除缓存,也就是
延迟双删
的策略。外部请求没有命中缓存则会查询数据库,查到数据后将其更新到缓存中,则自动保持了一致性.- 为缓存设置一个过期时间,读缓存数据前判断缓存是否过期,过期了则从数据库中查询数据,进行缓存更新.
有兴趣的读者可以参考 缓存一致性设计方案
5. 缓存清理策略
- FIFO(先进先出) :最先进入缓存的数据在缓存空间不足时被优先清除.
- LFU(最少使用) :无论数据是否过期,根据其使用的次数判断,清除使用次数最少的数据.
- LRU(最近最少使用):
无论数据是否过期,根据数据最后一次被使用的时间戳,清除最远使用时间戳的数据.实现:
LinkedHashMap 中的 accessOrder 属性设置为 true 时将根据元素的访问顺序将最近访问的数据放在双向链表尾部, 同时重写其 removeEldestEntry() 方法指定数据淘汰条件,即可实现LRU.
6. 缓存分类
6.1.本地缓存
缓存数据保存在单个服务器内存中,各个服务器之间缓存的数据相互独立
- 优点:读取速度快
- 缺点:分开存储可能出现一台应用服务器的数据有更新,而其他服务器数据没有更新,导致数据不一致的问题.
6.2.集中式缓存
缓存数据保存在专门的缓存服务器中,应用服务器通过网络请求从缓存服务器获取缓存数据
- 优点:集中管理缓存,保证数据一致性
- 缺点:网络请求需要消耗时间,读取频繁的话网络请求消耗的时间成本可能比将数据从数据库读取出来的成本还要高