缓存的五种设计模式

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"利用缓存来加速系统已经成为很常见的一种操作。这种方式有效率、简单,而且成本也在可控的范围内。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"说到缓存,通常会下意识的想到缓存是用来加速读的,实际上,读数据和写数据都可以使用缓存。总的来说,缓存的使用模式可分成五种。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这五种方式就是从是读缓存还是写缓存的角度来进行划分的。需要注意,这里的缓存是广义上的缓存,不仅仅指 Redis 这些常用作缓存的软件。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这些缓存模式并不是新技术,而是伴随在计算机体系结构演进中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Cache-Aside"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果从缓存中找到数据,称之为"},{"type":"text","marks":[{"type":"strong"}],"text":"命中缓存"},{"type":"text","text":",如果没有找到数据,称为之"},{"type":"text","marks":[{"type":"strong"}],"text":"未命中缓存"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Cache-Aside 应该是使用最为广泛的一种模式。应用直接去缓存中找数据,命中缓存则直接返回,如果未命中缓存,则需要先去数据库中查询数据,并将查询到的数据存储到缓存中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/b1/b1c76278c84a0e436ba17ad741f03663.png","alt":null,"title":"图1: Cache-Aside","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种方式会让缓存中的数据与数据库中的数据不一致,所以一般会给缓存中的数据设置过期时间(TTL),数据过期之后就去数据库中取最新的数据。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在数据更新时,应该和下文的 Write-Around 配合,而不要使用 Write-Through。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Read-Through Cache"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Read-Through 的方式与 Cache-Aside 的方式很接近,区别在于,Cache-Aside 是通过应用程序来更新缓存中的数据,而 Read-Through 则是通过缓存自身来更新数据,也就是说应用和数据库之间不直接进行连接。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/84/84ba2d2293705b4d174905e2d5fff9ca.png","alt":null,"title":"图2: Read-Through","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这种模式也存在缓存中数据与数据库中数据不一致的情况,但是相比于给缓存设置过期时间,它只需要和 Write-Through 搭配使用就可以解决这个问题。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Write-Through Cache"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面说了两种以读为主的缓存。Write-Through 会先将数据写入到缓存中,然后由缓存将数据存入到数据库中。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/88/88b0d1f81fe31706fd1e10904e48853f.png","alt":null,"title":"图3: Write-Through","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Write-Through 与 Read-Through 相结合可以很好的解决缓存和数据库中数据不一致的问题,Write-Through 每次都会先更新缓存中的数据,所以每次读到的数据也是最新的。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/79/791c0af28a1558d1be88365c866a045a.png","alt":null,"title":"图4: Read-Through + Write-Through","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Write-Around"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Write-Around 其实本身并不会用到缓存,而是会直接写入到数据库中。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ba/ba4fe57ee28d1d20e6683e4f916d2778.png","alt":null,"title":"图5: Write-Around","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Cache-Aside 为什么要配合 Write-Around 而不能和 Write-Through 一起使用呢?"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因为 Write-Through 会先更新缓存,而如果这时刚好有另外一个线程将数据库中旧的数据读取出来将缓存中新的数据覆盖,就会造成数据错误,而使用 Write-Around 就不会出现这个问题。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/61/61f83718b7d7526d9c680449fa972b7c.png","alt":null,"title":"图6: Cache-Aside + Write-Around","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Write-Around 在某些场景下与 Read-Through 搭配使用也很有用,对于某些只需要写一次并且读多次的情况,比如聊天信息的写入和获取。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Write-Back"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Write-Back 算是 Write-Through 的改良版,Write-Through 每写一次缓存,缓存就会写一次数据库,而 Write-Back 则是写了多次缓存后才会写一次数据库,可以大大减轻服务器的压力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"这一模式在 MySQL 等数据库产品中使用很广泛。"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/05/051a355fb64939245d3062f63ae247d8.png","alt":null,"title":"图7:Write-Back","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"当然, Write-Back 也不是没有缺点,如果缓存出现了问题,那么缓存中这部分没有持久化的数据就会丢失。 "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"文 / Rayjun"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] https://codeahoy.com/2017/08/11/caching-strategies-and-how-to-choose-the-right-one/"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[2] https://coolshell.cn/articles/17416.html"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章