暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

巨杉内核笔记 | 分布式事务漫谈(一)

巨杉数据库 2019-12-26
1047

引言

对于支持 OLTP 的数据库系统来说,事务都是必不可少的一个核心特性。在数据库系统从单机架构向分布式架构演进的过程中,系统复杂性大幅提升,对事务的支持面临极大的挑战。


分布式系统通常采用数量更多,价格更便宜的硬件,用户可以在有效控制成本的情况下,更从容地应对业务的高速增长。但是一分钱一分贷,价格低了,在稳定性和可靠性上就没那么靠谱了。在大规模的集群里,主机设备故障、硬盘罢工等问题,基本都是家常便饭。甚至也有一些外部因素会对系统产生影响,比如被人挖断光缆,导致服务大面积瘫痪的事,也实实在在地发生过。


因此,相对复杂的组网模式,也就成为分布式系统面临的一大难点:存在更多的风险可能性。这些需要从软件的架构及实现层面进行弥补,任何对环境存在过度假设的方案,都是无意义的。与此同时,除了应对各种可能的异常,数据库系统还要确保在分布式环境下,提供完整的事务能力、完备的ACID 特性,以及满足实际业务需要的高性能,这些都是需要软件提供商们直面的挑战。


作为新一代分布式关系型数据库,SequoiaDB 对这些问题进行了深入的研究并最终产品化,在客户的线上业务系统中取得了良好的应用效果。本系列文章,将对其分布式事务的基本实现机制及关键技术点进行介绍,着重介绍其中的高性能设计、完备的强一致性保证等内容。


概述

一个完整的事务流程,通常包括事务的开启、事务操作的执行,以及事务的结束(提交或回滚)。由于 SequoiaDB 的分布式特性,其事务通常需要集群中的多个节点(协调节点、一个或多个数据节点)通过网络消息进行交互与协同。协调节点作为数据库集群与业务进行交互的入口,同时也承担着全局的事务管理器的功能,它在接收到客户端请求时,选择目标数据节点,进行事务消息的下发,收集各节点的事务状态,并控制全局的事务提交或回滚。


正如前面讲到的问题,任何一个节点都有可能在关键时刻掉链子。为了应对各种节点异常的情况,数据节点除了在协调节点的统一指挥下进行步调一致的操作之外,也需要具备一定的自治能力。在协调节点失效或者自身异常的情况下,能够主动和其它节点进行确认,并处理自己的未决事务,以在全局范围内确保数据一致。


下面我们将按照一个事务的基本流程,对 SequoiaDB 中的分布式事务进行介绍。


开启事务

事务由客户端(基于 SequoiaDB 驱动开发的各种应用)主动开启,它会向服务端(集群中的协调节点)发送一个 begin transaction 的消息。协调节点在收到该消息后,会进行一些必要的准备工作,并为该事务分配一个事务 ID。事务 ID 是一个 64 位整形值,但它并非一个简单递增的数值,而是由协调节点 ID、递增序列值和若干特殊标记组合而成的。事务 ID 生成后,会记录在会话线程中,并包含在后续的事务消息中下发给数据节点。在一个会话中,同一时刻只会存在一个事务。因此,如果相同会话中连续多次调用开启事务的接口(而不进行事务的提交或回滚),都是使用的第一次开始的事务。


对于软件系统,网络交互是一个开销比较大的操作,而对于存在多节点间网络交互的分布式系统来说,其对性能的影响就更加明显,甚至直接成为整个系统的性能瓶颈。因此,设计一套简洁、高效的消息框架,对保障系统的高性能,具有至关重要的意义。在这一点上,SequoiaDB 实现了消息打包、批量发送及处理的能力,最大限度地减少了消息交互,从而有效地节省了网络带宽,减小了处理时延。


比如,在开启事务阶段,数据节点不需要进行特定操作,因此协调节点完成自己的操作之后,立即返回成功。当客户端执行下一个事务操作时,协调节点就会将事务开始的消息和数据操作的消息打包到一起,发送给数据节点处理。


数据节点在开启事务时会进行必要的检查,如节点是否为主节点,当前会话上的事务是否处于不一致状态。如果检查通过,则会将协调节点下发的事务 ID 设置到会话中。完成事务开启后,就会进行后续的事务操作。


事务操作

在事务开启后即可在事务内进行数据操作,如在一个或多个表上进行 CRUD 操作。该事务内对数据的变更,在其它事务中是否可见,以及对锁的竞争行为,取决于隔离级别的配置。


如前文所述,如果是第一次向一个数据节点发送事务操作请求,那么会对开启事务和数据操作消息打包发送。在数据节点上,接收到该消息包后,会依次解析并处理其中的消息。如果数据节点之前已经接收过协调节点发送过来的该事务的消息,则新消息中只会包含新事务操作的消息。


结束事务(提交或回滚)

在完成所有事务中的操作后,需要决定事务是提交还是回滚。结束事务是两阶段提交协议应用的阶段。两个阶段是指:

  • 准备阶段(Pre-Commit):在这一阶段,协调节点询问所有参与的数据节点是否准备好提交;参与的数据节点如果已经准备好提交则回复可以进行提交,并进入等待提交状态(Wait-Commit),否则回复不可以进行提交。



  • 提交阶段(Commit):协调节点如果在上一阶段收到所有参与的数据节点回复都可以进行提交,则在此阶段向所有参与的数据节点发送提交指令,所有参与的数据节点立即执行提交操作;否则协调者向所有参与的数据节点发送回滚指令,参与的数据节点立即执行回滚操作。



在这个阶段,事务内的操作已经结束,各数据节点上的数据变更已经完成,等待进行最后的处理及资源清理。提交通常是一个轻量级的操作,但在分布式环境下,由于事务可能涉及到多个节点,因此难点在于确保所有节点动作的一致性。如果是提交,要确保所有节点上最终都是提交,如果是回滚,则所有节点上要全部回滚。


PRE_COMMIT

在 PRE_COMMIT 阶段,数据节点上主要做两件事:写一条 PRE_COMMIT 的事务日志;将该事务置为 WAIT_COMMIT 状态,表示自己在等待 COMMIT。

COMMIT

COMMIT 也是一个轻量级的操作,因为在此之前,数据变更都已经完成了。COMMIT 阶段的操作主要包括:
  • 写一条事务提交的事务日志

  • 将会话线程中的事务状态切换为 COMMIT

  • 删除该事务的事务控制块

  • 释放该事务持有的所有锁

  • 释放该事务所占有的事务日志空间

在该事务释放了事务锁之后,其它之前在等待这些锁的事务即可继续执行。 

提交性能优化

在基本的两阶段提交协议基础之上,SequoiaDB 针对某些场景进行了进一步的高性能设计。如果事务中操作的数据存在于同一个数据组上,此时就不需要进行多个分区组中事务的确认,可以将两阶段提交简化为一阶段直接进行提交。这样能够有效减少网络通信及协调确认流程,大大提高性能。


小结

本篇作为分布式事务部分的开篇,主要对分布式数据库系统所面临的挑战,以及 SequoiaDB 中的分布式事务的基本流程、高性能设计进行了介绍,后续会进一步分享分布式事务的其它关键技术点,如事务强一致性保证等,敬请期待。


往期技术干货
巨杉系列工具 | 集群分析工具sdbtop

巨杉Tech | 分布式数据库Sysbench测试最佳实践

巨杉Tech | 巨杉数据库数据高性能数据导入迁移实践

巨杉⼯具系列之一 | ⼤对象存储⼯具sdblobtool

巨杉Tech | 基于Kafka+Spark+SequoiaDB实时处理架构快速实战

巨杉Tech | SequoiaDB数据域及存储规划

巨杉Tech | SparkSQL+SequoiaDB 性能调优策略

巨杉Tech | 使用 etlAlchemy 工具迁移数据实战

巨杉Tech | Hbase迁移至SequoiaDB 实战

巨杉Tech | SequoiaDB 巨杉数据库高可用容灾测试

巨杉Tech | 使用 SequoiaDB + Docker + Nodejs 搭建 Web 服务器

巨杉学习笔记 | SequoiaDB MySQL导入导出工具使用实战

巨杉内核笔记 | 会话(Session)

180秒揭秘数据库金融级灾备架构




点击阅读原文,获取更多精彩内容~
最后修改时间:2019-12-27 09:44:34
文章转载自巨杉数据库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论