分布式理论基础



点击上方 疾风先生能够订阅哦

在这一篇中主要讲述分布式基础理论知识,其中包含CAP定理,ACID以,BASE理论以及一致性协议分析.有了CAP定理的基础,可以帮助咱们在根据业务特色进行分区容错一致性模型设计中提供解决问题的方向以及架构设计方案的设计与落地实现.同时须要区分数据库ACID的AC与咱们的分布式AC存在的联系与差别,其次,在分布式网络中,为避免节点故障抑或是网络延迟等问题致使系统服务出现大量的不可用问题,那么对于BASE理论实现的技术方案有哪些.最后讲述分布式系统中数据的一致性问题.
java




CAP定理python

网络分区容错(Partition tolerance)
  • 网络连通性
服务节点之间的网络通讯正常

在上述能够看到,服务A集群与冗余服务A1与A2节点造成一个对外闭环的集群,同理服务B也构成一个闭环集群.此时发起一个请求操做,须要经过服务A与服务B进行协做,在服务B节点正常运做状况下,这个时候的分布式网络是处于连通状态,服务A与服务B之间可以进行正常网络通讯完成数据协做.nginx

  • 网络分区web

服务节点之间的网络通讯发生中断或者是延迟响应出现短期的中断.

在上述的图中,一个请求操做须要经过服务节点A与服务节点B完成协做,可是若是服务B没有作集群部署,此时服务节点B发生故障或者是网络延迟,那么这个时候服务节点A与服务节点B之间将没法进行通讯,此时服务A将与服务B失去联系,即服务节点之间发生网络通讯中断而产生网络分区,此时服务A节点与服务B节点被划分为彼此独立互不相连的节点服务,即以下:

  • 分区容错算法

服务节点之间的网络通讯可以经过容错处理手段来保证服务节点之间互通.

为了保证上述的服务A与服务B可以正常通讯,即便服务B节点发生故障,也能够经过集群服务B的其余节点B1或者是B2来继续为服务A提供服务,以保证服务A节点可以正常完成请求操做的处理.而对于这种状况称为分区容错,在分布式环境中,节点故障与网络延迟是没法避免的,所以为了保证咱们的分布式系统服务可以正常运做,那么在进行架构设计的时候就须要作到知足CAP定理中的分区容错(Partition Tolerance)数据库

一致性(Consistency)
客户端每次发起的读取请求,不管是访问分布式集群中的哪一个节点,都可以读取到最新的一份写入数据.
分布式一致性的理解以下:

在上述发起一个事务操做请求的时候,集群的服务A接收事务请求操做v=v1的处理,此时服务A须要并未将数据同步到冗余服务节点A1以及A2,而这个时候向集群A服务发起读取请求操做,因为集群服务的负载均衡分配算法会将读取请求转发到服务A1,可是此时存储数据v的服务节点A1并未从服务A同步到最新的数据v,此时客户端读取到数据v并不是是最新写入的数据,致使读取数据结果不一致.这个时候为了保证数据的一致性,就须要要求服务节点A在接收到数据状态变动的同时也须要向集群服务中的冗余服务节点发起数据同步操做,保证其余冗余服务节点与服务节点A最新写入的数据是一致的.也就是说分布式系统的一致性须要保证在有状态的服务节点下数据的读取是最新写入的,即:后端

而对于数据在分布式环境进行同步操做的时候,会存在如下两个核心问题:
  • 节点发生故障如何保证读取的数据是一致性的,即存在节点故障问题
  • 节点之间须要经过网络进行数据同步,即存在网络延迟问题
可用性(Availability)
要实现可用性,须要牺牲数据的一致性,也就是没法保证数据看到都是最新的一份.

咱们先来思考分布式系统中哪些地方会存在不可用的状况:api

  • 单节点故障致使服务的不可用.微信

  • 服务与服务之间调用依赖,被调用方服务发生故障,调用方服务也会发生故障致使不可用.网络

  • 当发起一个事务请求操做经过服务A来调用服务B的时候,此时服务节点B须要同步数据到其余冗余服务节点B1以及B2,若是此时有读取请求的操做来访问服务节点A,为了保证看到的数据是最新的,这个时候因为B1或者B2节点未完成数据同步可是要保证数据读取最新这个时候会致使服务A出现短暂的不可用,或者称为同步等待数据返回.

经过上述咱们看到,节点故障咱们能够经过分区容错解决,也就说在分布式系统设计中分区容错与可用性是能够并存的,而服务调用方发生故障致使不可用,也能够认为是分区容错的一种手段,只不过是在应用层次经过过载保护或者是降级进行控制;然而对于后者,咱们看到要保证数据的一致性,读取请求须要进行同步等待服务节点完成数据的同步操做以后再进行返回,那么在这个等待的时间窗口内,对于客户端而言,读取请求资源的操做出现短期内的不可用.

由此可知,在咱们的分布式环境下,为了保证节点与节点之间的正常通讯,即保证分布式系统服务节点的网络连通性,咱们必需要知足分区容错这一特性,而C与A只能知足其一.但对于RDBMS系统而言,好比MySQL或者是Oracle的关系型数据库,这类传统的关系型数据库因为设计的初衷都不是考虑分布式系统设计,而是保证一致性以及系统可用,尤为是事务操做的一致性,读写实时性抑或是复杂SQL的多表查询,放到分布式系统中实现要更为复杂.因而才有了分布式数据库,好比MongoDB知足CP原则,而CouchDB知足AP原则.同时对于关系型数据库,好比MySQL,咱们会经过冗余服务复制来知足分布式系统设计的AP抑或是经过CP + AP的方式实现分库分表的集群.

CAP定理应用以下图所示:

所以,当咱们在思考分布式系统设计的时候,须要基于CAP定理从业务数据层面去思考咱们的架构设计方案.




ACID理论

事务的ACID
  • 原子性(Atomicity)

是指一个数据库操做的事务不可分割的工做单位,要么操做成功,要么操做失败.

  • 一致性(Consistency)

一致性是指事务开启以前以及开启以后数据库的完整性约束没有被破坏.

  • 隔离性(Isolation)

多个事务并发访问的时候,两个事务之间彼此相互独立而且互不影响,一个事务不该该影响其余事务运行效果.

  • 持久化(Durability)

意味着在事务完成之后,该事务对数据库所做的更改便持久的保存在数据库之中,并不会被回滚

  • 分布式系统如何保证事务的ACID

当咱们了解到一个操做具有ACID特性的时候,咱们基本上能够认为完成了一个事务操做,而在分布式系统中,实现一个知足ACID的请求操做须要考虑到网络以及节点故障问题等问题,因而就须要经过分布式事务协议来保证完成一个具有ACID特性的请求操做.

2PC事务协议
  • 工做原理

分为投票阶段以及提交阶段,集群服务节点扮演角色有协调者(Coordinator)以及事务的参与者(Cohort).

其工做流程以下:

投票阶段

首先向集群服务节点发起一个事务请求操做,即v=v1,这个时候集群服务选举一个协调者来负责接收事务请求的操做,并由协调者统一指挥相应的事务操做.这个时候接收到事务请求以后协调者将向集群服务各个参与事务的节点发起v=v1操做请求,询问是否容许进行操做.

这个时候服务集群参与者的节点接收到协调者的操做请求,并在执行当前的操做请求的时候进行undo以及redo的日志记录,经过undo日志实现回滚,redo日志实现持久化,最后将响应结果返回给协调者.

提交阶段 - 成功提交

协调者接收到参与者节点进行事务执行操做准备的响应,根据参与者节点的响应结果,为了保证事务的ACID特性,若是全部的参与者节点都容许进行事务v=v1的请求操做时,那么这个时候协调者就会向各个参与者节点服务发起commit的请求并等待各个参与者节点事务操做结果的响应.

参与者接收到协调者的提交请求以后,这个时候每一个参与者节点就能够正常完成单点机器的事务操做,即知足事务ACID的特性,完成事务操做以后每一个参与者节点都会向协调者发起事务操做结果的响应.这个时候协调者接收到事务操做响应的结果并向客户端给予事务操做成功的响应.

提交阶段 - 失败提交

  • 参与者3因网络缘由致使超时未响应

  • 参与者3拒绝v=v1的请求操做

对于实现分布式事务的ACID,要保证数据的强一致性,所以只要其中有一个参与者节点在进行事务投票阶段发生上述问题,这个时候协调者会视为abort,则协调者下一步将会发起abort的回滚操做,即:

协调者根据参与者节点给予的响应结果做出abort的回滚策略,此时向各个参与者节点发起abort的回滚操做,即:

这个时候参与者节点接收到事务回滚操做,将原先保存的undo数据进行恢复,而后将回滚的操做结果响应给协调者,协调者接收到全部参与者节点回滚的响应结果,向客户端发起事务操做失败的响应结果.

2PC产生阻塞
  • 协调者发起请求的时候会等待参与者的响应结果
  • 参与者接收到协调者发起的请求并给予响应此时也处于等待状态,等待提交redo或者回滚undo
  • 此时参与者接收到应答指令执行相应的操做以后,协调者会继续处于等待参与者处理的结果响应
  • 同时,既然是分布式系统,必然离不开网络服务之间的通信以及机器节点的故障问题,于是若是协调者产生不可用,此时全部的参与者将会一直处于阻塞状态
2PC产生数据不一致
  • 当协调者向参与者发起提交或者是回滚操做的时候,其中有一个参与者服务节点产生不可用的状况,这个时候参与者节点将没法接收到提交或者回滚信息,那么这个时候就会产生数据不一致.
2PC的总体流程总结

3PC事务协议

在实际应用场景中,3PC的使用场景并很少,大部分是基于2pc的实现来完成分布式事务,甚至是为了保证数据的强一致性会采起TCC的事务协议来完成,对于3PC现简单阐述以下:

3PC提交过程说明
  • 协调者服务节点发起事务请求给到参与者节点询问是否容许事务请求提交
  • 参与者节点接收到事务请求提交以后将当前数据记录到undo日志中,以便于后续请求的超时或者是无响应进行事务的回滚,这个时候记录undo日志以后返回给协调者告知请求提交的结果
  • 协调者此时若是没有接收到参与者的请求提交响应回复抑或是拒绝请求提交将终止当前操做再也不继续下一步;若是收到容许请求提交操做,则会向参与者节点发起预提交请求到参与者节点中
  • 参与者节点若是没有接收到预提交的请求抑或是网络延迟中断,那么就会将上次的undo日志进行数据回复并丢弃当前的事务操做;若是能正确接收到预提交的请求操做,那么这个时候会将更新的数据记录到redo日志中,以便于后续进行持久化.
  • 对于协调者而言,若是正确接收到预提交请求的ACK响应,那么这个时候将会执行请求提交到参与者节点;若是没有接收到ACK的响应抑或是网络超时问题,将会直接丢弃当前的事务操做.
  • 而对于第三阶段的确认提交,参与者节点不管是网络中断仍是超时抑或是正常接收到doCommit的提交请求操做,那么这个时候都会执行redo日志进行持久化操做并响应给协调者节点告知当前事务操做完成而且已经提交.
3PC存在的数据不一致问题
经过上述的流程分析,咱们很容易得出,3PC的事务协议提交阶段存在的数据不一致主要体如今:
在协调者进行预提交阶段,协调者服务节点向参与者节点发起预提交请求,其中向参与者集群服务节点已成功发起预提交请求,可是这个时候协调者服务节点发生故障致使不可用,那么就会致使参与者节点服务部分没有收到预提交的请求,这个时候这部分参与者节点因为没有收到preCommit请求而进行undo日志的回滚.
TCC事务协议
TCC定义
TCC,即Try(预留资源)-Confirm(确认操做)-Cancel(撤销操做),其核心流程以下:

TCC原理分析
  • 在主服务节点注册一个确认以及撤销的操做,而后在主服务节点开启事务执行资源的锁定并预留可用的资源,而后提交消息分发到各个子服务节点中
  • 子服务节点接收到主服务节点的事务操做消息,这个时候子服务也将本身对应的资源进行锁定,同时也将可用的资源预留出来以便于提高并发操做的性能,而后向主服务节点推送操做结果的消息为Success或者是Fail
  • 主服务节点根据各个子服务节点操做结果的反馈,若是存在一个子服务节点的Fail反馈,那么就执行撤销回滚操做并将锁定的资源回收到资源池中来保证整个分布式事务的ACID,若是返回都是Success,那么就执行确认操做释放锁定资源.最后将操做结果以消息的形式分发到各个子服务节点上
  • 子服务节点接收到主服务节点的事务确认或者回滚消息,也将执行相应的确认或者是回滚操做,若是是回滚操做,那么一样也将锁定的资源回收到资源池中,若是是执行确认操做,那么就释放资源.
能够看到TCC是创建在业务基础上来保证分散的服务节点的事务一致性,实现相对比2PC更为复杂些.
TCC各个服务节点运做
以一个送礼下单为例展开,现有一个订单服务,礼物服务以及用户积分服务.以下图所示:

订单服务能够认为是一个主服务,主要负责订单状态的更新,而礼物服务以及积分服务做为一个子服务,负责更新礼物库存以及积分信息.因而对于一个TCC的操做流程能够分解为以下几个步骤:

  • 订单服务接收到送礼下单的请求,那么这个时候订单服务将会建立一个订单并设置当前的订单状态为PENDING以便于提高并发性能查询而并不是处于建立订单的阻塞等待状态,同时分发消息到礼物服务以及积分服务.

  • 礼物服务以及积分服务分别收到订单服务发出的事务操做请求命令,这个时候礼物服务以及积分服务分别记录redo以及undo日志,redo能够理解为可用资源提供外界查询以实现并发访问的性能,undo锁定使用的资源以便于回滚,这里的redo能够是对应的数据库已发生变动数据的记录,undo日志记录变动前的数据并设置为锁定状态.而后将操做结果返回给订单服务节点.

  • 订单服务节点更新返回的子服务消息结果,若是都是操做成功,那么这个时候就执行确认操做,订单服务将订单状态更新为FINISHED,并将消息分发到各个服务节点,若是存在一个节点操做失败,则执行更新状态为REJECTED,并下发回滚操做的消息.

基于上述的认知以后,咱们要实现一个基于TCC的分布式事务,若是在没有使用开源产品的场景下,最简单的方式是能够基于MQ的方式来实现可靠消息的生产与消费从而实现咱们的分布式事务协议TCC.




BASE理论

BASE理论定义

BASE是Basically Available(基本可用),Soft Sate(软状态)以及Eventual Consistency(最终一致性)三个短语的缩写.

  • 基本可用:多是部分功能不可用或者是因网络缘由响应时间延迟致使延迟的时间段内不可用

  • 软状态:集群服务节点在进行数据同步期间数据的过渡状态.好比一个事务操做前为v1,进行事务操做后为v2,节点服务之间数据由v1转变为v2的状态为过渡状态.

  • 最终一致性:通过系统内部服务之间的运行协做,最终服务节点表如今业务上抑或是集群leader选举或者是数据上等最终保持一致性

数据一致性模型
  • 线性一致性(强一致性): 不管是在集群服务哪一个节点,看到的数据最终都是一致性.

  • 顺序一致性(弱一致性): 集群服务节点的数据变更以及操做顺序保持一致.

  • 最终一致性(弱一致性): 集群的全部服务节点最终都会呈现数据的一致性

基本可用策略
  • 流量削峰:应对高并发量冲击,能够从如下几个方面来考虑问题,一个是错开时间段;一个是限流+错开时间段,好比预定抢购;一个是在边缘节点抑或是负责均衡器作流控;一个是在应用程序中基于MQ消息队列来作缓冲;一个是在底层数据库表采起分区表,不够再进行分库分表设计.

  • 延迟响应: 好比在进行购票的时候,咱们会提交购票请求而后须要进入系统的排队等候,等待请求被处理.

  • 降级: 一个是当被调用的服务依赖不可用时,为了服务调用者节点时可用的,须要加入异常处理的降级操做;又或者是在负载均衡器中发现后端服务不可用的时候能够采起降级返回错误提示等

  • 过载保护: 在抢购或者是秒杀系统中,能够考虑在nginx中进行限流而后将超出的流量直接放回抢购失败;抑或是在应用服务中的线程池中将任务添加到阻塞队列中,若是队列满了能够考虑直接丢弃任务策略.

参考文档
## 有状态与无状态服务
https://nordicapis.com/defining-stateful-vs-stateless-web-services/

## CAP定理
https://dzone.com/articles/understanding-the-cap-theorem
https://dzone.com/articles/quick-notes-what-cap-theorem

关于一致性的详细分析留到下一篇文章中.



最后感谢花时间阅读,若是有收获欢迎动一动小手指转发或者好看,谢谢!




你好,我是疾风先生,前后从事外企和互联网大厂的java和python工做, 记录并分享我的技术栈,欢迎关注个人公众号,致力于作一个有深度,有广度,有故事的工程师,欢迎成长的路上有你陪伴,关注后回复greek可添加私人微信,欢迎技术互动和交流,谢谢!

老铁们关注走一走,不迷路



      有用就点个好看吧   

本文分享自微信公众号 - 疾风先生(Gale2Writing)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索