《深入浅出分布式技术原理》 学习笔记 day15

112 阅读4分钟

大家好,我是砸锅。一个摸鱼八年的后端开发。熟悉 Go、Lua。今天和大家一起学习分布式技术😊

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情

分布式事务

事务是什么

事务是一个或者多个操作的组合操作,并且它对这个组合操作提供一个保证,如果这个组合操作之前的数据是一致的,那么操作之后的数据也应该是一致的

事务的四个特性

  1. 一致性,一个事务可以正确的将数据从一个一致性的状态,变换到另一个一致性的状态
  2. 原子性,一个事务所有的操作,要么全部执行,要不一个都不执行
  3. 隔离性,如果多个事务并发执行,那么执行结果和一个个串行执行的结果是一样的
  4. 持久性,如果一个事务已经提交,不论什么原因产生的结果都是永久存在的,保证了事务的结果不会丢失

如何实现一致性

事务的一致性实现需要多维度的保证:

  1. 底层存储的多副本数据强一致性,例如外键约束和唯一约束
  2. 事务原子性、隔离性和持久性一起协作
  3. 数据库和应用层的约束检测

原子性的定义

原子操作拥有整体的不可分割性,所有操作要么执行,要不一个都不执行。其次是可串行化的隔离性,即线程安全

原子性的实现

  1. 单节点事务,单节点操作不可分割
  2. 分布式事务,多节点操作不可分割

单节点事务一般是存储引擎上通过 Undo Log、Redo Log 和 Commit 记录来实现,Redo Log 保证事务的持久性,Undo Log 保证事务的原子性,Commit 记录了事务的提交点

分布式事务对于部分节点失败导致的操作分割,常见的思路是通过两阶段提交(2PC)来解决

选择一个协调者,这个协调者可以是分布式事务的参与节点,也可以是一个单独的进程。然后第一阶段是协调者发送(Prepare)事务请求到所有参与的节点询问它们是否可以提交,参与节点回复可以的话,协调者就在阶段 2 发送提交请求(Commit),如果回复不可以的话,协调者就在阶段 2 发出放弃请求(Rollback)

阶段 2 的时候依据阶段 1 的结果,决定事务最终是提交还是放弃

2PC 是一个阻塞式协议,当参与者回复之后,必须等待协调者的决定,所以参与者所有占用的资源都不能释放

2PC 是一个逆可用性协议,如果阶段 1 的时候任何一个参与者发生故障,协调者都会中止操作。如果阶段 2 的时候协调者发生故障,参与者也只能等待,不能完成操作

2PC 不能容忍少数节点失败的情况,是因为 2PC 是一个原子提交协议,需要与所有节点达成共识,而 Raft 和 Paxos 则只需要大部分节点达成一致,确保共识成立,但是 2PC 保证事务原子性,不能保证多个节点的事务操作同时提交,如果没有同时提交,就会使得事务的可见性出现问题

隔离性的定义

如果多个事务并发执行时,事务之间不应该出现相互影响的情况

持久性的定义

持久性在事务中的定义是,如果一个事务已经提交,不论什么原因它产生的结果都是永久存在的

不论是 SATA 硬盘还是 SSD 硬盘,从硬盘自身的特点来说,顺序读写的性能都要远远高于随机读写。另外从系统的角度来看,顺序读写在预读和缓存命中率等方面也要大大优于随机读写

对于单节点来说,我们可以先在内存中将事务的操作完成,然后将处理的结果顺序写入日志文件中,这就避免了事务操作结果随机写入存储的性能问题了。然后我们再提交事务,这样一来,哪怕事务提交后,机器立即崩溃了,在机器故障恢复后,系统依然能通过日志文件,恢复已经提交的事务。我们把这种通过顺序写入日志的形式,称之为重做日志(RedoLog)或预写日志(Write Ahead Log)

其次,要保障事务在磁盘故障情况下的持久性,必须将数据复制到多块磁盘上,两种思路:一是通过磁盘阵列,从磁盘内部复制数据来解决;另一种是通过外部的数据复制来解决

此文章为2月Day22学习笔记,内容来源于极客时间《深入浅出分布式技术原理》