关于java:RocketMQ-分布式事务消息

2次阅读

共计 3714 个字符,预计需要花费 10 分钟才能阅读完成。

一、什么是事务

事务是将一次执行过程中所波及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能失常执行的状况下能力提交,只有其中任一操作执行失败,都将导致整个事务的回滚。一句话来说,就是保障多个操作要么都做,要么都不做。同时一旦事务提交,则其所做的批改会永恒保留到数据库。

二、事务的四个个性(ACID)

  • A: 原子性 (Atomicity)
    一个事务 (transaction) 中的所有操作,要么全副实现,要么全副不实现,不会完结在两头某个环节。事务在执行过程中产生谬误,会被回滚(Rollback)到事务开始前的状态,就像这个事务素来没有执行过一样。
  • C: 一致性 (Consistency)
    事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。如果事务胜利地实现,那么零碎中所有变动将正确地利用,零碎处于无效状态。如果在事务中呈现谬误,那么零碎中的所有变动将主动地回滚,零碎返回到原始状态。
  • I: 隔离性 (Isolation)
    指的是在并发环境中,当不同的事务同时操纵雷同的数据时,每个事务都有各自的残缺数据空间。由并发事务所做的批改必须与任何其余并发事务所做的批改隔离。事务查看数据更新时,数据所处的状态要么是另一事务批改它之前的状态,要么是另一事务批改它之后的状态,事务不会查看到中间状态的数据。
  • D: 持久性 (Durability)
    指的是只有事务胜利完结,它对数据库所做的更新就必须永恒保留下来。即便产生零碎解体,重新启动数据库系统后,数据库还能复原到事务胜利完结时的状态。

三、InnoDB 事务实现

基于掂量事务的四个个性,InnoDB 实现事务实际上就是 4 个个性的实现。

  • 原子性

    • 在 MySQL 中有很多类型的日志,二进制日志、查问日志、谬误日志、慢查问日志等等。除了这些日志,还提供了两种事务日志,redo log 用来保障持久性,undo log 是原子性和隔离性实现的根底。
    • 数据库每执行一条更新数据的 sql 就会生成一条 undo log,比方 insert 一条数据,就会生出一条 delete 的 undo log。如果事务执行失败或者调用 rollback 就能够依据 undo log 做数据回滚。
  • 隔离性

    • 隔离性是指,事务外部的操作与其余事务是隔离的,并发执行的各个事务之间不能相互烦扰。严格的隔离性,对应了事务隔离级别中的 Serializable (可串行化),但理论利用中出于性能方面的思考很少会应用可串行化。
    • InnoDB 采纳可反复读隔离级别,应用 MVCC 和行锁、间隙锁实现隔离性。
  • 持久性

    • InnoDB 作为 MySQL 的存储引擎,数据是寄存在磁盘中的,但如果每次读写数据都须要磁盘 IO,效率会很低。为此,InnoDB 提供了缓存(Buffer Pool),Buffer Pool 中蕴含了磁盘中局部数据页的映射,作为拜访数据库的缓冲:当从数据库读取数据时,会首先从 Buffer Pool 中读取,如果 Buffer Pool 中没有,则从磁盘读取后放入 Buffer Pool;当向数据库写入数据时,会首先写入 Buffer Pool,Buffer Pool 中批改的数据会定期刷新到磁盘中(这一过程称为刷脏)。
    • Buffer Pool 的应用大大提高了读写数据的效率,然而也带了新的问题:如果 MySQL 宕机,而此时 Buffer Pool 中批改的数据还没有刷新到磁盘,就会导致数据的失落,事务的持久性无奈保障。
    • 于是,redo log 被引入来解决这个问题:当数据批改时,除了批改 Buffer Pool 中的数据,还会在 redo log 记录这次操作;当事务提交时,会调用 fsync 接口对 redo log 进行刷盘。如果 MySQL 宕机,重启时能够读取 redo log 中的数据,对数据库进行复原。redo log 采纳的是 WAL(Write-ahead logging,预写式日志),所有批改先写入日志,再更新到 Buffer Pool,保障了数据不会因 MySQL 宕机而失落,从而满足了持久性要求。

    既然 redo log 也须要在事务提交时将日志写入磁盘,为什么它比间接将 Buffer Pool 中批改的数据写入磁盘 (即刷脏) 要快呢?次要有以下两方面的起因:
    (1)刷脏是随机 IO,因为每次批改的数据地位随机,但写 redo log 是追加操作,属于程序 IO。
    (2)刷脏是以数据页(Page)为单位的,MySQL 默认页大小是 16KB,一个 Page 上一个小批改都要整页写入;而 redo log 中只蕴含真正须要写入的局部,有效 IO 大大减少。

  • 一致性

    • 一致性是指事务执行完结后,数据库的完整性束缚没有被毁坏,事务执行的前后都是非法的数据状态。
    • 一致性不仅由数据库自身来保障,同时业务零碎也保证数据的一致性。

四、分布式事务的由来

古代软件架构随着业务畛域划分为多个微服务,独特组成了简单的软件系统。而从数据库层面来看,随着数据量的暴发,不得不采纳分库分表的形式,升高数据库的压力。这样,就造成多个服务依赖不同的数据库,那么在同时操作的时候,如何保障事务?这就是分布式事务。

简而言之,分布式事务就是一个大的事务由不同的子事务组成,这些小的事务操作散布在不同的服务器节点下面,属于不同的微服务,分布式事务须要保障同一事务下的子事务要么全副胜利,要么全副失败,即保证数据的最终一致性。

五、分布式事务解决方案

在这篇不想用太大的篇幅说一些概念上的货色,然而要说 RocketMQ 的分布式事务实现,所以在这里顺便提一下以后分布式事务的集中解决方案:

  • 两阶段提交(2PC)

    两阶段提交(2PC) 是 Oracle Tuxedo 零碎提出的 XA 分布式事务协定的其中一种实现形式,参考《分布式事务之两阶段提交(2PC)》。

  • Try-Confirm-Cancle(TCC)

    TCC 是基于尝试、确认、勾销来实现分布式事务的,想理解更多,参考《分布式事务之弥补事务(TCC)》。

  • 本地音讯表

    本地音讯表 计划最后是 ebay 提出的,外围是将须要分布式解决的工作通过消息日志的形式来异步执行。消息日志能够存储到本地文本、数据库或音讯队列,再通过业务规定主动或人工发动重试。人工重试更多的是利用于领取场景,通过对账系统对预先问题的解决。

除了上述外,还有一些解决方案,比方阿里 SEATA,SAGA 计划和最大致力告诉 … 感兴趣同学们能够自行理解, 当然还有咱们这篇要说的 MQ 事务。

六、MQ 事务

RocketMQ 是阿里开源的一款高性能、高吞吐量的分布式消息中间件,基于音讯异步形式提供了对分布式事务的反对,实现事务最终一致性。

上面是 RocketMQ 事务音讯的根本流程交互图:

如图其中分为两个流程:失常事务音讯的发送及提交、事务音讯的弥补流程。

1. 事务音讯发送及提交:

(1) 发送 half 音讯。
(2) 服务端响应音讯写入后果。
(3) 依据发送后果执行本地事务(如果写入失败,此时 half 音讯对业务不可见,本地逻辑不执行)。
(4) 依据本地事务状态执行 Commit 或者 Rollback(Commit 操作生成音讯索引,音讯对消费者可见)

流程图如下:

2. 弥补流程:

(1) 对没有 Commit/Rollback 的事务音讯(pending 状态的音讯),从服务端发动一次“回查”
(2) Producer 收到回查音讯,查看回查音讯对应的本地事务的状态
(3) 依据本地事务状态,从新 Commit 或者 Rollback

其中,弥补阶段应用定时器回查形式用于解决音讯 Commit 或者 Rollback 产生超时或者失败的状况。

七、RocektMQ 事务音讯的应用

如上,小伙伴们应该对 RocketMQ 的事务音讯有了肯定的理解,上面看下如何在开发场景下如何应用。

发送事务音讯时和一般的音讯区别是,本人要新建一个 TransactionMQProducer 和对应的一个 TransactionListener的实现。

  • TransactionMQProducer
    具体的配置有 group、nameServer 地址、执行本地事务的线程池和事务监听器的实现。
this.producer = new TransactionMQProducer(config.getGroup());
    this.producer.setNamesrvAddr(config.getNameServer());
    this.producer.setExecutorService(config.getExecutorService());
    this.producer.setTransactionListener(config.getTransactionListener());
  • TransactionListener
    实现 TransactionListener 接口的两个办法:

    • executeLocalTransaction(Message message, Object o)
      用于执行本地事务的办法。
    • checkLocalTransaction(MessageExt messageExt)
      RocketMQ 回查本地事务状态调用的办法。

代码详见 ???? : https://github.com/wangning1018/rocketmq-transaction-message-demo

欢送拜访集体博客 获取更多常识分享。

正文完
 0