DDD-复制滞后问题

235 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

本系列主要是《数据密集型应用系统设计》阅读笔记,本文记录复制滞后问题主题的笔记心得。

复制滞后

数据复制可容忍节点故障,还能提高可扩展性(采用多节点来处理更多的请求)和低延迟(将副本部署在地理上距离用户更近的地方)。 主从复制要求所有写请求都经过主节点,而任何副本只能接受只读查询。对于读操作密集的负载,将读请求分发给这些副本,可以减轻主节点负载并允许读请求就近满足。 很多的副本往往意味着异步复制,也意味着从副本读到落后于主节点的数据,这就是复制滞后带来的问题。从不同的副本读区,也可能读到不同的数据。 虽然副本最终能赶上主节点并保持一致。这种效应也被称为最终一致性。 总的来说,副本落后的程度理论上并没有很大,正常情况下,主节点和从节点上完成写操作直接的时间延迟可能不足1秒,这样的滞后,这实践中通常不会导致太大影响。但是,如果系统已接近设计上限,或者网络存在问题,则滞后可能情商增加到几秒甚至几分钟。

我前面写到了一个例子,导致较长复制延迟的一个典型例子(但又是非常合理的复制延迟),MySQL主备延迟竟17小时了!然而可能还要等2年...

复制的方案一般包括:

  • 基于语句的复制
  • 基于行的逻辑复制
  • 基于日志(WAL)的复制

从副本读取数据

那如果又要异步同步副本又要从副本读取数据(这对于密集型和偶尔写入的负载时是非常合适的方案。),有没有什么可行的策略呢?这可能需要分场景探讨。

读自己的写

许多应用让用户提交一些数据,接下来查看他们自己提交的内容。例如讨论主题的评论,但是当用户读取数据的时候,数据可能来自从节点。 用户写入不久就查看数据的话,新数据还没有到达从节点,这看起来是刚刚提交的数据丢失了。这需要保证当前用户马上能读到自己的数据,而对于其他的用户可以稍后才看到

那么应用应该怎么保证这样的一致性呢?

  • 当前用户可能会修改的内容,从主节点读;当前用户不可能修改的内容,从从节点读; 一般来说一个页面只有部分用户有权限编辑。

  • 跟踪页面的最新更新时间,如果是在更新后一分钟内,都从主节点读,否则从节点读。这要和监控从节点读滞后程度同步进行。

单调读

对于同一个用户来说,不能每次读到的内容都不相同。这个可以用Session保持的思想,用基于用户ID的哈希方法选择副本。

总结

对于又要异步同步副本又要从副本读取数据,在应用层可以提供比底层数据库更强有力的保证,例如只在主节点上进行特定类型的读取。代价是,应用层代码中处理这些问题通常会非常复杂,且容易出错。

另外,在分布式数据库中,不同的分区独立运行,因此不存在全局写入顺序,可能读到的数据会发生反常。 为了防止这样的问题发生,需要确保有因果顺序关系的写入都交给一个分区来做。