概述
缓存分类
- 静态缓存、分布式缓存、热点本地缓存。
- 静态缓存通过生成 Velocity 模板或者静态 HTML 文件来实现。部署在Nginx,可以减少对于应用服务器的压力。
- 分布式缓存典型的就是我们平常用来存储动态数据的redis。
- 热点本地缓存指的是一些极端热点的数据,比如某凡的瓜,主要部署在代码层面,阻挡热点查询对于分布式缓存节点和数据库节点的压力。
由于本地缓存是部署在应用服务器中,而应用服务器通常会部署多台,当数据更新时,不能确定哪台服务器本地中了缓存,更新或者删除所有服务器的缓存不是一个好的选择,所以通常会等待缓存过期。因此,这种缓存的有效期很短,通常为分钟或者秒级别,以避免返回前端脏数据
。
缓存的不足
- 适合读多写少的业务场景,数据最好有一定热点属性;如果是搜索这种,每个人搜索词都不同,没有明显热点,缓存命中率就会比较低,作用就不会那么明显了。
- 缓存会给系统带来复杂度,并且会有数据不一致的风险。比如更新数据库成功,而更新缓存失败;再比如多个系统间的交互各有各的缓存。这种场景需要考虑设置较短过期时间,或者手动清理。
- 缓存通常使用内存作为存储介质,但是内存空间有限。所以使用缓存要做数据量级的评估,对于可预见的需要消耗大量存储成本的数据要慎用。
- 缓存也会给运维带来成本。
Cache Aside 旁路缓存
- 更新数据时不更新缓存,而是删除缓存中的数据,在读取数据时,发现缓存中没了数据之后,再从数据库中读取数据,更新到缓存中。
- 极限情况:A读缓存不存在- > A读数据库 -> B更新数据库 -> B删除缓存 -> A写入缓存。此时A写入的是旧数据,不过这种情况概率很低,因为写入缓存的速度远超过更新数据库的速度。
Read/Write Through(读穿 / 写穿)策略
- 这个策略的核心原则是用户只与缓存打交道,由缓存和数据库通信,写入或者读取数据。
Write Through 的策略是这样的:先查询要写入的数据在缓存中是否已经存在,如果已经存在,则更新缓存中的数据,并且由缓存组件同步更新到数据库中,如果缓存中数据不存在,我们把这种情况叫做“Write Miss(写失效)”
。- 有两种“Write Miss”方式:
- 一个是“Write Allocate(按写分配)”,做法是写入缓存相应位置,再由缓存组件同步更新到数据库中;
- 另一个是“No-write allocate(不按写分配)”,做法是不写入缓存中,而是直接更新到数据库中。在 Write Through 策略中,我们一般选择“No-write allocate”方式,原因是无论采用哪种“Write Miss”方式,我们都需要同步将数据更新到数据库中,而“No-write allocate”方式相比“Write Allocate”还减少了一次缓存的写入,能够提升写入的性能。
- Read Through 策略就简单一些,它的步骤是这样的:先查询缓存中数据是否存在,如果存在则直接返回,如果不存在,则由缓存组件负责从数据库中同步加载数据。
Write Back(写回)策略
- 核心思想是在写入数据时只写入缓存,并且把缓存块儿标记为“脏”的。而脏块儿只有被再次使用时才会将其中的数据写入到后端存储中。
- 在“Write Miss”的情况下,我们采用的是“Write Allocate”的方式,也就是在写入后端存储的同时要写入缓存,这样我们在之后的写请求中都只需要更新缓存即可,而无需更新后端存储了。
- 我们在读取缓存时如果发现缓存命中则直接返回缓存数据。如果缓存不命中则寻找一个可用的缓存块儿,如果这个缓存块儿是“脏”的,就把缓存块儿中之前的数据写入到后端存储中,并且从后端存储加载数据到缓存块儿,如果不是脏的,则由缓存组件将后端存储中的数据加载到缓存中,最后我们将缓存设置为不是脏的,返回数据就好了。
- 其实这种策略不能被应用到我们常用的数据库和缓存的场景中,它是计算机体系结构中的设计,比如在向磁盘中写数据时采用的就是这种策略。无论是操作系统层面的 Page Cache,还是日志的异步刷盘,亦或是消息队列中消息的异步写入磁盘,大多采用了这种策略。因为这个策略在性能上的优势毋庸置疑,它避免了直接写磁盘造成的随机写问题,毕竟写内存和写磁盘的随机 I/O 的延迟相差了几个数量级呢
最后
以上就是粗暴秀发为你收集整理的高并发系统设计:缓存的读写策略的全部内容,希望文章能够帮你解决高并发系统设计:缓存的读写策略所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复