分布式

Raft 论文摘要(二)

Raft 论文摘要(二)

D瓜哥
在上一篇文章中,通过阅读 《In Search of an Understandable Consensus Algorithm》 前三节的内容,对论文的大致内容做了简介,简单说明了一下 Replicated state machines 的用途以及 Paxos 本身存在的问题。 4. Designing for understandability several goals in designing Raft: it must providea complete and practical foundation for system building; it must be safe under all conditions and available under typical operating conditions; it must be efficient for common operations. Our most important goal — and most difficult challenge — was understandability. 从这里可以看出,Raft 设计的初衷就是为了易于理解和便于构建。 There were numerous points in the design of Raft where we had to choose among alternative approaches.
Raft 论文摘要(一)

Raft 论文摘要(一)

D瓜哥
前一段时间,在一次开组会的时候,给小组成员简单介绍了一下 Raft 协议。大概四年前读过 Raft 的论文,这次分享的时候,好多好多细节都忘了。所以,再次把 《In Search of an Understandable Consensus Algorithm》 这篇论文找出来,重读一遍,做个笔记和摘要,方便后续学习和复习。 Abstract Raft is a consensus algorithm for managing a replicated log. 开篇摘要就点出了 Raft 的特点: Raft 是一种管理复制日志的共识算法。 In order to enhance understandability, Raft separates the key elements of consensus, such as leader election, log replication, and safety, and it enforcesa stronger degree of coherency to reduce the number of states that must be considered. 为了增强可理解性,Raft 将共识分解成几个关键元素,例如 Leader 选举,日志复制,以及安全性等;同时,为了降低需要考虑的状态的数量,还强制实施了更强的一致性。
分布式锁之 Apache Curator InterProcessReadWriteLock

分布式锁之 Apache Curator InterProcessReadWriteLock

在上一篇文章 分布式锁之 Apache Curator InterProcessMutex 中介绍了基于 ZooKeeper 实现的互斥锁。除此之外,还可以实现读写锁。这篇文章就来简要介绍一下 InterProcessReadWriteLock 的实现原理。 老规矩,先看看类的注释: /** * <p> * A re-entrant read/write mutex that works across JVMs. Uses Zookeeper to hold the lock. All processes * in all JVMs that use the same lock path will achieve an inter-process critical section. Further, this mutex is * "fair" - each user will get the mutex in the order requested (from ZK's point of view). * </p> * * <p> * A read write lock maintains a pair of associated locks, one for read-only operations and one * for writing.
分布式锁之 Apache Curator InterProcessMutex

分布式锁之 Apache Curator InterProcessMutex

对分布式锁耳熟能详。不过,一直关注的是基于 Redis 实现的分布式锁。知道 ZooKeeper 也可以实现分布式锁。但是,原来的想法是把 Redis 那个思路切换到 ZooKeeper 上来实现就好。今天了解到 Apache Curator 内置了分布式锁的实现: InterProcessMutex。查看了一下源码实现,发现跟基于 Redis 实现的源码相比,在思路上还是有很大不同的。所以,特别作文记录一下。 先来看一下,整体流程: 结合流程图和源码,加锁的过程是这样的: 先判断本地是否有锁数据,如果有则对锁定次数自增一下,然后返回 true; 如果没有锁数据,则尝试获取锁: 在指定路径下创建临时顺序节点 获取指定路径下,所有节点,检查自身是否是序号最小的节点: 如果自身序号最小,则获得锁;否则 如果自身不是序号最小的节点,则通过 while 自旋 + wait(times) 不断尝试获取锁,直到成功。 获得锁后,把锁信息缓存在本地 ConcurrentMap<Thread, LockData> threadData 变量中,方便计算重入。 在 ZooKeeper 中的结构大致如下: 下面我们逐个方法进行分析说明。先来看一下 InterProcessMutex 的注释: /** * A re-entrant mutex that works across JVMs. Uses Zookeeper to hold the lock. All processes in all JVMs that * use the same lock path will achieve an inter-process critical section.
Spring 扩展点实践:整合 Apache Dubbo(二)

Spring 扩展点实践:整合 Apache Dubbo(二)

D瓜哥
在 Spring 扩展点实践:整合 Apache Dubbo(一) 中,D瓜哥介绍了 Dubbo 如何使用 Spring 的插件机制与 Spring 整合。限于篇幅原因,上一篇文章只介绍到了服务提供者的注册。本篇文章继续上一篇文章的主题,继续介绍 Spring 与 Dubbo 的整合过程。先来讲解一下服务消费者的生成过程。 Dubbo 生成服务消费者的过程 先来看看 XML 配置文件: dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/resources/spring/dubbo-consumer.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"> <dubbo:application name="demo-consumer"/> <dubbo:registry address="zookeeper://127.0.0.1:2181"/> <dubbo:reference id="demoService" check="false" interface="org.apache.dubbo.demo.DemoService"/> </beans> 我们先看一下 ReferenceBean 类的声明: org.apache.dubbo.config.spring.ReferenceBean public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean { // 此处省略 N 行代码 @Override public Object getObject() { return get(); } // 此处省略 N 行代码 @Override @SuppressWarnings({"unchecked"}) public void afterPropertiesSet() throws Exception { // Initializes Dubbo's Config Beans before @Reference bean autowiring prepareDubboConfigBeans(); // lazy init by default.
Spring 扩展点实践:整合 Apache Dubbo(一)

Spring 扩展点实践:整合 Apache Dubbo(一)

D瓜哥
在上一篇文章 Spring 扩展点概览及实践 中介绍了 Spring 内部存在的扩展点。 Spring 扩展点实践:整合 MyBATIS 中,D瓜哥带大家了解了一下 MyBATIS 如何利用 Spring 的扩展点实现了与 Spring 的完美整合。现在,学以致用,我们继续来分析一下 Spring 与 Apache Dubbo 的整合流程。 示例程序 Apache Dubbo 仓库中就有很完整的示例。D瓜哥直接拿来使用就不再搭建示例程序了。 首先,需要启动一个 ZooKeeper 实例。查看 Dubbo 的依赖可以看出,最新版代码依赖的 ZooKeeper 是 3.4.13 版。所以,为了最好的兼容性,就要选用 3.4.X 版的 ZooKeeper 服务器。D瓜哥直接使用 Docker 启动 ZooKeeper 了。命令如下: docker run --rm --name zookeeper -d -p 2181:2181 zookeeper:3.4.14 这次我们使用 Apache Dubbo 的 dubbo-demo/dubbo-demo-xml 示例。 第二步,启动服务提供者程序,找到 DUBBO/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-provider/src/main/java/org/apache/dubbo/demo/provider/Application.java,运行该类。 第三步,运行服务消费者程序,找到 DUBBO/dubbo-demo/dubbo-demo-xml/dubbo-demo-xml-consumer/src/main/java/org/apache/dubbo/demo/consumer/Application.java,运行该类。 如果没有任何错误,则在终端可以看到 result: async result 输出。 在开始正餐之前,D瓜哥先给大家来个开胃菜。 Spring 插件机制简介 不知道大家有没有想过一个问题:Spring 框架是如何支持越来越多的功能的?
Kafka 常见面试题

Kafka 常见面试题

D瓜哥
Kafka 是由 LinkedIn 开发的一个分布式的消息系统,使用 Scala 编写,它以可水平扩展和高吞吐率而被广泛使用。Kafka 本身设计也非常精巧,有很多关键的知识点需要注意。在面试中,也常常被问到。整理篇文章,梳理一下自己的知识点。 架构设计问题 Kafka 整体架构如下: Figure 1. Kafka 架构 Kafka 架构分为以下几个部分 Producer:消息生产者,就是向 Kafka Broker 发消息的客户端。 Consumer:消息消费者,向 Kafka Broker 取消息的客户端。 Topic:可以理解为一个队列,一个 Topic 又分为一个或多个分区。 Consumer Group:这是 Kafka 用来实现一个 Topic 消息的广播(发给所有的 Consumer)和单播(发给任意一个 Consumer)的手段。一个 Topic 可以有多个 Consumer Group。 Broker:一台 Kafka 服务器就是一个 Broker。一个集群由多个 Broker 组成。一个 Broker 可以容纳多个 Topic。 Partition:为了实现扩展性,一个非常大的 Topic 可以分布到多个 Broker上,每个 Partition 是一个有序的队列。Partition 中的每条消息都会被分配一个有序的id(offset)。将消息发给 Consumer,Kafka 只保证按一个 Partition 中的消息的顺序,不保证一个 Topic 的整体(多个 Partition 间)的顺序。 Offset:Kafka 的存储文件都是按照 offset.Kafka 来命名,用 offset 做名字的好处是方便查找。例如你想找位于 2049 的位置,只要找到 2048.

负载均衡算法及实践

D瓜哥
前几天在看一个资料时,看到关于负载均衡算法的介绍。最近也在研究 Spring Cloud 和 Apache Dubbo 等微服务框架。正好负载均衡是微服务框架中一个很重要的知识点。就动手做个整理和总结。方便后续学习。 听朋友建议,这篇文章还可以在算法对比,客户端负载均衡与服务端负载均衡区分等两方面做些补充。这些内容后续再补充加入进来。 常见的负载均衡算法 轮询(Round Robin)法 轮询选择指的是从已有的后端节点列表中按顺序依次选择一个节点出来提供服务。 优点:试图做到请求转移的绝对均衡。实现简单,使用广泛。 加权轮询(Weighted Round Robin)法 实际使用中各个节点往往都带有不同的权重,所以一般都需要实现带权重的轮询选择。 权重高的被选中的次数多,权重低的被选中的次数少。 优点:是 轮询(Round Robin)法 改良版。适用于服务器配置不一致时,可以将配置好的服务器多干活,配置差的服务器少干活以使机器的负载达到相同的水平。 静态轮询(Static Round Robin)法 HAProxy 中实现的一个负载均衡算法。 没有后台服务器的限制,服务器启动时,修改权重也不会生效。增删服务器时,服务器准备就绪后,会立即加入到服务队列中。 随机(Random)法 通过随机函数,根据后端服务器列表的大小值来随机选择其中一台进行访问。由概率统计理论可以得知,随着调用量的增大,其实际效果越来越接近于平均分配流量到每一台后端服务器,也就是轮询的效果。 加权随机(Weighted Random)法 与加权轮询法类似,加权随机法也是根据后端服务器不同的配置和负载情况来配置不同的权重。不同的是,它是按照权重来随机选择服务器的,而不是顺序。 原地址哈希(IP Hashing)法 源地址哈希的思想是获取客户端访问的IP地址值,通过哈希函数计算得到一个数值,用该数值对服务器列表的大小进行取模运算,得到的结果便是要访问的服务器的序号。 优点:保证了相同客户端 IP 地址将会被哈希到同一台后端服务器,直到后端服务器列表变更。根据此特性可以在服务消费者与服务提供者之间建立有状态的 Session 会话。 URI 哈希(URI Hashing)法 HAProxy 中实现的一个负载均衡算法。支持部分 URI(问号之前)和完整 URI 两种模式。 这个算法可以把同一个 URI 的访问发送到同一台服务器上,以最大程度提高缓存命中率。 该算法支持两个可选参数 len 和 depth,后跟一个正整数。仅在需要基于URI的开头来平衡服务器时,这些选项可能会很有用。 len 参数指示算法仅应考虑URI开头的许多字符来计算哈希。请注意,将 len 设置为 1 几乎没有意义,因为大多数URI都以前导 / 开头。 depth 参数指示用于计算哈希的最大目录深度。请求中的每个斜杠都计为一个级别。如果同时指定了两个参数,则在达到任意一个参数时都将停止评估。 哈希算法也有很多中,而且不同算法各有优缺。回头单独开篇整理吧。 URL 参数(URL Parameter)法 HAProxy 中实现的一个负载均衡算法。根据 URL 参数的哈希值来选择服务器。

在世界读书日,推荐书单

今天是世界读书日,各种人都在推荐书单。D瓜哥也凑个热闹,水一篇文章,推荐一些书籍。 在前一段时间,D瓜哥已经写了一个书单: 推荐几本 Java 并发编程的书。为了避免重复,上一个书单中推荐过的书籍,这次就不再重复推荐了。 每年十二个月,D瓜哥就推荐 12 本书,每个月读一本想必压力也不算大。 如何阅读一本书? D瓜哥在年初的时候,刚刚再次重读了这本书。而且,还写了一篇读书笔记: 《如何阅读一本书?》之读书笔记。 如果喜欢读书,那么这本书绝对应该是首先阅读的第一本书。一句话总结一下:用检视阅读的方法来快速筛选出你关注主题的书籍;用分析阅读的方法来吸收一本书的精华;用主题阅读的办法来对多本同一主题的书去伪存真,加工再输出。 远见 D瓜哥在去年年末写的年终总结 “告别 2019,迎接 2020” 中提到了这本书。考虑这本书的实用性和对自身发展的指导意义,所以决定再次推荐这本书。 在这本书中,作者将职业生涯分为:强势开局、聚焦长板和实现持续的影响力三个阶段。 在强势开局阶段,就像要开始一个汽车拉力赛,要努力加添燃料。 在聚焦长板阶段,要努力提高自己的核心竞争力,创造自己的制高点。 在实现持续的影响力阶段,则要优化长尾效应,让自己持续保持领先。 对于职业生涯有追求的小伙伴,尤其是在读大学生,一定要去尽早认真读一读这本书。 思考,快与慢 这是一本有关心理学方面的书籍。作者丹尼尔•卡尼曼因其与阿莫斯•特沃斯基在决策制定上的研究而荣获了 2002 年度的诺贝尔经济学奖。所以,这本书质量上肯定是有保证的。 这本书主要是介绍认知心理学的。作者在书中,把人的认知分为系统一和系统二。系统一是那种不需要思考的,已经固化在我们基因中的反应,比如看见危险会跑路等;而系统二,则是需要深入思考才能有所收获的事情,比如在新税法下,计算个人应该缴纳的个人所得税。两个系统相辅相成,时刻影响着我们的生活,但我们却有些熟视无睹。 穷查理宝典 提起查理·芒格,也许有些人不知道是谁。(看这篇文章的读者估计都了解)但是,他的搭档估计是人尽皆知,那就是世界股神沃伦·巴菲特。 虽然这本书不是查理·芒格书写的,里面的精华部分,却都是查理的演讲稿。通过这些演讲,你可以看到一个睿智的老人,如何在循循善诱地向你传授他的思维方法。查理给我们介绍了他的思维模型:逆向思维,多元思维模型,打造自己的核心圈,避免嫉妒效应,内部积分卡(用我们古人的话说就是反求诸己)等等。 社会性动物 D瓜哥是去年开始读这本书的,非常抱歉目前还没有读完。 这本书是讲述社会心理学的,讲述在这个社会中,人与人之间是如何相互影响的。举一个典型的例子:你思考过吗,什么样的广告最能打动你吗? 事实 比尔·盖茨也推荐了这本书。我也是最近刚刚开始读这本书。还没有读完。就不做过多评价了。用一个问题,勾引一下你的兴趣: 问题:在全世界所有的低收入国家里面,有多少百分比的女孩能够上完小学? 选项:A. 20% B. 40% C. 60% 想知道答案,就快点去读这本书吧。 最近更新:D瓜哥终于把这本书读完了:https://www.diguage.com/post/factfulness/[《事实》之读书笔记^]。 人类简史 坦白讲,这本书D瓜哥才读了一半。但是,作者最近发表的一篇文章: 尤瓦尔·赫拉利《冠状病毒之后的世界》,一个史学家站在历史发展的角度去看待疫情对世界发展的影响。由此可对赫拉利的思想窥得一斑。那么,如果感兴趣,他的成名大作《人类简史》就不得不读了。 最近因为疫情影响,在网上看到各种五毛的无脑言论,怼天怼地,仿佛中国要征服世界,征服宇宙一样,真是让人呵呵… 未来几十年时间里,中国未来寻求自身发展,还需要融入到整个世界经济中,在全世界产业链中,力争上游,占领高附加值的产业,比如芯片,5G,大飞机等等。怼这个,怼那个,只能让自己像二战时期的纳粹德国和日本,让自己四面树敌,最后被全世界群殴。 上帝掷骰子吗? 这是D瓜哥看过的,最好看的科普书,没有之一。 你知道爱因斯坦因为发表相对论,革了物理学的命;但是你知道吗?爱因斯坦也因为自己的顽固守旧阻碍过量子物理的发展。你知道普朗克首次提出量子的概念;但是,你了解吗?普朗克却是非常坚决地反对量子物理的发展。你了解薛定谔的猫到底是怎么回事吗?这些料都可以在这本书中读到。 作者通过各种各样的故事展示了量子物理学从无到有,颠覆整个经典物理,然后又重塑整个现代物理的过程。整个故事可谓波澜壮阔,跌宕起伏。 另外,从这本书中,我希望大家能读出科学的味道。曾经跟一个朋友在讨论,到底什么是科学?我举两个例子来说明: 关于光本质的三次论战 现在,上过高中物理的人都了解,光具有波粒二象性。说得更直白一些,光即是波,也是粒子。围绕光到底是波,还是粒子在历史上,曾经有过三次论战,参与论战的也不乏大家耳熟能详的物理大咖。 第一次的主角是牛顿牛爵爷,通过观察光的直线传播和反射现象,牛顿将光解释为粒子。考虑到牛顿在当时已经是成绩斐然的世界知名物理学家,他的观点在当时得到了广泛的认可。这是第一次论战。 第二次论战的主角是托马斯·杨,这位主角想必学过高中物理的童鞋,想必对双缝干涉实验都有印象。双缝干涉实验是高中物理中非常重要的一个实验,而且操作也很简单。双缝干涉实验就是托马斯·杨发明的。托马斯·杨完成了双缝干涉实验,有力地证明了光的波动性质。然后,大家开始普遍接受光的波动性学说。 你以为这就完了吗?然而并没有,最后踢出临门一脚的是又一个大名鼎鼎的物理学家:爱因斯坦。1905年,爱因斯坦发表论文,对于光电效应给出解释。他把光解释为即是波,也是粒子。至此,这个长达近三百年的争论才得以盖棺论定。爱因斯坦也因为这篇论文,获得了 1921 年度的诺贝尔物理学奖。 牛顿的经典力学 学过初中物理的童鞋,相关对牛顿运动三定理都很了解。从 1687 年,牛顿发表《自然哲学的数学原理》,在书中详细阐述了牛顿运动三定律。至此,两百多年时间里,《自然哲学的数学原理》几乎奠定了经典物理的基础。可谓无往不胜。 但是,在计算水星轨道时,总是出现微小的偏差。物理学家不断尝试来解决这个问题,却一直未能如愿。直道 1915 年爱因斯坦发表广义相对论,才正确地解释了水星近日点的反常进动。后来,经过广义相对论的进一步的发展,人们发现,牛顿运动定律只是在低速情况下,广义相对论的特例。

分布式事务概述

D瓜哥
现在手机银行转账已经司空见惯。但是,D瓜哥一直在思考,银卡跨行转账是如何保证事务一致性的?借机就对分布式事务,做了简单地了解。 2PC 两阶段提交(2pc, two-phase commit protocol),2pc是非常经典的强一致性、中心化的原子提交协议。中心化是指协议中有两类节点:一个中心化协调者节点(coordinator)和N个参与者节点(participant、cohort)。 顾名思义,两阶段提交协议的每一次事务提交分为两个阶段: 在第一阶段,协调者询问所有的参与者是否可以提交事务(请参与者投票),所有参与者向协调者投票。 在第二阶段,协调者根据所有参与者的投票结果做出是否事务可以全局提交的决定,并通知所有的参与者执行该决定。在一个两阶段提交流程中,参与者不能改变自己的投票结果。两阶段提交协议的可以全局提交的前提是所有的参与者都同意提交事务,只要有一个参与者投票选择放弃(abort)事务,则事务必须被放弃。 两阶段提交协议也依赖与日志,只要存储介质不出问题,两阶段协议就能最终达到一致的状态(成功或者回滚) 优点 强一致性,只要节点或者网络最终恢复正常,协议就能保证顺利结束;部分关系型数据库(Oracle)、框架直接支持 缺点 网络抖动导致的数据不一致: 第二阶段中协调者向参与者发送commit命令之后,一旦此时发生网络抖动,导致一部分参与者接收到了commit请求并执行,可其他未接到commit请求的参与者无法执行事务提交。进而导致整个分布式系统出现了数据不一致。 超时导致的同步阻塞问题: 2PC中的所有的参与者节点都为事务阻塞型,当某一个参与者节点出现通信超时,其余参与者都会被动阻塞占用资源不能释放。 单点故障的风险: 由于严重的依赖协调者,一旦协调者发生故障,而此时参与者还都处于锁定资源的状态,无法完成事务commit操作。虽然协调者出现故障后,会重新选举一个协调者,可无法解决因前一个协调者宕机导致的参与者处于阻塞状态的问题。 基于两阶段提交的分布式事务在提交事务时需要在多个节点之间进行协调,最大限度地推后了提交事务的时间点,客观上延长了事务的执行时间,这会导致事务在访问共享资源时发生冲突和死锁的概率增高,随着数据库节点的增多,这种趋势会越来越严重,从而成为系统在数据库层面上水平伸缩的"枷锁", 这是很多Sharding系统不采用分布式事务的主要原因。 3PC 三阶段提交协议(3pc Three-phase_commit_protocol)主要是为了解决两阶段提交协议的阻塞问题,从原来的两个阶段扩展为三个阶段,并且增加了超时机制。 3PC 的三个阶段分别是 CanCommit、PreCommit、DoCommit CanCommit 协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。 PreCommit 协调者向所有参与者发送PreCommit命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者中有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。 DoCommit 在前两个阶段中所有参与者的响应反馈均是YES后,协调者向参与者发送DoCommit命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送abort请求命令,执行事务的中断。 3PC只是解决了在异常情况下2PC的阻塞问题,但导致一次提交要传递6条消息,延时很大。 TCC TCC是Try、Commit、Cancel的缩写,TCC在保证强一致性的同时,最大限度提高系统的可伸缩性与可用性。 TCC(Try-Confirm-Cancel)又被称补偿事务,TCC 与 2PC 的思想很相似,事务处理流程也很相似,但 2PC 是应用于在 DB 层面,TCC 则可以理解为在应用层面的 2PC,是需要我们编写业务逻辑来实现。 TCC 的核心思想是:"针对每个操作都要注册一个与其对应的确认(Try)和补偿(Cancel)"。 一个完整的业务包含一组子业务,Try操作完成所有的子业务检查,预留必要的业务资源,实现与其他事务的隔离;Confirm使用Try阶段预留的业务资源真正执行业务,而且Confirm操作满足幂等性,以遍支持重试;Cancel操作释放Try阶段预留的业务资源,同样也满足幂等性。“一次完整的交易由一系列微交易的Try 操作组成,如果所有的Try 操作都成功,最终由微交易框架来统一Confirm,否则统一Cancel,从而实现了类似经典两阶段提交协议(2PC)的强一致性。” 再来一个例子: 与2PC协议比较 ,TCC拥有以下特点: 位于业务服务层而非资源层 ,由业务层保证原子性 没有单独的准备(Prepare)阶段,降低了提交协议的成本 Try操作 兼备资源操作与准备能力 Try操作可以灵活选择业务资源的锁定粒度,而不是锁住整个资源,提高了并发度 缺点 应用侵入性强:TCC由于基于在业务层面,至使每个操作都需要有 try、confirm、cancel三个接口。 开发难度大:代码开发量很大,要保证数据一致性 confirm 和 cancel 接口还必须实现幂等性。 在 Seata 中,根据两阶段行为模式的不同,我们将分支事务划分为 Automatic (Branch) Transaction Mode 和 Manual (Branch) Transaction Mode.