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

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

这是我的第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版Serverless系列实例进行获取接入点、创建Topic、创建订阅组、收发消息、查看消息轨迹和仪表盘。
消息队列 MNS 入门课程
1、消息队列MNS简介 本节课介绍消息队列的MNS的基础概念 2、消息队列MNS特性 本节课介绍消息队列的MNS的主要特性 3、MNS的最佳实践及场景应用 本节课介绍消息队列的MNS的最佳实践及场景应用案例 4、手把手系列:消息队列MNS实操讲 本节课介绍消息队列的MNS的实际操作演示 5、动手实验:基于MNS,0基础轻松构建 Web Client 本节课带您一起基于MNS,0基础轻松构建 Web Client
相关文章
|
6月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1052 3
|
10月前
|
人工智能 安全 Java
智慧工地源码,Java语言开发,微服务架构,支持分布式和集群部署,多端覆盖
智慧工地是“互联网+建筑工地”的创新模式,基于物联网、移动互联网、BIM、大数据、人工智能等技术,实现对施工现场人员、设备、材料、安全等环节的智能化管理。其解决方案涵盖数据大屏、移动APP和PC管理端,采用高性能Java微服务架构,支持分布式与集群部署,结合Redis、消息队列等技术确保系统稳定高效。通过大数据驱动决策、物联网实时监测预警及AI智能视频监控,消除数据孤岛,提升项目可控性与安全性。智慧工地提供专家级远程管理服务,助力施工质量和安全管理升级,同时依托可扩展平台、多端应用和丰富设备接口,满足多样化需求,推动建筑行业数字化转型。
352 5
|
5月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的"神经网络",强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
存储 缓存 NoSQL
分布式系统架构8:分布式缓存
本文介绍了分布式缓存的理论知识及Redis集群的应用,探讨了AP与CP的区别,Redis作为AP系统具备高性能和高可用性但不保证强一致性。文章还讲解了透明多级缓存(TMC)的概念及其优缺点,并详细分析了memcached和Redis的分布式实现方案。此外,针对缓存穿透、击穿、雪崩和污染等常见问题提供了应对策略,强调了Cache Aside模式在解决数据一致性方面的作用。最后指出,面试中关于缓存的问题多围绕Redis展开,建议深入学习相关知识点。
812 8
|
9月前
|
监控 Linux 应用服务中间件
Linux多节点多硬盘部署MinIO:分布式MinIO集群部署指南搭建高可用架构实践
通过以上步骤,已成功基于已有的 MinIO 服务,扩展为一个 MinIO 集群。该集群具有高可用性和容错性,适合生产环境使用。如果有任何问题,请检查日志或参考MinIO 官方文档。作者联系方式vx:2743642415。
3090 57
|
10月前
|
负载均衡 NoSQL 算法
Redisson分布式锁数据一致性解决方案
通过以上的设计和实现, Redisson能够有效地解决分布式环境下数据一致性问题。但是, 任何技术都不可能万无一失, 在使用过程中还需要根据实际业务需求进行逻辑屏障的设计和错误处理机制的建立。
450 48
|
11月前
|
消息中间件 人工智能 监控
文生图架构设计原来如此简单之分布式服务
想象一下,当成千上万的用户同时要求AI画图,如何公平高效地处理这些请求?文生图/图生图大模型的架构设计看似复杂,实则遵循简单而有效的原则:合理排队、分工明确、防患未然。
430 14
文生图架构设计原来如此简单之分布式服务
|
9月前
|
消息中间件 缓存 算法
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
631 0
分布式开发:数字时代的高性能架构革命-为什么要用分布式?优雅草卓伊凡
|
11月前
|
并行计算 PyTorch 算法框架/工具
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
本文探讨了如何通过技术手段混合使用AMD与NVIDIA GPU集群以支持PyTorch分布式训练。面对CUDA与ROCm框架互操作性不足的问题,文章提出利用UCC和UCX等统一通信框架实现高效数据传输,并在异构Kubernetes集群中部署任务。通过解决轻度与强度异构环境下的挑战,如计算能力不平衡、内存容量差异及通信性能优化,文章展示了如何无需重构代码即可充分利用异构硬件资源。尽管存在RDMA验证不足、通信性能次优等局限性,但该方案为最大化GPU资源利用率、降低供应商锁定提供了可行路径。源代码已公开,供读者参考实践。
983 3
融合AMD与NVIDIA GPU集群的MLOps:异构计算环境中的分布式训练架构实践
|
11月前
|
人工智能 运维 监控
领先AI企业经验谈:探究AI分布式推理网络架构实践
当前,AI行业正处于快速发展的关键时期。继DeepSeek大放异彩之后,又一款备受瞩目的AI智能体产品Manus横空出世。Manus具备独立思考、规划和执行复杂任务的能力,其多智能体架构能够自主调用工具。在GAIA基准测试中,Manus的性能超越了OpenAI同层次的大模型,展现出卓越的技术实力。