本系列文章中,会详细介绍Ignite如何管理键-值API的事务,以及它支持的部分机制和协议,下面是本系列要覆盖的主题:
- Ignite事务和2阶段提交协议;
- 并发模型和隔离级别;
- Ignite持久化层中的事务处理(WAL、检查点及其他);
- 第三方持久化中的事务处理
在第一篇文章中,我们会先讨论2阶段提交协议(2PC),然后看一下它如何处理各种类型的集群节点。
2阶段提交协议(2PC)
在一个分布式系统中,一个事务可能涉及多个集群节点,很显然,这在确保所有相关节点上的数据一致性方面,面临一些挑战。比如,如果一个节点故障,事务可能在该节点上没有提交。在这个场景中,一个广泛使用的确保一致性的方法就是2阶段提交协议。 顾名思义,它有两个阶段,准备和提交,下面看一下细节:
先看一下准备阶段,图1中,有一个示例网络,它由一个客户端(事务发起方),2个主节点和4个备节点组成。 Ignite使用一个分布式哈希表来决定数据在集群中如何分布(分区),集群中中每个主备节点都持有数据的一部分,这些节点会维护一个节点及其拥有的分区的内部分布式哈希表,主备节点只是指向数据所在的位置,主节点就是数据主拷贝所在的位置。如果主节点不可用并且备节点存在的话,数据仍然是可用的。 注意,Ignite没有纯粹的主节点或者备节点,每个节点默认既是主节点,又是备节点,它是一组分区的主节点又是其他分区的备节点。 在图1中,还有一些箭头来显示不同类型节点间的各种消息流:
- 客户端发送一个准备消息(1 Prepare)给事务涉及的所有主节点;
- 主节点获得所有的锁(取决于事务为悲观还是乐观),然后转发准备消息(2 Prepare)给所有的备节点;
- 每个节点会给客户端一个确认(3 ACK, 4 ACK),即所有的锁已经成功获得然后事务准备提交。
下一阶段,会执行提交阶段。在图2中,会看到一个类似于准备阶段的消息流:
- 客户端发送提交消息(5 Commit)给事务涉及的所有主节点;
- 主节点提交事务并且转发提交消息(6 Commit)给所有的备节点,然后备节点提交事务;
- 每个节点返回事务提交成功的确认消息给客户端(7 ACK, 8 ACK)。
这里可能发生许多故障,比如备节点故障,主节点故障,或者甚至客户端故障,我们后续会研究这些场景,然后在其它文章中介绍Ignite如何进行应对。
节点类型
前面的讨论中提到了集群节点的各种类型,客户端节点(事务发起方)在Ignite社区中通常称为近端节点,而其它节点成为远端节点,如图3所示:
通常来说,应用会通过客户端节点接入集群,应用和客户端节点的职责分工如下:
- 应用调用方法:
- txStart()
- cache.put()
- cache.get()
- tx.commit()
- 客户端节点管理其他的操作:
- 事务初始化
- 事务状态跟踪
- 发送准备和提交消息
- 协调整个事务过程
下面是中的一小段示例代码,显示了事务的执行方式:
try (Transaction tx = transactions.txStart()) { Integer hello = cache.get("Hello"); if (hello == 1) cache.put("Hello", 11); cache.put("World", 22); tx.commit();}
本例中会看到,可以通过txStart()方法开始事务,可以通过tx.commit()方法提交事务。相应的,在try块体中,代码在Hello键上执行了一个**cache.get()操作,然后,然后判断值是否为1,如果是,那么通过cache.put()将值改为11,然后通过cache.put()**在缓存中写入另一个键-值对。
总结
在第一篇文章中,快速地预览了2阶段提交协议,然后描述了Ignite的处理方式,在本系列的下一部分中,会看到乐观和悲观锁模型还有隔离级别。
本文译自GridGain的技术布道师Akmal B. Chaudhri的。