前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >异地多活架构进阶:如何解决写后立即读场景问题?

异地多活架构进阶:如何解决写后立即读场景问题?

作者头像
腾讯云开发者
发布2024-11-27 09:20:51
发布2024-11-27 09:20:51
2740
举报
文章被收录于专栏:【腾讯云开发者】

《醍醐灌顶!异地多活架构设计看这篇就够了》一文中,基于容灾需要,讨论了数据写入的架构模型。数据读取方面,重点在于解决读取请求的负载分担、路由选择的问题,对于容灾架构的选择影响不大。不过,其中的“写后立即读”场景,是个一致性范畴的问题,即写入的数据和写入后读到的数据是否一致的问题,本文不展开讨论各种一致性模型,只关注“写后立即读”的要求是数据写入后短时间内到来的读请求能够读取到最新写入的值这一具体问题,这是互联网应用中数据读取中比较独特和典型的场景,值得深入探讨,本文尝试分析一下这个问题的细节并探讨相应的解决思路。

关注腾讯云开发者,一手技术干货提前解锁👇

01、问题细节剖析

1.1 解决思路方向

写后立即读的问题是指一份数据在写完之后,很短时间内来读这份数据,读不到最新写入的值。解决这个问题,就需要读操作能够从最新写入了数据的节点获取数据,有几个方向:

  1. 单写单读,将所有需要写后立即读的请求都路由到唯一的写入点读取,可以保证能够读到最新写入的值;
  2. 多写多读,保证写入点个数(W)和读取点个数(R)的和大于节点总数(N),即 N < R + W,也就是 NRW 方案;
  3. 读时复制,在读节点收到读请求的时候,检测本节点的被读数据是否是最新的,不是的话,就等把最新的数据复制到位再返回。

在接入层、逻辑层、数据层的基础架构中,数据库层面具有最全貌的数据复制细节,可以刻画最精确的数据状态,如果能从数据库层面来着手,将从根本上解决写后立即读问题且做到业务无关,业务侧也会更轻松,例如上面的读时复制在数据库层面就比较容易做。不过,很多业务并不是运行在这么理想的数据库系统之上,还是不得不从业务侧来考虑解决思路。

NRW 是各节点对等的议会制度,用多数派解决读到新值的问题,根据读写量级压力调节 R 和 W 的数值来使系统达到一个较好的状态。这种模型,有请求量放大的问题,不管怎么调节 R 和 W 的数值,都只是把 R 和 W 的负载情况相对均衡,整体的读写代价增加是不可避免的。在跨城容灾场景下,NRW 方案成本较高,不太能接受,因为:

  1. 如果每次都要读多个节点,那基本上就面临着读请求都要跨城;
  2. 如果每次都就近读1个节点,那就要求写入的时候要写入所有节点。

所以,很多业务都不采用对等机制来维护数据,而是采用主从模式,主写点写入之后,出于容灾的考虑,会等主写点数据复制到部分从节点后才算成功写入。为什么不复制到所有的从节点呢?因为重点在容灾,保证在主写点之外有冗余数据,并不追求各节点的数据完全一致。这样,就等同于 NRW 中的 W 是 1 < W < N,但是这一批写入点不是对等的,而是通过主从复制达到写 W 个节点的效果。读操作方面,基本都是读1次,这样就不能满足 N < R + W 了。在这种主从架构下,要想写后立即读到新值,基本就是去读主写点了,退化成了“单写单读”的情况,这就是本文要讨论的模型了。

1.2 业务架构案例

为了避免过于宽泛,下面以作者工作中碰到的典型的三地五中心跨城容灾架构来展开讨论,希望针对该典型模型的探讨能把问题核心聊清楚,在结合实际情况设计方案的时候有所启发。关于下图架构的几点说明:

  • 主从复制模式是半同步模式,只要求主写点收到2份数据复制确认,保证在本城之外有一份冗余数据后即提交成功,但是2份数据复制确认具体是哪2个从节点来的,不确定;
  • 数据层为了屏蔽容灾、运营动作导致的读写节点变更对上层调用放透明,通过名字服务提供读写访问,提供了写名字、读名字,写名字指向主写点,读名字指向所有节点提供就近访问能力;
  • 如果要应对写后立即读,那么在做读操作路由的时候,得选择写名字获得主写点进行数据读取。

1.3 解决方案模型

从业务架构案例的架构图来看,好像和NRW的多R情况类似,每次读都在做跨城读取。其实不然,可以把“写后立即读”细拆如下几点来看:

  1. 写源:即写操作的发起来源,大抵可以分两类,一类来源是用户触发,另一类是后台触发。差别在于,用户触发一般是单个细粒度的写更新,后台触发往往是大批量的写更新,结合读需要,二者对于写点的压力是不同的;
  2. 架构:在一主N从的存储架构下,数据在主写节点写入之后,还没有同步到某从节点的情况下,读请求打到该从节点上,就产生了读不到新值的问题;
  3. 时效:一个是数据写入之后读请求到来之前的时间差,记写后读间隔,也就是“写后立即读”的立即是多立即;另一个是数据写入后和复制到从的时间差,记写复制时延。如果写复制时延大于写后读间隔,就会产生读不到新值的问题。基本上很难保证写复制时延一定小于写后读间隔;
  4. 读者:即写入数据的读取使用方,和写源类似,一类是真实用户,一类是后台程序。后台程序基本上都是可以采用异步的方式解决即可,大都不用考虑“立即”的问题,写后立即读重点在于解决用户的“立即读“需要;
  5. 场景:一份数据的使用场景基本上都是多样的,并不是所有的场景都有写后立即读的诉求,往往都是解决少量核心场景的需要即可;
  6. 范围:在数据全集中,一个时间段内有多少数据是需要面临写后立即读问题?从写源分析来看,用户触发的写显然是小范围的,后台触发的写是大范围的,但是这种大批量往往可以做时间段拆分,可以缩减范围,再考虑真实用户带来的读,也就是小范围的了。“小范围”结合“少场景”,这就是一个典型的“局部性”问题。

可以看到,解决写后立即读问题,并不需要所有请求都去主写节点,只要把“刺头”挑出来即可,也就是要寻找一种方案:该方案需要标识出哪些数据有写入操作,在特定时间段内特定场景的读请求到来时,数据不确定是否同步到从副本的情况下,引导这部分请求去读主写点。在异地多活场景下,读请求到来的接入点所在地和数据所在地可能是跨城的,如果读请求的时延要求比较敏感,还需要在写入后的短时间内新数据能够提供就近访问,避免跨城。总结一下要点如下:

  1. 区分业务场景;
  2. 标识写入数据;
  3. 判断时延要求;
  4. 提供就近访问。

这4点,是基于局部特征,层层下钻的过程,下面分别来看看。

02、区分业务场景

区分业务场景,指的是如何把有写后立即读的“刺头”场景标识出来。基本可以从服务调用方和服务提供方两端视角来看:

  1. 服务调用方视角,服务的不同调用方根据需要,在调用服务的时候申明请求是否有写后立即读的诉求,可以通过服务提供方在协议上定义协议字段让调用方申明诉求;
  2. 服务提供方视角,服务提供方为不同的调用方分配标识,在服务提供方内部管理调用方属性,将有写后立即读诉求的调用方标识出来;
  3. 一般来说,服务提供方视角的方式具有更好的可控可管特性,不太容易被调用方滥用,比较推荐。

明确了读写场景,每个用户读请求到来的时候,判断一下场景属性,如果是不需要写后立即读的场景,访问本地就近的数据副本即可,无需关心该副本是否有最新数据。对于有写后立即读需要的场景,则需要做进一步的判断处理。

03、标识写入数据

如何标识某份数据有写入,有两个方向:

  1. 用户触发写入的场景,可以在给用户回包的时候,把写入的信息带上,立即读的时候回带,后台可以直接用来做判断;
  2. 不论哪种写操作发起来源,由后台统一记录最近写入的信息,请求到来的时候,先访问一下记录的写入信息,再行判断是否有最近写入。这里可以更进一步,不光记录数据是否有写入的标识,还可以考虑把完整的写入数据也记录下来;
  3. 后台统一记录的处理方式更有普适性,上面提到的两种典型场景,不论是用户写后立即读,还是后台写后用户立即读,都能很好应对。

不管是用户端传递携带写入记录标识,还是后台存放写入记录标识,都在数据库之外引入了一套额外的依赖机制,会增加复杂度,引入的机制可靠性上相较于数据库来说,也是会有所折损的。不过,写后立即读主要解决的是用户体验层面的问题,应该说一般是能够接受的。当然,具体还是需要结合业务实际仔细评估。

有了写入数据的标识,用户读请求到来的时候,先读取一下最近写入的标识,判断一下,如果最近没有写入,说明本地副本已经有了最新的数据,访问本地就近的数据副本即可。如果最近有写入,那么需要进一步判断处理。

04、判断时延要求

读场景往往有较高的性能要求,处理时延是一个很重要的指标,在异地多活的跨城架构中,都会提供本地的就近访问副本,以达到低延时的目标。不过,普通的读副本并不具备提供最新写入数据的访问能力。写后立即读的情况,其时延需要要考虑的主要因素包括:

  1. 跨城往返时延大约 30ms,这种时延是否可以接受?
  2. 读请求需要读取的数据,是否有多份?多份数据是否都有写后立即读的要求?
  3. 多份数据的读取,是有前后依赖需要串行读取?还是可以并发读取?
  4. 上面的几个问题,需要综合考虑整个业务多种场景,且适当考虑未来,当前可以满足需要,未来是否依然?

明确了业务的时延要求后,对于要读到最新值的读请求,如果时延要求没那么高的,引导读主写点即可,否则,就需要提供就近访问能力。下面是以比较通用的后台记录写入标识模式来说明时延的示意图。

05、提供就近访问

写后立即读的就近访问,要求提供就近访问的副本保证有最新数据,而我们讨论的数据层架构是保证不了的,这就需要业务层在把数据成功写入数据层后,额外往各读请求接入所在地写一份数据,以达到就近访问的目的。这种情况下,可以扩展上文“标识写入数据”提到的写入记录,不光记录写入标识,同时记录写入的具体数据。下面是简化的处理示意图,就近副本的定位,是用来解决写后立即读的问题,结合读请求不会污染数据,以及业务侧来实现强一致比较麻烦,设计上可以轻量化,例如:

  1. 第2步写入数据之后,就可以并行回包,以及并行写多份就近副本了;
  2. 在写就近副本的时候,可以采用轻量的 CAS 写入保障,失败的情况下,可以适当增加重试次数;
  3. 增加短时的异步对账,检测就近副本和主写点之间的差异,让失败的影响控制在很小的时间范围之内;
  4. 对于异步写入就近副本的方式,可以提供封装好的 API,提供给有需要的服务,降低使用成本。

06、解决思路总结

写后立即读是比较典型的局部性问题,如果能够在数据库层面根据主从数据复制细节,刻画局部特征,解决起来会事半功倍。本文根据该问题的局部性特征,从业务侧角度,总结了区分业务场景、标识写入数据、判断时延要求、提供就近访问四步的解决思路,层层递进下钻,细化局部特征。

-End-

原创作者|熊章俊

你的业务是否有类似的问题,具体实践是怎样的呢?欢迎评论留言。我们将选取1则优质的评论,送出腾讯云定制文件袋套装1个(见下图)。12月4日中午12点开奖。

📢📢欢迎加入腾讯云开发者社群,享前沿资讯、大咖干货,找兴趣搭子,交同城好友,更有鹅厂招聘机会、限量周边好礼等你来~

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-11-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云开发者 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 01、问题细节剖析
  • 02、区分业务场景
  • 03、标识写入数据
  • 04、判断时延要求
  • 05、提供就近访问
  • 06、解决思路总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档