架构师一口气说透分布式数据一致性问题

简介: 架构师一口气说透分布式数据一致性问题

这是我的第42篇原创


今天聊聊分布式环境下数据一致性的各种解决方案。有点烧脑,但是很有趣。


单体环境中的一致性问题

在传统关系型数据库环境(单体环境,或者叫单机)中,自己记录自己的就行了,单机环境不存在环境数据一致性的问题,倒是有并发操作数据一致性的问题。

对于一个数据库操作(专业术语叫:事务)来说,总结出4个特性:原子性、一致性、隔离性和持久性,合称ACID,我们不需要记那么多,只需要知道这些特性就是能保证数据库里的数据能够准确就行了。

  • 原子性(atomicity):一个事务中的所有操作,不可分割,要么全部成功,要么全部失败;
  • 一致性(consistency):一个事务执行前与执行后数据的完整性必须保持一致;
  • 隔离性(isolation):一个事务的执行,不能被其他事务干扰,多并发时事务之间要相互隔离;
  • 持久性(durability):一个事务一旦被提交,它对数据库中数据的改变是永久性的。

为了防止很多人一起操作,数据库会大量使用锁。锁就是在你操作这条数据的时候,加一个状态位,别人就无法操作了,类似于你上厕所的时候锁门一样

在上图中,有两个业务操作同时要修改关于的等级,但是业务操作3拿到锁了,所以操作之后,关羽的等级会变成35。业务操作2会因为这条记录被锁,而执行失败。

单机数据库环境(传统数据库),用的大多是悲观锁,意思就是用悲观的态度对待数据库修改,假定任何一次拿数据都可能遇到有人会修改:

  • 在你修改这条数据的时候,数据库会自动帮你对条记录上个锁,别人就无法在你改数据的时候同时修改了,这叫行锁;
  • 在你改这个表的时候,数据库也会给表上锁,这叫表锁;
  • 在你读取数据的时候上锁,就是读锁;
  • 在你写数据的时候上锁,这就是写锁。


分布式环境中的一致性问题

但是分布式环境,就不一样了。锁是面对并发任务的,解决多个任务抢一个资源的问题。分布式的时候也会面临这个问题,用的是分布式锁解决。

但是分布式本身会导致另外一个问题:分布式是集群环境,集群环境会存储多个副本,这个时候问题来了,既然一份数据会存储多个副本,集群怎么保证多个副本中的数据都是一样的?又怎么最终保证修改完数据后,我们去读取这个数据,就是刚刚改好的数据呢?

之所以有这个问题,就是因为分布式环境是多个小数据库组成集群,而网络通讯出现异常是集群建设的前提假设。也就是说,当业务操作1修改关羽等级的时候,就可能出现三个副本的数据不一致的情况。副本1、2已经改好了,副本3因为网络延迟,还没改好;这时业务操作2读取关羽等级的时候,如何保证能读取到最新的数据?这就是分布式环境中的数据一致性的额问题。


CAP定理

为了研究分布式数据一致性的问题,IT届吵吵了很久,2000年,Eric Brewer在国际会议上提出了CAP猜想,2002年,Lynch与其他人证明了Brewer猜想。这个被证明的CAP定理如下:

  • C一致性,即所有副本的数据都是一致的;
  • A高可用性,即一部分节点出现故障,能够响应客户端的读取请求

  • P分区容错性,分布式环境中,即出现网络分区时,也能使客户端拿到最新数据
  • C\A\P无法同时满足,最多只能同时满足其中两项。

其中P(分区容错性)是必须的,也就是说,我们只剩下CP和AP两个选择。要么抛弃数据一致性,追求高可用,要么抛弃高可用,追求数据一致性。而这两个结果都不是我们想要的。这可咋办?


BASE理论

这个世界总是有英雄站出来。eBay的架构师Dan Pritchett提出了BASE理论:

  • Basically Availble,基本可用(CAP中的A,高可用)
  • Soft-state,软状态/柔性事务
  • Eventual Consistency,最终一致性(CAP中的C,数据一致性)

所有的非金融的应用场景中,我们都遵循BASE理论,提供基本可用和最终一致性的服务。


Quorum机制

正是基于CAP和BASE理论,才有了Quorum机制,来解决分布式环境中数据一致性的问题。quorum机制又叫NRW机制,允许集群中有不一样的情况,但是只要能保证读取的时候有新的数据就行了,NRW即:

  • N=总节点数
  • R=read,读取的副本数
  • W=write,写入的副本数
  • 拿到最新数据所需要读取的副本数共需:R=N-W+1,W越大,写入的概率越小,读取的压力就越小;W越小,写入的概率越大,但是读取的节点数就越多,读取的性能越差

以上图为例,假设业务操作1进行修改关羽等级的时候,只有两个节点修改成功了,那么业务操作2进行读取的时候,必须要读取R=N-W+1=3-2+1=2个副本就能获取到最新的数据。你看,我们无需所有节点都一致,也能达成数据可用的效果。至于那个还没改好的节点,集群的数据同步机制会慢慢同步的。

那么有没有让所有节点都一次性全部成功写入的方法呢?有的,方法还不少。


强一致性解决方案

目前主流的强一致性解决方案有4种:

  • 2PC(2 phase commit)2阶段递交法
  • 3PC(3 phase commit)3阶段递交法
  • 4PC(笑) TCC(try-cancel-commit)试一下,不行就算了递交法
  • 消息中间件一致性解决方案

基本上跟TCP/IP三次握手的逻辑是一样的,2PC就是经过两个阶段,最后递交事务;3PC就是经过3个阶段,最后递交事务;TCC就是尝试、取消、递交;Half MQ就是先占坑,确认后再递交。

  • 2PC

2PC分为两个阶段:投票阶段和操作阶段。既然是投票,就得有一个人从中协调,要不怎么保证公平呢。所以2PC引入了一个协调者coordinator。一个分布式事务请求过来,先到协调者这边,协调者发起第一阶段即投票阶段,问所有的参与者:你们准备好了吗?所有人回答:准备好了!然后协调者发起第二阶段即递交阶段说:兄弟们,改吧。然后所有参与者发起本地事务把关于的等级改成34级。如果有人说:我这还没好,那么协调者也会发起第二阶段,只不过就变成了取消操作。

这就跟跑步比赛一样,第一阶段:裁判喊“准备~~”;第二阶段:裁判喊“跑”!

2PC比较耗资源,因为所有人的资源都锁着,一直等到所有人都答复了才能递交/取消,万一有节点甚至是协调者掉线那就麻烦了,全得等着。

  • 3PC

3PC是在2PC的基础上做了一些优化,在2PC的两个阶段之间,增加一个“预执行”Percommit的阶段,这样就变成了3个阶段:CanCommit、PerCommit、DoCommit。

这还跟跑步比赛一样,第一阶段:裁判喊“各就位~~”;第二阶段:裁判喊“预备~~~”;第三阶段:裁判喊“跑”!

3PC由于增加了预执行的操作,不会造成长时间锁资源,而且增加了超时自动递交的规则,效率大大增加。

但是万一有些节点超时的时候,有些节点告诉协调者他准备失败,然后协调者取消了任务咋办?这样还是会导致数据不一致。

  • TCC

TCC实际上是在业务逻辑层实现的,就是写业务代码的程序员完成的。2PC、3PC都是资源层实现的,是底层的逻辑封装好的。TCC就是Try、Cancel、Commit,这不是跟2PC一样的么?准备-取消or执行。所以很多程序员在看TCC和2PC的时候会感觉这俩很像。TCC的优势是应用自己定义数据库操作的粒度,降低锁的冲突,提高吞吐量。

TCC的问题在于每个业务都要写一次TCC。太繁琐了。有没有更好的解决办法呢?

  • 消息中间件一致性解决方案

其实消息中间件的一致性解决方案分为普通MQ和Half MQ 半消息(事务消息)。

现在我们不需要老是询问了,也不需要在业务逻辑里总去做各种尝试了。直接把需要别人改的东西扔到MQ里,其他组件到MQ里定时消费消息,按要求执行就OK了。完全解耦,简直完美!

但是MQ本身就有一些小问题,比如上游应用处理完了,把消息扔到MQ的时候出现问题了,那就完蛋了,前后数据就不一致了。这时候就需要半消息(事务消息)出场了。

Half MQ的意思就是把消息再分成两次,做一次类似于2PC的操作。

这样就避免了普通MQ的管杀不管埋的弊端。生产者需要等半消息确认成功后,才开始写本地事务。MQ这边已经确认消息ok,再投递给消费者,消费者那边进行消费就行了。


我们发现,一个很简单事情放到分布式环境之后就变得非常复杂。就好比是自己做决定和让集体做决定一样,太难了。自己决定的话,自己说了算就行了。集体决定得需要各种各样的规则,要不就大家各说各的,吵成一团。

好在计算机比人要简单的多,我们怎么说,它就怎么做。比起人来说,还是计算机要容易对付的多啊。


还有,各种问题,总是有解决方案的,我们总是在无穷逼近完美之中,但是貌似又不是能完美解决,总是有一些小小的问题。我站在巨人的肩膀上,感叹世界的不完美,是不是太作了?


以上~~~

相关实践学习
消息队列RocketMQ版:基础消息收发功能体验
本实验场景介绍消息队列RocketMQ版的基础消息收发功能,涵盖实例创建、Topic、Group资源创建以及消息收发体验等基础功能模块。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
4天前
|
设计模式 存储 算法
分布式系统架构5:限流设计模式
本文是小卷关于分布式系统架构学习的第5篇,重点介绍限流器及4种常见的限流设计模式:流量计数器、滑动窗口、漏桶和令牌桶。限流旨在保护系统免受超额流量冲击,确保资源合理分配。流量计数器简单但存在边界问题;滑动窗口更精细地控制流量;漏桶平滑流量但配置复杂;令牌桶允许突发流量。此外,还简要介绍了分布式限流的概念及实现方式,强调了限流的代价与收益权衡。
38 11
|
1月前
|
消息中间件 存储 Cloud Native
云原生架构下的数据一致性挑战与应对策略####
本文探讨了在云原生环境中,面对微服务架构的广泛应用,数据一致性问题成为系统设计的核心挑战之一。通过分析云原生环境的特点,阐述了数据不一致性的常见场景及其对业务的影响,并深入讨论了解决这些问题的策略,包括采用分布式事务、事件驱动架构、补偿机制以及利用云平台提供的托管服务等。文章旨在为开发者提供一套系统性的解决方案框架,以应对在动态、分布式的云原生应用中保持数据一致性的复杂性。 ####
|
6天前
|
设计模式 监控 Java
分布式系统架构4:容错设计模式
这是小卷对分布式系统架构学习的第4篇文章,重点介绍了三种常见的容错设计模式:断路器模式、舱壁隔离模式和重试模式。断路器模式防止服务故障蔓延,舱壁隔离模式通过资源隔离避免全局影响,重试模式提升短期故障下的调用成功率。文章还对比了这些模式的优缺点及适用场景,并解释了服务熔断与服务降级的区别。尽管技术文章阅读量不高,但小卷坚持每日更新以促进个人成长。
30 11
|
8天前
|
消息中间件 存储 安全
分布式系统架构3:服务容错
分布式系统因其复杂性,故障几乎是必然的。那么如何让系统在不可避免的故障中依然保持稳定?本文详细介绍了分布式架构中7种核心的服务容错策略,包括故障转移、快速失败、安全失败等,以及它们在实际业务场景中的应用。无论是支付场景的快速失败,还是日志采集的安全失败,每种策略都有自己的适用领域和优缺点。此外,文章还为技术面试提供了解题思路,助你在关键时刻脱颖而出。掌握这些策略,不仅能提升系统健壮性,还能让你的技术栈更上一层楼!快来深入学习,走向架构师之路吧!
42 11
|
21天前
|
消息中间件 架构师 数据库
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
45岁资深架构师尼恩分享了一篇关于分布式事务的文章,详细解析了如何在10Wqps高并发场景下实现分布式事务。文章从传统单体架构到微服务架构下分布式事务的需求背景出发,介绍了Seata这一开源分布式事务解决方案及其AT和TCC两种模式。随后,文章深入探讨了经典ebay本地消息表方案,以及如何使用RocketMQ消息队列替代数据库表来提高性能和可靠性。尼恩还分享了如何结合延迟消息进行事务数据的定时对账,确保最终一致性。最后,尼恩强调了高端面试中需要准备“高大上”的答案,并提供了多个技术领域的深度学习资料,帮助读者提升技术水平,顺利通过面试。
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
|
17天前
|
存储 算法 安全
分布式系统架构1:共识算法Paxos
本文介绍了分布式系统中实现数据一致性的重要算法——Paxos及其改进版Multi Paxos。Paxos算法由Leslie Lamport提出,旨在解决分布式环境下的共识问题,通过提案节点、决策节点和记录节点的协作,确保数据在多台机器间的一致性和可用性。Multi Paxos通过引入主节点选举机制,优化了基本Paxos的效率,减少了网络通信次数,提高了系统的性能和可靠性。文中还简要讨论了数据复制的安全性和一致性保障措施。
33 1
|
1月前
|
人工智能 运维 算法
引领企业未来数字基础架构浪潮,中国铁塔探索超大规模分布式算力
引领企业未来数字基础架构浪潮,中国铁塔探索超大规模分布式算力
|
25天前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
55 8
|
1月前
|
消息中间件 监控 Cloud Native
云原生架构下的数据一致性挑战与解决方案####
在数字化转型加速的今天,云原生架构以其轻量级、弹性伸缩和高可用性成为企业IT架构的首选。然而,在享受其带来的灵活性的同时,数据一致性问题成为了不可忽视的挑战。本文探讨了云原生环境中数据一致性的复杂性,分析了导致数据不一致的根本原因,并提出了几种有效的解决策略,旨在为开发者和企业提供实践指南,确保在动态变化的云环境中保持数据的完整性和准确性。 ####
|
1月前
|
存储 缓存 监控
解决分布式系统演进过程中数据一致性问题的方法
【10月更文挑战第24天】解决分布式系统演进过程中数据一致性问题是一个复杂而又重要的任务。需要综合运用多种方法和技术,根据具体的系统需求和场景,选择合适的解决方案。同时,不断地进行优化和改进,以适应不断变化的分布式系统环境。
71 4