Ignite Transaction

作者介绍:Redfox

原文链接:Ignite Transaction

1. Atomicity Mode

Ignite的支持跨cache的transaction,跨cache的transaction时要求不同cache之间的Atomicity Mode是相同的。
Cache的Atomicity Mode通过CacheConfiguration中的atomicityMode进行配置,主要支持下面三种Atomicity Mode:

TRANSACTIONAL_SNAPSHOT

  • 支持多个操作的多个key放在一个逻辑操作(事务)中,放在一个逻辑操作中的事务要么全成功,要么全失败,支持ACID特性

  • 同时支持K/V事务和SQL事务,使用MVCC来支持两种类型的事务

  • 不支持near cache

TRANSACTIONAL

  • 支持多个操作的多个key放在一个逻辑操作(事务)中,放在一个逻辑操作中的事务要么全成功,要么全失败,支持ACID特性

  • 支持K/V事务

  • 支持near cache

ATOMIC

  • 所有的操作都是原子的,一次同时只执行一个操作

  • 因为不用去做事务锁,所以性能比TRANSACTIONAL、TRANSACTIONAL_SNAPSHOT要高

  • 批量写入(例如PutAll、RemoveAll)可能会部分成功部分失败,这个操作会抛出一个异常,异常中间包含没有写入成功的K/V

2. Concurrency & Isolation

Concurrency:Ignite支持乐观并发控制模式和悲观并发控制模式,选择什么样的并发控制模式决定了在什么时机对entry进行加锁操作。悲观并发控制模式是在prepare阶段就对事务所操作的entry进行加锁,乐观并发控制模式是在访问数据的时候,就对entry进行加锁。无论选择哪种并发控制模式,在事务commit之前都存在一个时间区间,在这个区间内,事务所操作的所有entry,都是加锁状态的。

Isolation:隔离级别定义了并发执行的事务,对同时操作的key,是如何看待和如何处理的。Ignite支持READ_COMMITED、REPEATABLE_READ、SERIALIZABLE几种隔离级别。

所以并发控制模型和隔离级别是一个事务的两个方面,下面是ignite在这两个方面的支持。

2.1 悲观事务

悲观事务在事务执行第一条读取或者写入(根据隔离级别来看是第一条读取还是写入)的时候,就会对事务中所有的entry进行加锁,直到事务commit或者rollback才释放锁定。在这个模式下,锁定首先在primary节点上进行,在prepare阶段将锁定推送到backup节点上去,悲观事务的加锁顺序很重要(避免死锁)。ignite中会对entry按照约定的顺序规则进行加锁,悲观事务下支持的隔离级别如下:

READ_COMMITED
数据读取的时候不进行加锁,也不需要将数据读取到transaction中进行缓存,在第一次写入的时候才对所有的entry加锁。如果cache配置中允许的话,可以在backup节点上读取数据。READ_COMMITED可能的问题就是会导致不可重复读,即在一个事务中读取两次数据,可能会结果不一样。

REPEATABLE_READ
在第一次读写数据时,就将数据从primary节点读取到transaction map中,并且对所有的entry进行加锁。所有在这个事务中后续对同一份数据的读取,都可以读到在这个事务里面更新的最新数据,其它并发事务不能修改这个事务里的数据,所以可以获得可重复读。

SERIALIZABLE
和REPEATABLE_READ的工作方式相同。

悲观事务下的注意点

性能:因为悲观事务需要对所有的entry提前加锁,而且加锁是要按照一定的顺序控制的。所以,类似于putAll这种操作,如果将顺序相同的key放到一个part上进行操作,可能会减少在客户端与服务端之间加锁的锁定往来次数;

Long Transaction:因为在悲观事务下,我们不能修改集群的topology,要尽量减少时间比较长的悲观事务;

读取的一致性:只有在REPEATABLE_READ和SERIALIZABLE的隔离级别下,才能保证完整的读取一致性,通过读锁避免事务在过程中更新。

2.2 乐观事务

乐观事务在两阶段提交的prepare阶段才在primary节点上对entry进行加锁,加锁之后提交到backup节点上,在commit阶段释放所拥有的锁。

READ_COMMITED
在cache中的数据修改是在发起节点上先收集所有的更改,然后在事务commit阶段进行应用,数据读取的时候不进行加锁,也不需要将数据读取到transaction中进行缓存。如果cache配置中允许的话,可以在backup节点上读取数据,READ_COMMITED可能的问题就是会导致不可重复读,即在一个事务中读取两次数据,可能会结果不一样。

REPEATABLE_READ
和READ_COMMITED的实现方式相同,区别在于REPEATABLE_READ会把所有的读取过来的数据在发起节点上进行缓存,这样所有后续这个事务操作的读取,都可以确保是local的。

SERIALIZABLE
在第一次读取某个entry的时候,保存这个entry的版本号。如果在事务commit的时候,发现这个事务操作的所有entry存在一个entry的版本号和集群当前最新的entry版本号不相同,则这个事务失败,并对这个事务的修改操作进行回滚,用户需要处理这个异常,并且重试这个事务。这个中间需要特别强调的是即使这个事务只有读操作,没有写操作,这个事务也可能失败(假设后面读取的数据和事务刚开始时的数据不相同)。

乐观事务下的注意点

SERIALIZABLE下的重试:因为乐观事务是在操作过程中发现不能操作时,返回和抛出异常。所以我们需要捕获这种异常,然后进行重试,可能导致多个乐观事务循环重试的状态,所以我们在加锁时,也要考虑对entry加锁的顺序,降低循环重试的可能性;

读取一致性:只有在SERIALIZABLE的情况下,才能保证读取的一致性。但是即使在SERIALIZABLE的隔离级别下,在COMMIT之前,都可能发生部分读的现象,所以一定需要去捕获抛出的异常,以确保读取是一致的。

3. MVCC

只有TRANSACTIONAL_SNAPSHOT的原子模式,才支持MVCC特征,这个模式同时支持SQL事务和K/V事务,这两种类型的事务都支持MVCC。

MVCC是数据被多个用户并发访问时候,控制数据一致性的方法。每个事务在启动时获得数据的一致性快照,这个事务后续的操作只能看到和修改这个快照内的数据。当事务更新一个entry时,它需要确保这个entry没有被其它事务更新,然后创建这个entry的一个新的版本。这个新版本只有在这个事务commit之后才能被其它事务可见,如果这个entry被更新了,那么这个事务就会失败。Snapshot并不是物理的,而是逻辑的。它是由集群中的某个节点进行管理这些活动事务(MVCC-coordinator),这个节点追踪所有的活动事务,并且在每个事务结束时,都会通知到该节点。所有打开MVCC的cache操作,都需要从这个节点上获得快照数据。

目前TRANSACTIONAL_SNAPSHOT只支持悲观事务和REPEATABLE_READ隔离级别。

并发更新

当在一个事务里面(事务A),先读取一个entry,再更新这个entry过程中,可能存在另外一个事务在两个操作中间将这个entry更新的情况发生,如果这种情况发生,那么事务A会被置为“rollback only”(只允许回滚)的状态,ignite会抛出异常和设置SQL的状态码,让用户来处理这种状态,通常这个事务就需要重试。

限制

跨cache事务
在同一个事务里面要求所有的cache都设置为TRANSACTIONAL_SNAPSHOT模式,因此,如果需要在一个SQL事务中操作多个table,那么所有的table创建时,也要配置为TRANSACTIONAL_SNAPSHOT模式

嵌套事务
Ignite支持3种方案来处理嵌套事务,方案在JDBC、ODBC的连接参数中配置。

ERROR方案:当碰到嵌套事务,则抛出错误,同时外面的事务进行回滚,默认采用这种方案;

COMMIT方案:外围事务进行提交,嵌套事务在碰到COMMIT语句时进行提交,外围事务剩下的语句采用隐含事务模式;

IGNORE: 嵌套事务的BEGIN语句被忽略,嵌套事务中的语句被和外围事务一样执行,碰到COMMIT之后,进行事务提交,外围事务剩余的语句采用隐含事务模式。

持续查询
如果有其它操作在更新数据,那么持续查询获得的结果可能是过期的数据,因为更新数据需要时间通知到MVCC-coordinator节点上;

一个事务同时更新的记录数会被限制,因为可能造成内存泄漏,默认限制为20000条;

MVCC模式不支持:near cache、超时策略、事件通知、cache解析器、第三方持久化、堆内cache。

4. Two Phase Commit

1.png

2.png

两阶段提交

在分布式的ignite中,一个事务中的操作可能牵涉到修改多个partition上的数据,一个partition里面也存在主节点和备份节点,要保持一个事务中对所有节点的数据修改是一致的。ignite采用两阶段提交的方案来进行事务操作,两阶段提交事务中存在3个角色:
事务协调者(Transaction Coordinator):事务发起节点,它来控制事务的两阶段提交过程。
主节点(Primary Partition):ignite中某个partition的主节点,数据读写操作的主要对象。
备份节点(Backup Partition):ignite中某个partition数据备份的所在节点。

5. Near Node & Remote Node

3.png

在ignite中,Transactional coordinator也被称为Near Node。Near Node控制整个事务操作的全部流程,包括发起事务、跟踪事务状态、发起prepare、发起commit以及等待事务完成。

Near Node通常是也是集群的client节点。

6. Transaction Lifecycle

4.png

在ignite中,事务由tx.start()发起,然后在Near Node上创建Transaction的上下文环境,同时在Near Node上还要做以下事情:
1)为Transaction分配一个事务ID;
2)记录Transaction开始的时间;
3)记录当前topology的version、状态和信息。

将Transaction设置为active状态,然后执行读写操作,再执行Commit操作,完成事务。Transaction commit之后,开始执行两阶段提交,在prepare阶段,primary完成时需要做做以下事情:
1)检查保存在Transaction上下文中的topology version和当前的topology version是否相同;
2)获得所有的锁;
3)创建一个DHT上下文,保存所有的数据;
4)等待或者跳过备份节点完成prepare;
5)Near Node发起执行commit操作;
6)等待所有节点完成commit操作。

7. Pessimistic & READ_COMMITED

5.png

在这种组合模式下,读取数据(例如get、getAll等操作),是不会对entry进行加锁的。所以,可能存在刚开始读到的某个entry的数据,和事务完成(commit)时读到的某个entry的数据是不相同的。

在收到对某个entry的修改操作时,会对这个entry进行锁定操作。当发起commit之前,事务已经完成对所有该事务需要修改的数据的锁定,commit时,才会对primary或者backup上的二数据发起真正的修改操作。

锁的释放只有在整个事务完成之后才进行释放。

8. Pessimistic & (SERIALIZABLE | REPEATABLE_READ)

6.png

在这两种组合模式下,Near Node发现读取数据(例如get、getAll等操作)时,就会对读取的数据进行加锁操作,同样的数据修改操作也会对读取的数据进行加锁操作。

锁的释放只有在整个事务完成之后才进行释放。

9. Optimistic & (READ_COMMITED|REPEATABLE_READ)

7.png

在这两种并发控制组合模式下,数据锁定在prepare阶段才会发生(事务的commit,两阶段提交的prepare),相对于悲观并发控制模式(Near Node上发现有读写即进行锁定)来说,延后了对entry的锁定时间。在prepare阶段,不会比较entry的版本号。

10. Optimistic & SERIALIZABLE

8.png

在这两种并发控制组合模式下,数据锁定在prepare阶段才会发生(事务的commit,两阶段提交的prepare),相对于悲观并发控制模式(Near Node上发现有读写即进行锁定)来说,延后了对entry的锁定时间。在prepare阶段,会比较entry的版本号,与事务刚开始时的entry版本号。如果在prepare阶段发现版本号与事务刚开始时的版本号不相同,那么在prepare阶段就失败。

11. Lock Timeout

9.png

Ignite允许设置一个事务的超时时间,在这种设定模式下,当事务的执行事件超过约定的超时时间时,事务执行失败,需要进行rollback

悲观并发控制模式下:每次对entry进行锁定,都会比较事务执行是否超时

乐观并发控制模式下:只有在prepare阶段进行锁定时,才比较事务执行是否超时

所有参与事务的节点都会检查超时。如果超时,那么会在事务中设计一个标记,以方便NearNode执行事务撤销(回滚操作)

12. Backup Node Failure

10.png

如果一个backup节点损坏,那么事务仍旧会在剩余的节点上完成执行,不会对当前事务的执行产生任何影响。

在事务执行完后,会为这个partition选择一个新的backup节点。

13. Primary Node Failure On Prepare

11.png

如果primary节点在prepare阶段失效,那么系统会抛出一个异常给到客户端,客户端再将异常给到应用程序,由应用程序来决定是重新执行该事务还是做其它工作。

14. Primary Node Failure On Commit

12.png

如果primary节点在prepare节点完成之后失效,那么Near Node会等待backup节点发送过来的消息。

Backup节点发现primary节点失效情况下,会发送消息给到NearNode节点。如果backup已经完成了这个事务需要完成的所有修改操作,则Near Node会继续完成这个事务。

同时topology开始发生改变,并选择一个新的primary来代替失效的primary。

15. Coordinator(Near Node) Failure

13.png

如果Near Node失效,那么处理过程会比较复杂,因为系统中可能有的节点已经完成了commit,有的节点还没有完成commit,而且系统中的transaction的状态目前是没有保存的。

系统中的primary节点互相交换信息,只要有一个primary节点没有完成commit,则触发对这个transaction的回滚操作,参与这个事务的所有节点进行回滚。

MemFireDB,带你体验不一样的云端飞翔。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容