直播网站建设需要什么,网站开发平台论文,企业百度网站建设,网站那个做的比较好的目录
前言
一、Cache Aside#xff08;旁路缓存#xff09;策略
二、不一致解决场景及解决方案
一、数据库主从不一致
二、缓存与数据库不一致
三、问题分析
三、缓存误用
一、多服务共用缓存实例
二、调用方缓存数据
三、缓存作为服务与服务之间传递数据的媒介
四… 目录
前言
一、Cache Aside旁路缓存策略
二、不一致解决场景及解决方案
一、数据库主从不一致
二、缓存与数据库不一致
三、问题分析
三、缓存误用
一、多服务共用缓存实例
二、调用方缓存数据
三、缓存作为服务与服务之间传递数据的媒介
四、使用缓存未考虑雪崩
总结 前言
缓存是互联网分层架构中非常重要的一个部分通常用它来降低数据库压力提升系统整体性能缩短访问时间。有架构师说“缓存是万金油哪里有问题加个缓存就能优化”缓存的滥用可能会导致一些错误用法。
缓存你真的用对了么 一、Cache Aside旁路缓存策略 旁路缓存策略是最常用的一种缓存读写策略它适用于读请求比较多数据更新频率不高的场景。它的基本思想是应用程序直接访问缓存和数据库而不通过中间层。当需要读取数据时先从缓存中查找如果命中则直接返回如果未命中则从数据库中查询并将结果放入缓存中然后返回。当需要更新数据时先更新数据库然后删除缓存。 Cache Aside 策略也叫旁路缓存策略这 个策略数据以数据库中的数据为准缓存中的数据是按需加载的。它可以分为读策略和写策 略。
其中读策略的步骤是
从缓存中读取数据如果缓存命中则直接返回数据 如果缓存不命中则从数据库中查询数据 查询到数据后将数据写入到缓存中并且返回给用户。 写策略的步骤是 更新数据库中的记录 删除缓存记录。 你也许会问了在写策略中能否先删除缓存后更新数据库呢答案是不行的因为这样也有可能出现缓存数据不一致的问题我以用户表的场景为例解释一下。假设某个用户的年龄是 20请求 A 要更新用户年龄为 21所以它会删除缓存中的内容。这时另一个请求 B 要读取这个用户的年龄它查询缓存发现未命中后会从数据库中读 取到年龄为 20并且写入到缓存中然后请求 A 继续更改数据库将用户的年龄更新为 21这就造成了缓存和数据库的不一致。 那么像 Cache Aside 策略这样先更新数据库后删除缓存就没有问题了吗其实在理论上还是有缺陷的。假如某个用户数据在缓存中不存在请求 A 读取数据时从数据库中查询到年龄为 20在未写入缓存中时另一个请求 B 更新数据。它更新数据库中的年龄为 21并且清空缓存。这时请求 A 把从数据库中读到的年龄为 20 的数据写入到缓存中造成缓存和数据库数据不一致。 不过这种问题出现的几率并不高原因是缓存的写入通常远远快于数据库的写入所以在实际中很难出现请求 B 已经更新了数据库并且清空了缓存请求 A 才更新完缓存的情况。而一旦请求 A 早于请求 B 清空缓存之前更新了缓存那么接下来的请求就会因为缓存为空而从数据库中重新加载数据所以不会出现这种不一致的情况。 Cache Aside 策略是我们日常开发中最经常使用的缓存策略不过我们在使用时也要学会依情况而变。比如说当新注册一个用户按照这个更新策略你要写数据库然后清理缓存当然缓存中没有数据给你清理。可当我注册用户后立即读取用户信息并且数据库主从分离时会出现因为主从延迟所以读不到用户信息的情况。而解决这个问题的办法恰恰是在插入新数据到数据库之后写入缓存这样后续的读请求就会从缓存中读到数据了。并且因为是新注册的用户所以不会出现并发更新用户信息的情况。Cache Aside 存在的最大的问题是当写入比较频繁时缓存中的数据会被频繁地清理这样会对缓存的命中率有一些影响。 二、不一致解决场景及解决方案 发生写请求后不管是先操作DB还是先淘汰Cache在主从数据库同步完成之前如果有读请求都可能发生读Cache Miss读从库把旧数据存入缓存的情况。此时怎么办呢 一、数据库主从不一致 无缓存时数据库主从不一致问题 如上图发生的场景是写后立刻读 1主库一个写请求主从没同步完成 2从库接着一个读请求读到了旧数据 3最后主从同步完成 导致的结果是主动同步完成之前会读取到旧数据。可以看到主从不一致的影响时间很短在主从同步完成后就会读到新数据。 二、缓存与数据库不一致 再看引入缓存后缓存和数据库不一致问题。 如上图发生的场景也是写后立刻读 导致的结果是旧数据放入缓存即使主从同步完成后续仍然会从缓存一直读取到旧数据。 可以看到加入缓存后导致的不一致影响时间会很长并且最终也不会达到一致。 三、问题分析 可以看到这里提到的缓存与数据库数据不一致根本上是由数据库主从不一致引起的。当主库上发生写操作之后从库binlog同步的时间间隔内读请求可能导致有旧数据入缓存。 思路那能不能写操作记录下来在主从时延的时间段内读取修改过的数据的话强制读主并且更新缓存这样子缓存内的数据就是最新。在主从时延过后这部分数据继续读从库从而继续利用从库提高读取能力。 选择性读主 可以利用一个缓存记录必须读主的数据。 如上图当写请求发生时 1写主库 2将哪个库哪个表哪个主键三个信息拼装一个key设置到cache里这条记录的超时时间设置为“主从同步时延” PSkey的格式为“db:table:PK”假设主从延时为1s这个key的cache超时时间也为1s。 如上图当读请求发生时 这是要读哪个库哪个表哪个主键的数据呢也将这三个信息拼装一个key到cache里去查询如果 1cache里有这个key说明1s内刚发生过写请求数据库主从同步可能还没有完成此时就应该去主库查询。并且把主库的数据set到缓存中防止下一次cahce miss。 2cache里没有这个key说明最近没有发生过写请求此时就可以去从库查询 以此保证读到的一定不是不一致的脏数据。 PS如果系统可以接收短时间的不一致建议定时更新缓存就可以了。避免系统过于复杂。 三、缓存误用
一、多服务共用缓存实例 如上图服务A和服务B共用一个缓存实例不是通过这个缓存实例交互数据
该方案存在的问题是
1、可能导致key冲突彼此冲掉对方的数据
可能需要服务A和服务B提前约定好了key以确保不冲突常见的约定方式是使用namespace:key的方式来做key。
2、不同服务对应的数据量吞吐量不一样共用一个实例容易导致一个服务把另一个服务的热数据挤出去
3、共用一个实例会导致服务之间的耦合与微服务架构的“数据库缓存私有”的设计原则是相悖的
正确的部署方式是 如上图各个服务私有化自己的数据存储对上游屏蔽底层的复杂性。
二、调用方缓存数据 如上图服务提供方缓存向调用方屏蔽数据获取的复杂性。服务调用方也缓存一份数据先读自己的缓存再决定是否调用服务这个有问题
该方案存在的问题是 1、调用方需要关注数据获取的复杂性耦合问题 2、更严重的服务修改db里的数据淘汰了服务cache之后难以通知调用方淘汰其cache里的数据从而导致数据不一致带入一致性问题 3、有人说服务可以通过MQ通知调用方淘汰数据额难道下游的服务要依赖上游的调用方分层架构设计不是这么玩的反向依赖问题
三、缓存作为服务与服务之间传递数据的媒介 如上图服务A和服务B约定好key和value通过缓存传递数据服务A将数据写入缓存服务B从缓存读取数据达到两个服务通信的目的
多个服务关联同一个缓存实例会导致服务耦合 1大家要彼此协同约定key的格式ip地址等耦合
2约定好同一个key可能会产生数据覆盖导致数据不一致
3不同服务业务模式数据量并发量不一样会因为一个cache相互影响例如service-A数据量大占用了cache的绝大部分内存会导致service-B的热数据全部被挤出cache导致cache失效又例如service-A并发量高占用了cache的绝大部分连接会导致service-B拿不到cache的连接从而服务异常
四、使用缓存未考虑雪崩 常规的缓存玩法如上图 服务先读缓存缓存命中则返回缓存不命中再读数据库
什么时候会产生雪崩 如果缓存挂掉所有的请求会压到数据库如果未提前做容量预估可能会把数据库压垮在缓存恢复之前数据库可能一直都起不来导致系统整体不可服务。
如何应对潜在的雪崩 提前做容量预估如果缓存挂掉数据库仍能扛住才能执行上述方案。
否则就要进一步设计。
常见方案一高可用缓存 如上图使用高可用缓存集群一个缓存实例挂掉后能够自动做故障转移。
常见方案二缓存水平切分 如上图使用缓存水平切分推荐使用一致性哈希算法进行切分一个缓存实例挂掉后不至于所有的流量都压到数据库上。 总结
1、服务与服务之间不要通过缓存传递数据
2、如果缓存挂掉可能导致雪崩此时要做高可用缓存或者水平切分
3、调用方不宜再单独使用缓存存储服务底层的数据容易出现数据不一致以及反向依赖
4、不同服务缓存实例要做垂直拆分。