分布式事务
什么是事务
将多个不同的命令组装到一起的过程。
核心:锁与并发
称为事务为了更易理解。
性能较低。
容易理解的模型性能都不好,性能好的模型(锁的粒度小,增加了编程难度)都不易理解。
追求平衡。
事务要保证的问题就是一致性。
ACID保证事务完整性、原子性。什么是ACID?
建索引、读一行数据、插入一行并建索引、删除整张表….每个操作都是事务。
- two phase lock(2PL):两阶段锁,读(加锁) - 操作 - 提交(解锁)
事务单元
多个事务单元关联时,每个事务单元都不会看到数据的中间状态。
事务单元之间的 happen-before 关系:
- 读写
- 写读
- 读读
- 写写
《事务处理》
如何满足事务关联的同时更快完成(速度)?如何保证上面四种操作的逻辑顺序(正确性)?
- 排队各种操作:串行序列化、不需要冲突控制,但是慢,
- 针对同一个单元的访问进行访问控制,排成多个队,没有冲突的地方进行并行:读写均加锁,
- 针对读场景做优化,读与写锁分离开,读进行并行操作:提升读多写少性能,即读写锁,可重复读
- MVCC,多版本并发控制,写不阻塞读,copy on write,写读场景优化,写的时候可以读,只有写写时冲突,系统实现复杂性变高,日志变多。
ACID 中的 I,隔离级别,但为了并发而破坏了一致性:
- 可序列化
- 可重复读
- 读已提交
事务处理的常见问题
事务顺序
MVCC中,每次数据写入都放入不同版本的数据log,如何保证写写读的顺序。
内存中维持数据自增号,写的时候加1。读的时候根据ID找对应的数据。逻辑时间戳(事务单元先后)、物理时间戳(时钟)。
故障恢复
错误类型:
- 业务属性不匹配,记录操作的反向操作,进行回退
- 系统崩溃,在数据恢复没有完全完成时不对外不服务,防止崩溃时没有完成的事务而造成的中间数据暴露
死锁怎么办
原因:
- 两个线程
- 不同方向
- 相同资源
方法:
- 尽可能不死锁,降低隔离级别
- 碰撞检测,记录各单元持有的锁进行检查,终止一边
- 等锁超时,但是超长事务导致每次死锁释放需要太久时间,2是主流,这个辅助
深入单机事务
ACID
原子性操作:要么同时成功要么同时失败,回滚到事务最初状态。执行每个操作都记录一个回滚段。
一致性:核心为“看”,happen before,一个事务单元保证全部成功以后才可见。对多个事务操作的同一数据加锁,将事务顺序化,排队,同时将锁下推到数据上,将锁分离,而不是一个超级大锁。
隔离性:因为一致性中加锁而带来的性能问题,对强一致性进行破坏。
- 序列化读写,用排他锁,将所有读写操作排队:性能差==不可用
- 读写锁,读锁不能被写锁升级(读的时候不能写):
- 可重复读,读读操作并行
- 读写锁,读已提交,读锁能被写锁升级(读的时候能写):
- 读读并行
- 读写并行
- 读未提交,只加写锁,不加读锁
- 读读并行
- 读写并行
- 写读并行,所有的写是串行的,读都是并行的,可以读到写过程中未提交的数据(因此不建议用)
- MVCC,打脸上面的 SQL92标准。快照隔离级别,核心:copy on write+无锁编程,针对读多写少优化
- 每个事务都有一个版本号
- 新的事务同时进来后生成一个新的版本号,读取上一个版本号事务开始之前的数据
- 在读一致性数据的同时实现读未提交
持久性:事务完成后,所有的提交都要物理存储。延迟与持久性平衡。
(操作 -> 内存 -> 磁盘(块越大越块),如果在内存中攒成一块再写磁盘)
等待多次 commit 之后(group commit)再刷磁盘,攒成一大块,但吞吐变小,需要权衡
RAID 保证持久性:RAID controller 同时写到多个磁盘,同时成功同时失败,这又成为一个新的事务。
典型异常应对策略
业务属性不匹配:
- 原子性
- 一致性
- 回滚:事务单元中的每个操作都记录一个回滚段
系统宕机:重启后进入 recovery 模式,执行回滚段
调优原则
在不影响业务应用的前提下:
- 减少锁的覆盖范围(减小锁粒度)
- myisam 表锁 -> innodb 行锁
- 原位锁 -> mvcc 多版本(将一个大锁拆分到不同版本的数据上)
- 增加锁上可并行的线程数
- 读锁写锁分离、允许并行读取数据
- 选择正确的锁类型,与读写锁是不同层次的概念(共两种锁:排他锁,共享锁)
- 悲观锁,适合并发争抢比较严重的场景
- 乐观锁,适合并发争抢不太严重的场景
数据库中的 U 锁(update 锁):如果事务单元中有写操作,则在进行读操作时直接申请为写锁,而不是读锁。
分布式事务与单机事务
分布式事务的目标:
- 完整的事务支持,和单机一样
- 无限扩展
事务
(对于共享数据,)让多步操作顺序发生,让多线程看上去就像一步操作。
事务优化:尽可能的快,数据又不错乱。
网络
优点:去中心化,网络提供了理论上无限的扩展能力,理论上无线的数据安全性(不丢失),理论上无线的服务可用性。
缺点:共享数据困难(通过消息复制),更多的延迟,确定性丧失,并发编程难度。
基于锁的事务遇到的问题
从 2PL 到 2PC
所有的数据库都会抽象为两阶段锁的操作。在分布式中抽象为两阶段提交。
由第三者-协调器负责跨机提交。
分布式事务异常处理
任何步骤出现状况时全部回滚。但是当一阶段已提交并暴露后,二阶段提交失败则无法再回滚,只能等待直到处理成功。
分布式日志记录
协调者高可用:
- 必须是多机,任意协调者必须知道这个事务运行的状态
- 记录日志,准备阶段需要记录一次日志
- 每个节点的commit 都必须记录日志
分布式事务延迟变大
随着数据、节点增长,延迟越来越大,即分布式事务的最大问题。
基于 MVCC 的事务视线中遇到的问题
分布式顺序问题
逻辑时间戳,所有操作都需要一个时间戳,然后才能知道该操作需要操作的数据版本,以保证操作顺序。
但是分布式中无法再进行时间戳的分配了,单台机器分配的话将成为单点,同时,单位时间内能够分配的时间戳是有限的,比如一台机器为100台机器分配时间戳。多台又无法保证递增性。
分布式事务的主要难题
传统数据库的分布式事务
Google Spanner 赏析
阿里分布式事务模型
DRDS/TDDL 实战
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.