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

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

原文发布于微信公众号 - 大魏分享(david-share)

原文发表时间:2017-10-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端技术探索

Nginx从听说到学会(1.简介和对比)

没有听过Nginx?那么一定听过它的“同行”Apache吧!Nginx同Apache一样都是一种WEB服务器。基于REST架构风格,以统一资源描述符(Unifo...

953
来自专栏hotqin888的专栏

电子规范管理系统(2)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hotqin888/article/det...

1651
来自专栏FreeBuf

更适合作为主系统使用的Parrot Security简介

Parrot 是一个基于Debian的专注于渗透测试和隐私保护的Linux发行版,但是更加方便日常使用,有贴心的使用体验,丰富的工具,更注重隐私保护。 The...

8515
来自专栏大宽宽的碎碎念

数据库事务、隔离级别和锁ACID的真实含义隔离级别和并发控制MySQL和PostgreSQL对比如何写代码

57412
来自专栏北京马哥教育

推荐!国外程序员整理的系统管理员资源大全(一)

备份软件 Amanda -客户端-服务器模型备份工具 Bacula - 另一个客户端-服务器模型备份工具 Backupninja -轻量级,可扩展的元数据备份系...

50510
来自专栏数据和云

122Architecture 全面解读 - 第一篇 全局解析+ADG+IM模块

Oracle自发布12.1之后,就一直声称要全面转云,在之后的三四年里,一直杳无音信,大家都在猜测,Oracle又在憋什么大招,果然,2017阳春三月,大招来了...

3759
来自专栏农夫安全

运维的福利,黑客的噩梦

CYWL_Team服务器防御工具1.0 0x01开发前言 很多小黑都希望搭建自己的博客,论坛,来记录自己在安全之路上面的点点滴滴,不过总是被一些大牛来进行恶搞,...

3878
来自专栏MongoDB中文社区

9月.精华文章推荐

1.《GDPR: Impact to Your Data Management Landscape:Part 3 》

1202
来自专栏杨建荣的学习笔记

DBA和开发同事的一些代沟(五) (r7笔记第92天)

陆陆续续写了四篇和开发同事的代沟,从最开始的吐槽到后面的例行总结,整个过程也是总结经验,看似很小的问题对于DBA来说就是莫大的改进,或者在开发严重越不过去的坎儿...

39310
来自专栏FreeBuf

浅谈开源web程序后台的安全性

一、前言 不知怎的最近甚是思念校园生活,思念食堂的炒饭。那时会去各种安全bbs上刷刷帖子,喜欢看别人写的一些关于安全技巧或经验的总结;那时BBS上很多文...

2079

扫码关注云+社区

领取腾讯云代金券