分布式理论 | 青训营笔记

86 阅读11分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 8 天

1 概述

1.1 什么是分布式系统

分布式系统是计算机程序的集合,这些程序利用跨多个独立计算节点的计算资源来实现共同的目标。它也被称为分布式计算或分布式数据库,并依靠不同的节点通过公共网络进行通信和同步。这些节点通常代表独立的物理硬件设备,但也可代表单独的软件进程或其他递归封装的系统。分布式系统旨在消除系统的瓶颈或中心故障点。

1.2 常见的分布式系统

  • 分布式协调系统(日志复制系统)其实就是paxos算法及其变体的实现,典型的有zookeeper、etcd;一般来说只存少量的元数据信息,重点在高可用强一致,不提供高的through put,是分布式系统不可或缺的组件;

  • 面向非结构化数据的分布式文件/对象系统比较有名的包括Lustre(HPC)GlusterFS(NAS NFS)、HDFS(hadoop)、ceph(虚机块存储)、swift(restful对象存储),各有不同的适用领域。

  • 结构化数据的NoSQL分布式存储,种类和数量最多,按照Martin Fowler的分类,包括Aggregated Oriented NoSQL和图数据库NoSql;Aggregated Oriented NoSQL大致分为3类:

  • Key-value NoSQL,例如Redis Riak等;

  • column family NoSQL(wide column store),典型的是Hbase Cassandra

  • document NoSQL,典型的是MongoDB

2 理论基础

2.1 CAP

CAP 理论,相信很多人都听过,它是指:

一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

在分布式系统内,P 是必然的发生的,不选 P,一旦发生分区错误,整个分布式系统就完全无法使用了,这是不符合实际需要的。所以,对于分布式系统,我们只能能考虑当发生分区错误时,如何选择一致性和可用性。

而根据一致性和可用性的选择不同,开源的分布式系统往往又被分为 CP 系统和 AP 系统。

当一套系统在发生分区故障后,客户端的任何请求都被卡死或者超时,但是,系统的每个节点总是会返回一致的数据,则这套系统就是 CP 系统,经典的比如 Zookeeper。

如果一套系统发生分区故障后,客户端依然可以访问系统,但是获取的数据有的是新的数据,有的还是老数据,那么这套系统就是 AP 系统,经典的比如 Eureka。

其实 CAP 定理本质很简单,它就是一种分布式系统设计的不同理念概括,包括它说的一致性,可用性和分区容错性。这就类似一个大学的校训,是极度概念化的东西。

2.2 ACID理论

ACID 是 Jim Gray 在 1970 年提出的用于描述数据库事务的理论,它是Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久性)这几个单词首字母的缩写。

● 原子性:其强调事务的整体性和不可分割性,系统不会处于一个不可预测的中间状态。对于事务中包含的多个操作,系统在执行过程中要么完成全部操作并进行提交,要么全部操作都失败后,系统回滚到上一个一致性状态。
● 一致性:在事务的发起、运行和结束的全流程中,数据库的完整性约束没有被破坏,因为数据库状态更迭的基本单位是事务。
● 隔离性:其主要用于数据库事务的并发控制,系统需要保证多个并发执行的事务不会相互影响,从而防止数据不一致现象的发生。从具体实践来看,事务隔离又可以分为未提交读(Read-Uncommitted)、提交读(Read-Committed)、可重复读(Repeatable-Read)和串行化(Serializable)这四个级别,每个级别所蕴含的物理意义各不相同。
● 持久性:事务的成功提交意味着当前事务生命周期的结束,事务所做的任何修改都会被持久化地存储在数据库当中,即使系统遭遇故障,这些数据更新也不应丢失。

2.3 BASE理论

BASE 全称是 Basically Available(基本可用)、Soft State(软状态)和 Eventually Consistent(最终一致性)三个短语的缩写,来自 ebay 的架构师提出。

image.png

Base 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大型互联网分布式实践的总结,是基于 CAP 定理逐步演化而来的。

其核心思想是:既然无法做到强一致性,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。

Basically Available(基本可用)

基本可用就是假设系统某个模块出现了不可预知的故障,但其他模块依旧可用,例如商城双十一活动时,评论模块出现故障,但不会影响交易、商品等核心模块的流程使用。

Soft State(软状态)

软状态指的是允许系统中的数据存在中间状态,并认为该状态不影响系统的整体可用性,即允许系统在多个不同节点的数据副本存在数据延时。

Eventually Consistent(最终一致性)

上面讲到的软状态不可能一直是软状态,必须有时间期限。在期限过后,应当保证所有副本保持数据一致性,从而达到数据的最终一致性,因此所有客户端对系统的数据访问最终都能够获取到最新的值,而这个时间期限取决于网络延时,系统负载,数据复制方案等因素。

在 CAP 中的一致性要求在任何时间查询每个节点数据都必须一致,它强调的是强一致性,而最终一致性是允许在一段时间内每个节点的数据不一致,但是经过一段时间每个节点的数据必须一致,它强调的是最终数据的一致性。

3 分布式事务

3.1 两阶段提交

二阶段提交协议(Two-phase Commit Protocol,简称 2PC)是分布式事务的核心协议。在此协议中,一个事务管理器(Transaction Manager,简称 TM)协调 1 个或多个资源管理器(Resource Manager,简称 RM)的活动,所有资源管理器向事务管理器汇报自身活动状态,由事务管理器根据各资源管理器汇报的状态(完成准备或准备失败)来决定各资源管理器是“提交”事务还是进行“回滚”操作。

二阶段提交的具体流程如下:

  1. 应用程序向事务管理器提交请求,发起分布式事务;

  2. 在第一阶段,事务管理器联络所有资源管理器,通知它们准备提交事务;

  3. 各资源管理器返回完成准备(或准备失败)的消息给事务管理器(响应超时算作失败);

  4. 在第二阶段:

    • 如果所有资源管理器均完成准备,则事务管理器会通知所有资源管理器执行事务提交;
    • 如果任一资源管理器准备失败,则事务管理器会通知所有资源管理器进行事务回滚。

3.2 两阶段提交

针对两阶段提交存在的问题,三阶段提交协议通过引入一个 预询盘 阶段,以及超时策略来减少整个集群的阻塞时间,提升系统性能。三阶段提交的三个阶段分别为:预询盘(can_commit)、预提交(pre_commit),以及事务提交(do_commit)。

第一阶段:预询盘

该阶段协调者会去询问各个参与者是否能够正常执行事务,参与者根据自身情况回复一个预估值,相对于真正的执行事务,这个过程是轻量的,具体步骤如下:

  1. 协调者向各个参与者发送事务询问通知,询问是否可以执行事务操作,并等待回复;
  2. 各个参与者依据自身状况回复一个预估值,如果预估自己能够正常执行事务就返回确定信息,并进入预备状态,否则返回否定信息。

第二阶段:预提交

本阶段协调者会根据第一阶段的询盘结果采取相应操作,询盘结果主要有 3 种:

  1. 所有的参与者都返回确定信息。
  2. 一个或多个参与者返回否定信息。
  3. 协调者等待超时。

针对第 1 种情况,协调者会向所有参与者发送事务执行请求,具体步骤如下:

  1. 协调者向所有的事务参与者发送事务执行通知;
  2. 参与者收到通知后执行事务但不提交;
  3. 参与者将事务执行情况返回给客户端。

在上述步骤中,如果参与者等待超时,则会中断事务。  针对第 2 和第 3 种情况,协调者认为事务无法正常执行,于是向各个参与者发出 abort 通知,请求退出预备状态,具体步骤如下:

  1. 协调者向所有事务参与者发送 abort 通知;
  2. 参与者收到通知后中断事务。

第三阶段:事务提交

如果第二阶段事务未中断,那么本阶段协调者将会依据事务执行返回的结果来决定提交或回滚事务,分为 3 种情况:

  1. 所有的参与者都能正常执行事务。
  2. 一个或多个参与者执行事务失败。
  3. 协调者等待超时。

针对第 1 种情况,协调者向各个参与者发起事务提交请求,具体步骤如下:

  1. 协调者向所有参与者发送事务 commit 通知;
  2. 所有参与者在收到通知之后执行 commit 操作,并释放占有的资源;
  3. 参与者向协调者反馈事务提交结果。

针对第 2 和第 3 种情况,协调者认为事务无法成功执行,于是向各个参与者发送事务回滚请求,具体步骤如下:

  1. 协调者向所有参与者发送事务 rollback 通知;
  2. 所有参与者在收到通知之后执行 rollback 操作,并释放占有的资源;
  3. 参与者向协调者反馈事务回滚结果。

在本阶段如果因为协调者或网络问题,导致参与者迟迟不能收到来自协调者的 commit 或 rollback 请求,那么参与者将不会如两阶段提交中那样陷入阻塞,而是等待超时后继续 commit,相对于两阶段提交虽然降低了同步阻塞,但仍然无法完全避免数据的不一致。

3.3 MVCC

MVCC是一种多版本并发控制机制。MVCC可以在大多数情况下代替行级锁,降低系统开销。
MVCC的本质就是copy on write,能够做到写不阻塞读MVCC能够做到写读不冲突,读读不冲突,读写也不冲突,唯一冲突的就是写和写,这样系统并发读就可以非常高。MVCC 提供了时点(point in time)一致性视图。MVCC 并发控制下的读事务一般使用时间戳或者事务 ID去标记当前读的数据库的状态(版本),读取这个版本的数据。读、写事务相互隔离,不需要加锁。读写并存的时候,写操作会根据目前数据库的状态,创建一个新版本,并发的读则依旧访问旧版本的数据。 一句话讲,MVCC就是用同一份数据临时保留多版本的方式 ,实现并发控制。MYSQL的并发控制就是用MVCC实现的。

那么怎么把MVCC用到我们的kv数据库中呢?我们可以给key-value键值对也加上timestamp。然后在运行的过程中,遵照以下规则:

  • All modifies are adding a new version.
  • The same row(就是同一个key-value键值对) may have multiple versions.
  • Old versions dropped by GC.

在分布式并发事务的具体实现中,会用到一个Percolator Transaction Model。它是来自Google的一篇paper。Percolator的设计是为了解决2pc在分布式环境中的一些问题,相当于是2pc的增强版。用于在保证分布式一致性的基础上保证事务执行的ACID特性。