后端缓存
主要讲述redis。简单来说,redis就是一个数据库,不过redis的数据存在内存中,所以存写速度非常快。接下来直接讲常见的缓存问题。
缓存击穿
- 概念:对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据
- 原因:缓存在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,该key没有命中,大量请求穿透到数据库服务器
- 解决方案:使用互斥锁,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作比如Redis的SETNX,去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则就重试整个get缓存的方法;永远不过期,把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建
缓存雪崩
这个和缓存击穿的区别在于这里针对很多key,前者则是某一key缓存。
- 概念:大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
- 原因:大量缓存在同一时间失效;大量请求落到后端DB上;
- 解决方案:控制缓存并发、击穿现象发生;不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀;做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(高可用缓存集群);提前预估容量。
缓存穿透
- 概念:访问一个一定不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉
- 原因:key被高并发访问;该key没有命中,去后端DB获取;大量请求穿透到数据库服务器
- 解决方案:布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤,避免对底层数据存储系统造成压力;访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间,最长不超过5分钟(因为缓存会占用内存)
- 注意点:开发是否有将刚查询出来的数据放入缓存;尤其是对null的处理
缓存并发
- 概念:如果网站并发访问高,一个缓存如果失效或者不存在,可能出现多个进程同时直接获取DB数据,这时候会对DB造成很大的访问压力。
- 原因:缓存过期或者在更新或者不存在;同时有大量的并发请求该key;如果缓存更新,对某个key有大量的并发请求,此时请求获得的结果可能是更新之前或者更新之后,从而会导致“缓存一致性”的问题出现。
- 解决方案:由于“缓存并发”问题一般发生在查询期间,而且问题出在缓存更新时的高并发时刻,思路上,就可以在这个时候,对key加锁。(对缓存查询加锁,如果 KEY 不存在,就加锁,然后查 DB 后写入缓存,然后解锁;)
缓存一致性
- 概念:当数据时效性要求很高时,需要保证缓存中的数据与数据库中的保持一致,需要保证缓存节点和副本中的数据也保持一致,不能出现差异现象。(集群同步)
- 原因:对同一个数据进行读写,在数据库层面并发的读写并不能保证完成顺序;发生了写请求A,A的第一步淘汰了cache;A的第二步写数据库,发出修改请求;发生了读请求B,B的第一步读取cache,发现cache中是空的;B的第二步读取数据库,发出读取请求,此时A的第二步写数据还没完成,读出了一个脏数据放入cache;
- 解决方案:先更新数据库,成功后,让缓存失效
其他缓存问题
- 更新缓存:普通类型直接赋值;集合类型取出后添加再set进去;序列化的对象、json或者HTML数据;
- 数据覆盖:key冲突,彼此冲掉对方的数据
- 服务共用缓存:不同服务业务模式,数据量,并发量不一样,会因为一个cache相互影响;相同的key,冲掉数据;
缓存删除
- 前提:缓存设置了一个过期时间,过期后需要对这批key进行删除,因为缓存大小有限
- 定期删除:默认每100ms随机抽取一些过期的key,检查是否过期,如果过期就删除。因为本身key非常多,所以做不到每100ms遍历所有key,不然CPU压力很大
- 惰性删除:靠定期删除还残留的key,当你再次去查询这个key的时候,删除这个key
- 问题:如果定期漏掉很多key,且长时间没去查询,导致key堆积在内存中
- 解决方案:从已设置过期时间的数据集里挑选最近最少使用的数据淘汰;从已设置过期时间的数据集里挑选将要过期的数据淘汰;从已设置过期时间的数据集里挑选任意选择数据淘汰;在内存不足时,移除最近最少使用的数据;从数据集中任意淘汰数据;禁止驱逐数据;
移动端缓存
- 直接读缓存而不发送请求获取最新数据
- 协议缓存,http协议缓存机制是指通过 HTTP 协议头里的 Cache-Control(或 Expires)和 Last-Modified(或 Etag)等字段来控制文件缓存的机制。更新了一张图片,发布之后反复重新进页面总是看不到更新。涉及到资源更新的,变化前后都需要注意一下
- 使用缓存中的字段,类型冲突
- 缓存存储支持的类型,比如app缓存不支持缓存rn这边的gif图,导致展示不了动效
其他文章可以关注微信公众号测试架构师养成记,还有资料可以领哦~