高性能网站设计之缓存更新的套路

news/2024/5/19 8:46:39/文章来源:https://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/78693323

看到好些人在写更新缓存数据代码时,先删除缓存,然后再更新数据库,而后续的操作会把数据再装载的缓存中。然而,这个是逻辑是错误的。试想,两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。

我不知道为什么这么多人用的都是这个逻辑,当我在微博上发了这个贴以后,我发现好些人给了好多非常复杂和诡异的方案,所以,我想写这篇文章说一下几个缓存更新的Design Pattern(让我们多一些套路吧)。

这里,我们先不讨论更新缓存和更新数据这两个事是一个事务的事,或是会有失败的可能,我们先假设更新数据库和更新缓存都可以成功的情况(我们先把成功的代码逻辑先写对)。

更新缓存的的Design Pattern有四种:Cache aside, Read through, Write through, Write behind caching,我们下面一一来看一下这四种Pattern。

Cache Aside Pattern

这是最常用最常用的pattern了。其具体逻辑如下:

  • 失效:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中。

  • 命中:应用程序从cache中取数据,取到后返回。

  • 更新:先把数据存到数据库中,成功后,再让缓存失效。

注意,我们的更新是先更新数据库,成功后,让缓存失效。那么,这种方式是否可以没有文章前面提到过的那个问题呢?我们可以脑补一下。

一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。而不会像文章开头的那个逻辑产生的问题,后续的查询操作一直都在取老的数据。

这是标准的design pattern,包括Facebook的论文《Scaling Memcache at Facebook》也使用了这个策略。为什么不是写完数据库后更新缓存?你可以看一下Quora上的这个问答《Why does Facebook use delete to remove the key-value pair in Memcached instead of updating the Memcached during write request to the backend?》,主要是怕两个并发的写操作导致脏数据。

那么,是不是Cache Aside这个就不会有并发问题了?不是的,比如,一个是读操作,但是没有命中缓存,然后就到数据库中取数据,此时来了一个写操作,写完数据库后,让缓存失效,然后,之前的那个读操作再把老的数据放进去,所以,会造成脏数据。

但,这个case理论上会出现,不过,实际上出现的概率可能非常低,因为这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。

所以,这也就是Quora上的那个答案里说的,要么通过2PC或是Paxos协议保证一致性,要么就是拼命的降低并发时脏数据的概率,而Facebook使用了这个降低概率的玩法,因为2PC太慢,而Paxos太复杂。当然,最好还是为缓存设置上过期时间。

Read/Write Through Pattern

我们可以看到,在上面的Cache Aside套路中,我们的应用代码需要维护两个数据存储,一个是缓存(Cache),一个是数据库(Repository)。所以,应用程序比较啰嗦。而Read/Write Through套路是把更新数据库(Repository)的操作由缓存自己代理了,所以,对于应用层来说,就简单很多了。可以理解为,应用认为后端就是一个单一的存储,而存储自己维护自己的Cache。

Read Through

Read Through 套路就是在查询操作中更新缓存,也就是说,当缓存失效的时候(过期或LRU换出),Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务自己来加载,从而对应用方是透明的。

Write Through

Write Through 套路和Read Through相仿,不过是在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库(这是一个同步操作)

下图自来Wikipedia的Cache词条。其中的Memory你可以理解为就是我们例子里的数据库。

Write Behind Caching Pattern

Write Behind 又叫 Write Back。一些了解Linux操作系统内核的同学对write back应该非常熟悉,这不就是Linux文件系统的Page Cache的算法吗?是的,你看基础这玩意全都是相通的。所以,基础很重要,我已经不是一次说过基础很重要这事了。

Write Back套路,一句说就是,在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。这个设计的好处就是让数据的I/O操作飞快无比(因为直接操作内存嘛 ),因为异步,write backg还可以合并对同一个数据的多次操作,所以性能的提高是相当可观的。

但是,其带来的问题是,数据不是强一致性的,而且可能会丢失(我们知道Unix/Linux非正常关机会导致数据丢失,就是因为这个事)。在软件设计上,我们基本上不可能做出一个没有缺陷的设计,就像算法设计中的时间换空间,空间换时间一个道理,有时候,强一致性和高性能,高可用和高性性是有冲突的。软件设计从来都是取舍Trade-Off。

另外,Write Back实现逻辑比较复杂,因为他需要track有哪数据是被更新了的,需要刷到持久层上。操作系统的write back会在仅当这个cache需要失效的时候,才会被真正持久起来,比如,内存不够了,或是进程退出了等情况,这又叫lazy write。

在wikipedia上有一张write back的流程图,基本逻辑如下:

 

再多唠叨一些

1)上面讲的这些Design Pattern,其实并不是软件架构里的mysql数据库和memcache/redis的更新策略,这些东西都是计算机体系结构里的设计,比如CPU的缓存,硬盘文件系统中的缓存,硬盘上的缓存,数据库中的缓存。基本上来说,这些缓存更新的设计模式都是非常老古董的,而且历经长时间考验的策略,所以这也就是,工程学上所谓的Best Practice,遵从就好了。

2)有时候,我们觉得能做宏观的系统架构的人一定是很有经验的,其实,宏观系统架构中的很多设计都来源于这些微观的东西。比如,云计算中的很多虚拟化技术的原理,和传统的虚拟内存不是很像么?Unix下的那些I/O模型,也放大到了架构里的同步异步的模型,还有Unix发明的管道不就是数据流式计算架构吗?TCP的好些设计也用在不同系统间的通讯中,仔细看看这些微观层面,你会发现有很多设计都非常精妙……所以,请允许我在这里放句观点鲜明的话——如果你要做好架构,首先你得把计算机体系结构以及很多老古董的基础技术吃透了

3)在软件开发或设计中,我非常建议在之前先去参考一下已有的设计和思路,看看相应的guideline,best practice或design pattern,吃透了已有的这些东西,再决定是否要重新发明轮子。千万不要似是而非地,想当然的做软件设计。

4)上面,我们没有考虑缓存(Cache)和持久层(Repository)的整体事务的问题。比如,更新Cache成功,更新数据库失败了怎么吗?或是反过来。关于这个事,如果你需要强一致性,你需要使用“两阶段提交协议”——prepare, commit/rollback,比如Java 7 的XAResource,还有MySQL 5.7的 XA Transaction,有些cache也支持XA,比如EhCache。当然,XA这样的强一致性的玩法会导致性能下降,关于分布式的事务的相关话题,你可以看看《分布式系统的事务处理》一文。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_791523.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大型网站--负载均衡架构

负载均衡 (Load Balancing) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。大型网站负载均衡的利器全局负载均衡系统&#xff0…

织梦index.php被黑,织梦网站被黑的解决流程

织梦网站安全问题一直以来都是令人堪忧的,不过毕竟是开源程序,可以理解。这不最近有一位同学的站点就“中招”了,下面阿南就把处理的流程记录下来,希望对站长们有帮助。首先打开站点首页,我们可以看到,标题…

划重点!必备 SQL 查询优化技巧,提升网站访问速度

来自:开源中国 协作翻译链接:oschina.net/translate/sql-query-optimization原文:https://deliciousbrains.com/sql-query-optimization/译者:南宫冰郁, rever4433, soaring, 凉凉_, Tony, 无若在这篇文章中,我将介绍如…

AcFun网站已无法打开:官微表达无奈

IT之家2月2日消息 目前著名的弹幕网站AcFun中的视频已经无法播放,同时经过多地网友测试,AcFun的网站也已经无法打开,官微也发表微博,似乎表达对于网站无法打开的无奈。经过IT之家的测试,目前AcFun网站已经无法打开&…

大型网站限流算法的实现和改造

最近写了一个限流的插件,所以避免不了的接触到了一些限流算法。本篇文章就来分析一下这几种常见的限流算法分析之前依我个人的理解来说限流的话应该灵活到可以针对每一个接口来做。比如说一个类里面有5个接口,那么我的限流插件就应该能针对每一个接口就行…

高级Java开发人员最常访问的几个网站

这是高级Java开发人员最常访问的几个网站。 这些网站提供新闻,一般问题或面试问题的答案,精彩的讲座等。质量是优秀网站的关键因素,这此网站都有较高的质量内容。下面逐一介绍:1. StackoverflowStackoverflow.com可能是编程世界中…

高级Java开发人员最常访问的几个网站

这是高级Java开发人员最常访问的几个网站。 这些网站提供新闻,一般问题或面试问题的答案,精彩的讲座等。质量是优秀网站的关键因素,这此网站都有较高的质量内容。下面逐一介绍:1. StackoverflowStackoverflow.com可能是编程世界中…

大型网站系统架构的演化

四、使用集群改善应用服务器性能应用服务器作为网站的入口,会承担大量的请求,我们往往通过应用服务器集群来分担请求数。应用服务器前面部署负载均衡服务器调度用户请求,根据分发策略将请求分发到多个应用服务器节点。常用的负载均衡技术硬件…

JavaWeb之ServletContext——统计用户访问网站次数

各位小伙伴大家好呀~今天我们来了解 ServletContext 对象ServletContext 对象1)什么是 ServletContext 对象ServletContext 代表是一个 web 应用的环境(上下文)对象,ServletContext对象内部封装是该 web 应用的信息,一个 web 应用…

一个大型网站的技术架构是怎样建成的

网站系统架构层次如下图所示:1.前端架构前端指用户请求到达网站应用服务器之前经历的环节,通常不包含网站业务逻辑,不处理动态内容。浏览器优化技术并不是优化浏览器,而是通过优化响应页面,加快浏览器页面的加载和显示…

大型网站技术架构(二):架构要素和高性能架构

作者 | Arno原文 | https://segmentfault.com/a/1190000007390358在《大型网站技术架构(一)》我们把整个架构演变过程大致说了一下,这次我们来说说从哪方面进行考虑设计。为了使网站的能够应对高并发访问,海量数据处理&#xff0c…

网站高并发大流量访问的处理及解决方案

来自:Hist_花透的博客https://blog.csdn.net/qishouzhang/article/details/471119451.硬件升级普通的P4服务器一般最多能支持每天10万独立IP,如果访问量比这个还要大, 那么必须首先配置一台更高性能的专用服务器才能解决问题 ,否则…

网站 HTTP 升级 HTTPS 完全配置手册

作者:葡萄城技术团队链接:https://my.oschina.net/powertoolsteam/blog/1862967今天,所有使用Google Chrome稳定版的用户迎来了v68正式版首个版本的发布,详细版本号为v68.0.3440.75,上一个正式版v67.0.3396.99发布于6月…

ubuntu怎么跳出系统自动进去_wordpress、Dedecms织梦等网站系统怎么做百度自动推送?...

主动向百度等搜索引擎可缩短爬虫发现网站链接时间,加快网站的收录速度。网站时效性内容建议使用链接提交工具,实时向搜索推送数据。那么wordpress、Dedecms织梦等网站系统怎么做百度自动推送呢?有开发能力的对于动开发的人来说,要…

利用 PHP 扩展 Taint 找出网站的潜在安全漏洞实践

一、背景笔者从接触计算机后就对网络安全一直比较感兴趣,在做PHP开发后对WEB安全一直比较关注,2016时无意中发现Taint这个扩展,体验之后发现确实好用;不过当时在查询相关资料时候发现关注此扩展的人数并不多;最近因为换…

网站mysql密码怎么修改_mysql怎么修改密码

第一种方式:最简单的方法就是借助第三方工具Navicat for MySQL或Navicat Premium来修改,方法如下:1、登录mysql到指定库,如:登录到student库。2、然后点击上方“用户”按钮。3、选择要更改的用户名,然后点击…

百度网站疑似宕机 众多网友反馈不能正常登陆

从11月9日上午11点10分开始,有不少网友开始网上抱怨,百度网站及其旗下App都打不开的消息,而从用户的反馈来看,范围还是挺大的。目前,不少网友在微博上反馈称,百度网站似乎出现了宕机,很多用户不…

8个程序员专用软件/网站,个个是神器,第一个最惊喜......

节省时间的方法有俩,一个是放弃做一些事,在做一些事的时候同步做另一些事。另一种就是改进做一些事的效率,更快地做一些事。寻找更加高效、好用的工具所花费的时间,和这些工具将为你节省的时间相比,九牛一毛。今天给大…

大型网站图片服务器架构的演进!

在主流的Web站点中,图片往往是不可或缺的页面元素,尤其在大型网站中,几乎都将面临“海量图片资源”的存储、访问等相关技术问题。在针对图片服务器的架构扩展中,也会历经很多曲折甚至是血泪教训,尤其是早期规划不足&am…

Kali 利用setoolkit制作钓鱼网站

实验环境:一台kali(为机 NAT模式) 一台物理机(靶机) 在kali的终端上打开setoolkit 选择第一个社会工程,选择社会工程之后接着有11个选项. 选择第二个网站向量,选择完之后有8个选项. 选择第三个凭证收割方…