三高架构之缓存
三高架构之缓存
之前是分流,并发
导流:将原本复杂操作的请求,引导到简单的操作上
原来经过复杂的查询得出的结果,把它单独存到独立的存储空间中,以后再来查,不需要经过复杂的计算。
成本:空间。
收益:节省了时间。
缓存的数据和数据库的数据,一一对应。
kv值
- 计算k
- 查询k
- 得到值,做转换。
命中率(缓存中能查到的数据/数据库总数据)
没有命中的缓存,还需查原数据。
数据的查询时间:时间(123步骤花费的时间) +(1-命中率)*查原数据的时间。
如何提升缓存的收益
- 减少123时间。
- 提高命中率
应用场景:
- 读多写少,用缓存。
- 查询原数据时间特别长的场景。
键
生成时间1
不同功能业务的key值要不一样,否则会被覆盖。
要唯一,避免碰撞。
单向函数:hash。给定输入的情况下,很容易计算出结果,而给定结果的情况下,几乎不可能计算出输入值。
正向快速生成,逆向困难,输入敏感,冲突避免。
md4,md5,sha-0,sha-1,sha-2(用,因为冲突概率很低)
查询时间2
缓存的位置。内存,硬盘,本地。
数据结构。
比如两个字符串很长的比较,一位一位的比较。
equals,hashcode可以加速
转换3
查出的结果,转换成需要的类型
序列化值(二进制),要序列化后,再反序列化才能使用
键总结
- 无碰撞(唯一)。
- 高效生成(不需要,约定好)。系统表示+功能标识+业务标识+前后缀
- 高效比较。
公司统一标准。
值
序列化值(二进制)
序列化后,再反序列化后才能使用。
对象值
存对象会有数据污染,如果拿到的是对象的引用,中间的时候如果A操作了,B拿到对象会不一样(存的不是最终值)
缓存只是在 调用方和数据提供方直接的 暂存方。
缓存的更新机制
缓存中数据怎么来的:查询的时候,如果没有,就从数据提供方获取,然后放到缓存中。
被动更新机制
- 固定时间过期,被动更新
- 时效性更新机制:设置一个过期时间。先从缓存拿,没有,从数据提供方拿,然后缓存起来,这样就相当于将提供方的数据 更新到缓存中了。(放弃了实时一致性,比如商品关注人数,评论数,浏览量)
写:只写数据提供方。不理会缓存
主动更新机制
cache aside(把缓存放边上)
写:先更新,更新数据提供方,后删除缓存。
可以用。
鸵鸟算法
在计算机科学中,鸵鸟算法是一个忽略潜在问题的一种算法策略,这种策略对计算机程序可能出现的问题采取无视态度(类似于鸵鸟在遇到危险时将头埋在地里,装作看不见)。鸵鸟算法的使用前提是,问题出现的概率很低。
传说中鸵鸟看到危险就把头埋在地底下。当你对某一件事情没有一个很好的解决方法时,那就忽略它,就像鸵鸟面对危险时会把它深埋在沙砾中,装作看不到。这样的算法称为“鸵鸟算法“。这实在不算是一个算法,但却是目前实际系统采用最多的一种策略。例如在计算机操作系统中,当死锁真正发生且影响系统正常运行时,手动干预—重新启动。
双写一致性
先删除缓存,再更新数据提供方。 延迟双删
1.更新缓存,更新数据库。更容易造成数据的不一致,缓存成功,数据提供方失败。更糟糕
2.更新数据库,更新缓存。有缺点,但可取
A更新了数据库,B更新了数据库,B更新了缓存,A更新了缓存
3.删除缓存,更新数据库。
4.更新数据库,删掉缓存。 cache aside
延迟双删:删除缓存,更新数据提供方,睡眠一段时间(根据实际业务),再删除缓存
如果第二次 删除失败了,怎么办?重试一下。
自己写重试代码,没问题。自己挂了呢?
转移风险。重试的组件?消息队列。
Read/Write Through
直接将结果写入缓存。再从缓存 同步到数据提供方。调用方只需要和缓存交互。
写成功的标识:缓存成功,数据提供方成功(一个事务) TCC。
初始化:1.启动缓存,从数据提供方。2.读取缓存,初始化。
缓存预热命中率低,慢慢的命中率才高
保障:缓存非常可靠
Writer Behind
在上面做了升级,异步写入到数据提供方。加入消息队列,保证最终一致性。
缓存空间足够大,能缓存所有的数据,命中率100%。
清理机制
以提高缓存命中率为目标。
过去访问多的,未来访问也多。
最近被更新的,未来访问的多。
时效性清理
一刀切:过期全部清理。要求缓存中的数据都有一个有效时间。
1条数据:data ttl。
轮询时效清理:额外开启一个程序,定时清扫所有数据的有效期,到期了,干掉。
自动失效清理:cookie。本质:上面的轮询
数目阈值清理
1.条数
2.每条的大小
FIFO:队列大小是10,
LRU(Least Recently Used 最近最少使用):清理长久未访问的数据
LFU(Least Frequently Used 最不常用的):清理访问次数的数据
如果空间充足,则缓存多多的,提高命中率。
如果空间不够,再回收空间,把空间给其他人让出来。
垃圾回收。
强引用:只要被强引用,就不会被回收。内存不足时,哪怕自己挂掉,也不回收。
软引用:空间不足时,才会被回收。
弱引用:不管内存够不够都回收。
虚引用:没法被GCROOT引用,引用和没引用一样。
SoftReference。
用Java实现一个 根据内存空间大小的使用情况,做一个缓存组件。
Map<k,SoftReference<>>。空间紧张会被回收。
实战
混合使用
时效性清理+数据阈值
1.过期就干掉
2.密集查询,导致空间急剧增大
LRU+软引用
保证最近访问的数据一直都在,最近未被访问的数据放软引用,用软引用包装一下。让垃圾回收去管理
缓存风险点
每增加一个环节,就多一个风险。
缓存穿透:缓存没有数据,数据提供方也没有数据,穿透了。
无效的调用,增加数据提供方的压力,缓存基本无效。
解决方案:在缓存中,缓存一份 空数据。key有值,value为空。
缓存雪崩:大量缓存突然失效,引发的数据提供方压力骤增。
数据阈值式清理:缓存是逐个失效的,阈值比较低的时候会,阈值高可以缓解。
时效式清理:会造成雪崩,避免缓存在同一时刻失效。过期时间=固定值+随机值。错峰失效。
软引用清理:当空间紧张的时候,缓存占据的空间会被回收。单纯的软引用无法解决,配合lru,对经常访问的数据建立强引用。
缓存击穿:某个缓存高频访问,缓存失效,查数据提供方(有数据提供方兜底,不叫穿透)
read/write through,write behind。更新机制。因为数据的写,更新,先操作的是缓存。
cache aside:有一个节点,缓存被删除。可能有击穿
实际工作:清理机制+更新机制,针对缓存,共同考虑
缓存预热
启动系统的时候,提前加载一些数据。
时效式清理机制:缓存重复预热。
缓存的位置
匹配cpu和内存速率不同产生的。
缓存越靠近用户,给系统的压力越小。要想系统性能好,缓存一定要趁早。
前置模块:减少和后端通信的成本。
后置模块:公共模块。尽量用这个方式。
客户端缓存
客户端:浏览器,c软件,安装,ios,h5,小程序(程序需升级)
浏览器:cookie(过期时间,因为会请求服务器,轻量级的请求)需要浏览器和h5支持,
sqlite:安卓端的一个数据库。规则类(开机图片,引导页)。
cdn静态缓存
静态资源:页面,图片。
数据:地点,字典,行业分类,地区三级联动(标准化的数据)广义:与用户个体无关的,具有通用性的数据,都可以作为静态数据。
如果用户不同,参数不同,时间不同----结果不同。对系统性能造成负面影响
服务端缓存
redis,localcache,guava。
数据库缓存
冗余字段,中间表。
操作完业务,需要做统计,非实时的数据,后置。
新增订单。
insert order(xxxx) ,统计表(订单数据+1) 10s
5s ,定时任务扫描(48h-24h)+1 。
写缓存
写缓存:调用方和 数据处理方之间。
目的:减少巨量调用操作,对数据处理方法的冲击。削峰。
消息队列。
写缓存收益:原始时间 <(写缓存时间+缓存中数据向后传递的实际+原始时间)
收益在于用户的角度:用户目标的响应时间 降低了。
只需要写缓存的时间小于写库的时间就有收益。
读缓存:是以缓存命中的数据,替代 数据提供方的操作。
写缓存:通过增加额外花费的时间,来延迟数据处理方的工作。
写缓存实践:redis(发布订阅),消息队列(发布订阅),数据库(先生成数据,后期再进行统计,耗时的&对实时要求不高的,后置)。
适合场景:请求丰谷值变化明显&对实时性要求不高的系统中。
抢购系统,竞品系统,秒杀系统,抢红包系统。
在请求峰值的时候,降低请求响应的时候,提升系统吞吐量。在低谷的时候,把请求释放出来,慢慢消息。
消息推送系统:极光,百度。
缺点:实时性不高。
大厂:平峰(请求量在某个阈值之下),正常处理。峰值超过阈值的时候,触发写缓存。
降级:微服务降级组件处理可以。
灰度发布。配置灰度规则(规则中 有请求的阈值,根据阈值的不同,调用不同的系统)。
再扛不住就限流。要对流量进行评估。