一文讲透微服务下如何保证事务的一致性

原文地址:梁桂钊的博客

博客地址:http://blog.720ui.com

欢迎关注公众号:「服务端思维」。一群同频者,一起成长,一起精进,打破认知的局限性。

从本地事务到分布式事务的演变

什么是事务?回答这个问题之前,我们先来看一个经典的场景:支付宝等交易平台的转账。假设小明需要用支付宝给小红转账 100000 元,此时,小明帐号会少 100000 元,而小红帐号会多 100000 元。如果在转账过程中系统崩溃了,小明帐号少 100000 元,而小红帐号金额不变,就会出大问题,因此这个时候我们就需要使用事务了。请参见图 6-1。

这里,体现了事务一个很重要的特性:原子性。事实上,事务有四个基本特性:原子性、一致性、隔离性、持久性。其中,原子性,即事务内的操作要么全部成功,要么全部失败,不会在中间的某个环节结束。一致性,即使数据库在一个事务执行之前和执行之后,数据库都必须处于一致性状态。如果事务执行失败,那么需要自动回滚到原始状态,换句话说,事务一旦提交,其他事务查看到的结果一致,事务一旦回滚,其他事务也只能看到回滚前的状态。隔离性,即在并发环境中,不同的事务同时修改相同的数据时,一个未完成事务不会影响另外一个未完成事务。持久性,即事务一旦提交,其修改的数据将永久保存到数据库中,其改变是永久性的。

本地事务通过 ACID 保证数据的强一致性。ACID是 Atomic(原子性)、Consistency(一致性)、 Isolation(隔离性)和 Durability(持久性)的缩写 。在实际开发过程中,我们或多或少都有使用到本地事务。例如,MySQL 事务处理使用到 begin 开始一个事务,rollback 事务回滚,commit 事务确认。这里,事务提交后,通过 redo log 记录变更,通过 undo log 在失败时进行回滚,保证事务的原子性。笔者补充下,使用 Java 语言的开发者都接触过 Spring。Spring 使用 @Transactional 注解就可以搞定事务功能。事实上,Spring 封装了这些细节,在生成相关的 Bean 的时候,在需要注入相关的带有 @Transactional 注解的 bean 时候用代理去注入,在代理中为我们开启提交/回滚事务。请参见图6-2。

随着业务的高速发展,面对海量数据,例如,上千万甚至上亿的数据,查询一次所花费的时间会变长,甚至会造成数据库的单点压力。因此,我们就要考虑分库与分表方案了。分库与分表的目的在于,减小数据库的单库单表负担,提高查询性能,缩短查询时间。这里,我们先来看下单库拆分的场景。事实上,分表策略可以归纳为垂直拆分和水平拆分。垂直拆分,把表的字段进行拆分,即一张字段比较多的表拆分为多张表,这样使得行数据变小。一方面,可以减少客户端程序和数据库之间的网络传输的字节数,因为生产环境共享同一个网络带宽,随着并发查询的增多,有可能造成带宽瓶颈从而造成阻塞。另一方面,一个数据块能存放更多的数据,在查询时就会减少 I/O 次数。水平拆分,把表的行进行拆分。因为表的行数超过几百万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。水平拆分,有许多策略,例如,取模分表,时间维度分表等。这种场景下,虽然我们根据特定规则分表了,我们仍然可以使用本地事务。但是,库内分表,仅仅是解决了单表数据过大的问题,但并没有把单表的数据分散到不同的物理机上,因此并不能减轻 MySQL 服务器的压力,仍然存在同一个物理机上的资源竞争和瓶颈,包括 CPU、内存、磁盘 IO、网络带宽等。对于分库拆分的场景,它把一张表的数据划分到不同的数据库,多个数据库的表结构一样。此时,如果我们根据一定规则将我们需要使用事务的数据路由到相同的库中,可以通过本地事务保证其强一致性。但是,对于按照业务和功能划分的垂直拆分,它将把业务数据分别放到不同的数据库中。这里,拆分后的系统就会遇到数据的一致性问题,因为我们需要通过事务保证的数据分散在不同的数据库中,而每个数据库只能保证自己的数据可以满足 ACID 保证强一致性,但是在分布式系统中,它们可能部署在不同的服务器上,只能通过网络进行通信,因此无法准确的知道其他数据库中的事务执行情况。请参见图6-3。

此外,不仅仅在跨库调用存在本地事务无法解决的问题,随着微服务的落地中,每个服务都有自己的数据库,并且数据库是相互独立且透明的。那如果服务 A 需要获取服务 B 的数据,就存在跨服务调用,如果遇到服务宕机,或者网络连接异常、同步调用超时等场景就会导致数据的不一致,这个也是一种分布式场景下需要考虑数据一致性问题。请参见图6-4。

总结一下,当业务量级扩大之后的分库,以及微服务落地之后的业务服务化,都会产生分布式数据不一致的问题。既然本地事务无法满足需求,因此分布式事务就要登上舞台。什么是分布式事务?我们可以简单地理解,它就是为了保证不同数据库的数据一致性的事务解决方案。这里,我们有必要先来了解下 CAP 原则和 BASE 理论。CAP 原则是 Consistency(一致性)、Availablity(可用性)和 Partition-tolerance(分区容错性)的缩写,它是分布式系统中的平衡理论。在分布式系统中,一致性要求所有节点每次读操作都能保证获取到最新数据;可用性要求无论任何故障产生后都能保证服务仍然可用;分区容错性要求被分区的节点可以正常对外提供服务。事实上,任何系统只可同时满足其中二个,无法三者兼顾。对于分布式系统而言,分区容错性是一个最基本的要求。那么,如果选择了一致性和分区容错性,放弃可用性,那么网络问题会导致系统不可用。如果选择可用性和分区容错性,放弃一致性,不同的节点之间的数据不能及时同步数据而导致数据的不一致。请参见图 6-5。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值