DDIA 读书分享 第五章:Replication,多主模型

简介: DDIA 读书分享会,会逐章进行分享,结合我在工业界分布式存储和数据库的一些经验,补充一些细节。每两周左右分享一次,欢迎加入,网站在这里: https://ddia.qtmuniao.com/ 。我们有个对应的分布式&数据库讨论群,每次分享前会在群里通知。如想加入,可以加我的微信号:qtmuniao,简单自我介绍下,并注明:分布式系统群。


单主模型一个最大问题:所有写入都要经过它,如果由于任何原因,客户端无法连接到主副本,就无法向数据库写入。

于是自然产生一种想法:多主行不行?

多主复制(multi-leader replication):有多个可以接受写入的主副本,每个主副本在接收到写入之后,都要转给所有其他副本。即一个系统,有多个写入点

多主模型应用场景

单个数据中心,多主模型意义不大:复杂度超过了收益。总体而言,由于一致性等问题,多主模型应用场景较少,但有一些场景,很适合多主:

  1. 数据库横跨多个数据中心
  2. 需要离线工作的客户端
  3. 协同编辑

多个数据中心

假设一个数据库的副本,横跨多个数据中心,如果使用单主模型,在写入时的延迟会很大。那么每个数据中心能不能各配一个主副本?

image.png

                         multi-leader across multiple data centers

单主和多主,在多数据中心场景下的对比:

对比项 单主模型 多主模型
性能 所有写入都要路由到一个数据中心 写入可以就近
可用性 主副本所在数据中心故障,需要有个切主的过程 每个数据中心可以独立工作
网络 跨数据中心,写入对网络抖动更敏感 数据中心间异步复制,对公网容错性更高

但是多主模型在一致性方面有很大缺陷:如果两个数据中心同时修改同样的数据,必须合理解决写冲突。另外,对于数据库来说,多主很难保证一些自增主键、触发器和完整性约束的一致性。因此在工程实践中,多主用的相对较少。

离线工作的客户端

离线工作的一个应用的多个设备上的客户端,如果也允许继续写入数据。如:日历应用。在电脑上和手机上离线时如果也支持添加日程。则在各个设备联网时,需要互相同步数据。

则离线后还继续工作的多个副本,本质上就是一个多主模型:每个主都可以独立的写入数据,然后在网络连通后解决冲突。

但,如何支持离线后正常地工作,联网后优雅的解决冲突,是一个难题。

Apache CouchDB 的一个特点便是支持多主模型。

协同编辑

Google Docs 等类似 SaaS 模式的在线协同应用越来越流行。

这种应用允许多人在线同时编辑文档或者电子表格,其背后的原理,与上一节离线工作的客户端很像。

为了实现协同,并解决冲突,可以:

  1. 悲观方式。加锁以避免冲突,但粒度需要尽可能小,否则无法允许多人同时编辑一个文档。
  2. 乐观方式。允许每个用户无脑写入,然后如果有冲突,交由用户解决。

git 也是一个类似的协议。

处理写入冲突

多主模型最大的问题是:如何解决冲突。

image.png

write conflict

考虑 wiki 一个页面标题的修改:

  1. 用户 1 将该页面标题从 A 修改到 B
  2. 用户 2 将该页面标题从 A 修改到 C

两个操作在本地都修改成功,然后异步同步时,会出现冲突。

冲突检测

有同步或者异步的方式进行冲突检测。

对于单主模型,当检测到冲突时,由于只有一个主副本,可以同步的检测冲突,从而解决冲突:

  1. 让第二个写入阻塞,直到第一个写完成。
  2. 让第二个写入失败,进行重试。

但对于多主模型,两个写入可能会在不同主副本立即成功。然后异步同步时,发现冲突,但为时已晚(没有办法简单决定如何解决冲突)。

虽然,可以在多主间使用同步方式写入所有副本后,再返回请求给客户端。但这会失掉多主模型的主要优点:允许多个主副本独立接受写入。此时,蜕化成单主模型。

冲突避免

解决冲突最好的方式是在设计上避免冲突

由于多主模型在冲突发生后再去解决会有很大的复杂度,因此常使用冲突避免的设计。

假设你的数据集可以分成多个分区,让不同分区的主副本放在不同数据中心中,那么从任何一个分区的角度来看,变成了单主模型。

举个栗子:对于服务全球用户的应用,每个用户就近固定路由到附近的数据中心。则,每个用户信息都有唯一的主副本。

但如果:

  1. 用户从一个地点迁移到了另一个地点
  2. 某个数据中心损坏,导致路由变化

就会对该设计提出一些挑战。

冲突收敛

在单主模型中,所有事件比较容易进行定序,因此我们总可以用后一个写入覆盖前一个写入。

但在多主模型中,很多冲突无法定序:从每个主副本来看,事件顺序是不一致的,并且没有哪个更权威一些,那么就无法让所有副本最终收敛(convergent)

此时,我们就需要一些规则,来让其收敛:

  1. 给每个写入一个序号,并且后者胜。本质上是使用外部系统对所有事件进行定序。但可能会产生数据丢失。举个例子,对于一个账户,原有 10 元,客户端 A - 8,客户端 B - 3,任何一个单独成功都有问题。
  2. 给每个副本一个序号,序号更高的副本有更高的优先级。这也会造成低序号副本的数据丢失。
  3. 提供一种自动的合并冲突的方式。如,假设结果是字符串,则可以将其排序后,使用连接符进行链接,如在之前 Wiki 的冲突中,合并后的标题为 “B/C”
  4. 使用程序定制一种保留所有冲突值信息的冲突解决策略。也可以将这个定制权,交给用户。

自定义解决

由于只有用户知道数据本身的信息,因此较好的方式是,将如何解决冲突交给用户。即,允许用户编写回调代码,提供冲突解决逻辑。该回调可以在:

  1. 写时执行。在写入时发现冲突,调用回调代码,解决冲突后写入。这些代码通常在后台执行,并且不能阻塞,因此不能在调用时同步的通知用户。但打个日志之类的还是可以的。
  2. 读时执行。在写入冲突时,所有冲突都会被保留(如使用多版本)。下次读取时,系统会将所有数据本版本返回给用户,进行交互式的或者自动的解决冲突,并将结果写回系统。

上述冲突解决只限于单个记录、行、文档层面。

TODO(自动冲突解决)

界定冲突

有些冲突显而易见:并发写同一个 Key。

有些冲突则更隐晦,考虑一个会议室预订系统。预定同一个会议室不一定会发生冲突,只有预定时间段有交叠,才会有冲突。

多主复制拓扑

复制拓扑(replication topology)描述了数据写入从一个节点到另一个节点的传播路径。

在只有两个主副本时,拓扑是确定的,如图 5-7。Leader1 和 Leader 都得把数据发给对方。但随着副本数的增多,数据复制拓扑就会有多种选择,如下图:

image.png

                        multi-leader topologies

上图表示了 ≥ 4 个主副本时,常见的复制拓扑:

  1. 环形拓扑。通信跳数少,但是在转发时需要带上拓扑中前驱节点信息。如果一个节点故障,则可能中断复制链路。
  2. 星型拓扑。中心节点负责接受并转发数据。如果中心节点故障,则会使得整个拓扑瘫痪。
  3. 全连接拓扑。每个主库都要把数据发给剩余主库。通信链路冗余度较高,能较好的容错。

对于环形拓扑和星型拓扑,为了防止广播风暴,需要对每个节点打上一个唯一标志(ID),在收到他人发来的自己的数据时,及时丢弃并终止传播。

全连接拓扑也有自己问题:尤其是所有复制链路速度不一致时。考虑下面一个例子:

image.png

                                        writes wrong order

两个有因果依赖的(先插入,后更新)的语句,在复制到 Leader 2 时,由于速度不同,导致其接收到的数据违反了因果一致性。

要想对这些写入事件进行全局排序,仅用每个 Leader 的物理时钟是不够的,因为物理时钟:

  1. 可能不能够充分同步
  2. 同步时可能会发生回退

可以用一种叫做版本向量(version vectors)的策略,对多个副本的事件进行排序,解决因果一致性问题。下一节会详细讨论。

最后忠告:如果你要使用基于多主模型的系统,一定要知晓上面提到的问题,多做测试,确保其提供的保证符合你的使用场景。


我是青藤木鸟,一个喜欢摄影的分布式系统程序员。欢迎关注我的公众号:木鸟杂记。如果觉得不错,就点个在看分享一下吧。如果想找人交流分布式系统和数据库,欢迎来论坛:https://distsys.cn/ 提问,点击下方阅读原文可直达。

参考资料

[1]DDIA 读书分享会: https://docs.qq.com/sheet/DWHFzdk5lUWx4UWJq

相关文章
zabbix 自动发现
zabbix 自动发现
|
NoSQL Redis 数据库
docker-compose 自动管理 数据库
docker-compose 自动管理 数据库
444 3
|
机器学习/深度学习 数据采集 算法
Python使用随机森林模型进行电影评分预测
Python使用随机森林模型进行电影评分预测
1836 1
Python使用随机森林模型进行电影评分预测
|
存储 安全 数据库
对称加密的日常实践应用:以AES为例的加密解密指南
**摘要:** 本文介绍了对称加密算法AES在数据安全中的应用,强调了其在文件、通信和数据库加密中的重要性。通过Python示例展示了如何使用`cryptography`库实现AES-256的加密和解密,涉及密钥生成、CBC模式及PKCS7填充。同时,提醒注意密钥管理、模式选择和填充方式的选择对加密安全性的影响。
1447 1
|
算法
【MATLAB】WOA鲸鱼算法优化的VMD信号分解算法
【MATLAB】WOA鲸鱼算法优化的VMD信号分解算法
1278 0
【MATLAB】WOA鲸鱼算法优化的VMD信号分解算法
|
机器学习/深度学习 算法 安全
【SSA-LSTM】基于麻雀算法优化LSTM 模型预测研究(Matlab代码实现)
【SSA-LSTM】基于麻雀算法优化LSTM 模型预测研究(Matlab代码实现)
778 0
|
负载均衡 前端开发 Java
【Spring cloud】OpenFeign详解(超详细)
【Spring cloud】OpenFeign详解(超详细)
1810 0
|
存储 JavaScript Shell
vue项目打包后提交到git上为什么没有dist这个文件?
vue项目打包后提交到git上为什么没有dist这个文件?
vue项目打包后提交到git上为什么没有dist这个文件?
|
存储 算法 大数据
NLPIR智能语义技术让大数据挖掘更简单
NLPIR大数据语义智能分析平台主要有精准采集、文档转化、新词发现、批量分词、语言统计、文本聚类、文本分类、摘要实体、智能过滤、情感分析、文档去重、全文检索、编码转换等十余项功能模块,平台提供了客户端工具,云服务与二次开发接口等多种产品使用形式。
2448 0
|
机器学习/深度学习 人工智能 算法
吴恩达导师Michael I.Jordan学术演讲:如何有效避开鞍点(视频+PPT)
最近,加州大学伯克利分校教授Michael I. Jordan(吴恩达的导师)进行了一场演讲:使用合理的扰动参数增强的梯度下降法可有效地逃离鞍点,视频+图文,全是干货。
4325 0