首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ACID到底是个啥?浅谈微服务架构中的分布式数据管理

ACID到底是个啥?浅谈微服务架构中的分布式数据管理

作者头像
魏新宇
发布2018-03-22 16:20:21
1.3K0
发布2018-03-22 16:20:21
举报

ACID到底是个啥?

在传统的单体应用中,其后端通常会有一个关系型数据库,如Oracle DB、MySQL等。通过关系型数据库,有助于保证业务的ACID。

ACID这个贯口,相信大多数同学都能说出一二,但真正把这四点脱稿讲清楚,相信也不太容易,尤其是隔离性(I)方面。因此,我先介绍ACD,将I放在最后。

原子性A :定义:整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。

例如,大卫向小卫转账1000元。这个要么转成了,1000元到账;要不转账失败,不存在转账成功一半,转了500元的情况。

一致性C :定义:事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。

还拿转账举例子:张三、李四、王五是三个好基友。三个人每人账户有100元,共有300元。张三给李四转账10,李四给王五转账50,王五给张三转账100。那么,最后三个人账户的总额仍是300。

持久性D: 定义:在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。一旦交易提交了就不可回滚.

这点是可以很容易理解的。大卫给小卫转账,只要转成功了,就不能撤销转账了,后悔也来不及了。除非大卫再忽悠小卫把钱转回来。

隔离性I :定义:如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。即使交易并发执行,看起来也是串行的(Isolation: Concurrently executing transactions see the stored information as if they were running serially (one after another).)

这段话其实比较绕。别着急,看完以下内容,就清晰了。

先看一张大卫根据查阅到的资料总结的表,级别的数字越高,隔离的级别也就最高,牺牲的性能也就最多,最高的级别就是将多个并发事务串行执行:

事务隔离级别

事务隔离描述

解决的问题

不能解决的问题

最低1

Read Uncommitted

脏读

2

Read Committed

脏读

不可重复读

3

Repeated Read

脏读、不可重复读

幻读

最高4

Serialization

脏读、不可重复读、幻读

事务的隔离级(每个事务之间)别从低到高有:

1.Read Uncommitted:定义:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。

这个级别的隔离,会造成脏读。事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。

举个例子,网购:卖家是先确认到买家把钱打过来,再给卖家确认发货。如果卖家访问到的是买家正在付款时的事务信息,但并没有提交(卖家并不知道买家没有提交事务),然后就把货发给卖家。而在几个小时候,买家因为一些原因,撤销订单。这时候,卖家访问到的数据,就是脏数据。

2.Read Committed:定义:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。

通过Read Committed这种方式,可以解决Read Uncommitted举的网购尴尬的例子。但解决不了不可重复读的问题。

不可重复读(Non-repeatable read) : 在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务B在事务A提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这导致锁竞争加剧,影响性能。

举个例子:网购的时候,汤姆、杰瑞和凯特三个人都想同时买一箱牛栏山二窝头酒。而网站上只有两箱库存。三个人分别登录网站的时候,都看到还有两箱库存,三个人同时下单。结果在后台,汤姆和杰瑞的网速快一点,下单成功,而过了一天,卖家告诉凯特,你的酒买不成了,原因缺货。凯特暴怒:“TM我买的时候显示有货啊!” 结果很尴尬。。。

3.Repeated Read:定义:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。

Repeated Read隔离级别可以解决脏读和不可重复读的问题,但解决不了幻读(Phantom Read)的问题。

什么是幻读?在同一个事务中,同一个查询多次返回的结果不一致。事务A新增了一条记录,事务B在事务A提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读仅指由于并发事务增加记录导致的问题,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

继续上面的例子网购的时候,汤姆、杰瑞和凯特三个人都想同时买一箱红星二窝头酒。而网站上只有两箱库存。三个人分别登录网站的时候,都看到还有两箱库存,同时下单,结果汤姆和杰瑞的动作快一点,买成功。到凯特确认提交订单的时候,显示没库存了,因此无法提交订单。。凯特一愣:靠!之前不是显示库存还有一箱的么?!

4.Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

所以说,解决事务的隔离问题的终极方案,是将所以所有的并行事务改成串行执行,但显然,这将大幅度牺牲性能。

最后,我们再看一下上面列出过的表格,应该体会就比较深了:

事务隔离级别

事务隔离描述

解决的问题

不能解决的问题

最低1

Read Uncommitted

脏读

2

Read Committed

脏读

不可重复读

3

Repeated Read

脏读、不可重复读

幻读

最高4

Serialization

脏读、不可重复读、幻读

其实,大多数有过网购同学,都有过双十一抢购货物,到最后显示无货的经历。当然,这无伤大雅。

但对于银行而言,宁可牺牲一部分性能,也要保证数据的ACID,很简单,这个玩意和money有关。

利用关系型数据库,尽量保证事务ACID和CAP的方式,貌似无任何问题,也天下无敌了。大卫半路出家学过一点Oracle DB的知识,知道那个经典的

Select For update语句和故事。传统的RDBMS虽然锁特别重,但数据一致性的保护是非常好的。

但是,在微服务架构中,情况有变。对于微服务架构来说,数据都是微服务私有的,唯一可访问的方式就是通过API。这种打包数据访问方式使得微服务之间松耦合,并且彼此之间独立。传统式关系型数据库方式就不是很适合。

在上图中,订单服务不能直接访问客户表,只能通过客户服务发布的API来访问。订单服务也可以使用分布式事务处理(两阶段提交 2PC,这个概念在文后会有介绍)。

在服务和数据库之间维护数据一致性是非常根本的需求,在微服务架构中,2PC并不是一个十分理想的方案,因此我们需要找其他的方案。

事件驱动架构

在微服务架构中,我们将传统单体应用的各个功能模块拆分成多个更细小的服务,部署在容器或者虚拟机中。因此保证事务的一致性有点费劲。

为了方便理解,我们举个例子。有四个不错的朋友,以前一起工作,一起租房子住,想打麻将的时候,喊一嗓子,就可以开始打了。后来大家换了工作,有了自己的家庭。想再约打麻将,就可以建个微信群,约起来。在这四个微信群里,大家除了可以约打麻将,还可以约喝酒。

如果说以前大家住在一起的时候,可以简单地理解成一个单体应用。四个组件之间紧耦合。而后来大家分开以后,实现了松耦合,四个人之间的通讯,就需要微信群这个消息代理(Messsage Broker)来交换事件。也就是事务驱动型架构(event-driven architecture)。

在事务驱动型架构这种架构中,当某件重要事情发生时,微服务会发布一个事件,例如更新一个业务实体。当订阅这些事件的微服务接收此事件时,就可以更新自己的业务实体,也可能会引发更多的时间发布。

接下来,举的一个例子是,有两个微服务:Order Service和Customer Service。而这两个微服务之间的交互还是比较多的。两个微服务之间,有个消息代理。

第一步:客户端(通过API Gateway)对Order Service的微服务发起请求,创建个订单。而创建订单这个请求,在Order Service的数据库表中增加一行记录。而Order Service收到创建订单的请求的同时,向消息代理发一个创建订单的事件:

第二步:Customer Service这个微服务,通过消息代理获取到了创建订单的这个事件,然后,Customer Service在其后端数据库中,为此订单预留信用,然后向消息代理发布一个“Credit Reserved Event(信用预留)”事件

第三步:Order Service收到了Credit Reserved Event,改变订单的状态为OPEN

事件驱动架构优点是:使得交易跨多个服务且提供最终一致性,并且可以使应用维护最终视图;缺点在于编程模式比ACID 交易模式更加复杂。

消息代理的功能,在中间件范畴,如 JBoss A-MQ中 。顺便提一句,JBoss目前是红帽企业版中间件产品,社区的开源项目叫WildFly。

在以容器为基础的为微服务解决方案中,红帽官网提供了容器化的JBoss A-MQ docker image,可以直接部署在Openshift中。

由于篇幅有限,本文不做试验展示。后续文章会补上。

备注:

什么是2PC?

两阶段提交顾名思义它分成两个阶段,先由一方进行提议(propose)并收集其他节点的反馈(vote),再根据反馈决定提交(commit)或中止(abort)事务。我们将提议的节点称为协调者(coordinator),其他参与决议节点称为参与者(participants, 或cohorts)。

在阶段1中,coordinator发起一个提议,分别问询各participant是否接受。

在阶段2中,coordinator根据participant的反馈,提交或中止事务,如果participant全部同意则提交,只要有一个participant不同意就中止。

参考文献:

http://www.cnblogs.com/ws-astrologer/p/6681089.html https://baike.baidu.com/item/acid/10738?fr=aladdin

http://czmmiao.iteye.com/blog/1967034

http://www.cnblogs.com/bangerlee/p/5268485.html

https://en.wikipedia.org/wiki/Message_broker

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-10-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大魏分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Select For update语句和故事。传统的RDBMS虽然锁特别重,但数据一致性的保护是非常好的。
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档