咱们一般是这样设计的,应用程序先从cache取数据,没有获得,则从数据库中取数据,成功后,放到缓存中。数据库
那试想一下,若是取出来的null,需不须要放入cache呢?答案固然是须要的。缓存
咱们试想一下若是取出为null不放入cache会有什么结果?很显然每次取cache没有走db返回null,很容易让攻击者利用这个漏洞搞垮你的服务器,利用洪水攻击让你的程序夯在这个地方致使你的正常流程抢不到资源。安全
在读取缓存方面,你们没啥疑问,都是按照下图的流程来进行业务操做。服务器
可是在更新缓存方面,有如下几种策略:网络
通常如今采用的是先更新数据库,再删除缓存。并发
这有篇写的极好的博客可好好学习:分布式之数据库和缓存双写一致性方案解析分布式
现将主要内容摘录以下:ide
这套方案,你们是广泛反对的。为何呢?有以下两点缘由。
缘由一(线程安全角度
同时有请求A和请求B进行更新操做,那么会出现
(1)线程A更新了数据库
(2)线程B更新了数据库
(3)线程B更新了缓存
(4)线程A更新了缓存
这就出现请求A更新缓存应该比请求B更新缓存早才对,可是由于网络等缘由,B却比A更早更新了缓存。可能在DB和memcached中具备相同数据项的不一样值。这就致使了脏数据,所以不考虑。memcached
缘由二(业务场景角度)
有以下两点:
(1)若是你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会致使,数据压根还没读到,缓存就被频繁的更新,浪费性能。
(2)若是你写入数据库的值,并非直接写入缓存的,而是要通过一系列复杂的计算再写入缓存。那么,每次写入数据库后,都再次计算写入缓存的值,无疑是浪费性能的。显然,删除缓存更为适合。性能
该方案会致使不一致的缘由是。同时有一个请求A进行更新操做,另外一个请求B进行查询操做。那么会出现以下情形:
(1)请求A进行写操做,删除缓存
(2)请求B查询发现缓存不存在
(3)请求B去数据库查询获得旧值
(4)请求B将旧值写入缓存
(5)请求A将新值写入数据库
首先,先说一下。老外提出了一个缓存更新套路,名为《Cache-Aside pattern》。其中就指出
失效:应用程序先从cache取数据,没有获得,则从数据库中取数据,成功后,放到缓存中。
命中:应用程序从cache中取数据,取到后返回
更新:先把数据存到数据库中,成功后,再让缓存失效。
另外,知名社交网站facebook也在论文《Scaling Memcache at Facebook》中提出,他们用的也是先更新数据库,再删缓存的策略。
这种状况不存在并发问题么?
不是的。假设这会有两个请求,一个请求A作查询操做,一个请求B作更新操做,那么会有以下情形产生
(1)缓存恰好失效
(2)请求A查询数据库,得一个旧值
(3)请求B将新值写入数据库
(4)请求B删除缓存
(5)请求A将查到的旧值写入缓存
ok,若是发生上述状况,确实是会发生脏数据。
然而,发生这种状况的几率又有多少呢?
发生上述状况有一个先天性条件,就是步骤(3)的写数据库操做比步骤(2)的读数据库操做耗时更短,才有可能使得步骤(4)先于步骤(5)。但是,你们想一想,数据库的读操做的速度远快于写操做的(否则作读写分离干吗,作读写分离的意义就是由于读操做比较快,耗资源少),所以步骤(3)耗时比步骤(2)更短,这一情形很难出现。