【分布式】分布式事务原理与实践

原文地址:?spm=5176.100240.searchblog.8.KHdxRg

这里只用于学习和记录。

事务简介

事务的核心是锁和并发,采用同步控制的方式保证并发的情况下性能尽可能高,且容易理解。这种方式的优势是方便理解;它的劣势是性能比较低。

计算机可以简单的理解为一个标准的打字机,尽管看起来计算机可以并行处理很多事情,但实际上每个CPU单位时间内只能做一件事,要么读取数据、要么计算数据、要么写入数据,所有的任务都可以看成这三件事的集合。计算机的这种特性引出了一个问题:当多个人去读、算、写操作时,如果不加访问控制,系统势必会产生冲突。而事务相当于在读、算、写操作之外增加了同步的模块,进而保证只有一个线程进入事务当中,而其他线程不会进入。

单个事务单元

事务的四大特性分别是:原子型、一致性、隔离性和持久性。其中原子性指的是事务中包含的所有操作要么全做,要么全不做;一致性是指在事务开始以前,数据库处于一致性的状态,事务结束后,数据库也必须处于一致性的状态;隔离性要求系统必须保证事务不受其他并发执行的事务的影响;持久性是指一个事务一旦成功完成,它对数据库的改变必须是永久的,即使是在系统遇到故障的情况下也不会丢失,数据的重要性决定了事务的持久性的重要。

  

事务单元是通过Begin-Traction,然后Commit(Begin-Traction、Commit和Rollback之间所有针对数据的写入、读取的操作都应该添加同步访问),Begin和Commit之间就是一个同步的事务单元。例如,Bob给Smith
100块钱就是一个事务单元,这个过程中有很多步操作,具体如上图所示;但对业务来说,仅是一个转账的操作。

一组事务单元

 

当三个账户都在进行转账操作时,每个操作都涉及Smith账户,所有的事务都会排队,形成一组事务单元。

事务单元之间的Happen-Before关系中的四种可能性:读写、写读、读读、写写。所有事务之间的关系都可以抽象成这四种之一,来对应现在所有的业务逻辑处理。在此基础之上,需要用最快的速度处理多个事务单元之间的关系,同时还能保障这四种操作的逻辑顺序。

单个事务单元的其他例子

除了转账操作是事务单元外,诸如商品要建立一个基于GMT_Modified的索引、从数据库中读取一行记录、向数据库中写入一行记录,同时更新这行记录的所有索引、删除整张表等都是一个事务单元。

事务单元的实现方式

 

Two Phase Lock(2PL)是数据库中非常重要的一个概念。数据库操作Insert、Update、Delete都是先读再写的操作,例如Insert操作是先读取数据,读取之后判读数据是否存在,如果不存在,则写入该数据,如果数据存在,则返回错误。假设在该场景下没有读操作,只是单纯写入数据,则数据本身并没有事务操作,Delete、Update操作与之类似。数据库利用这些操作的特性,在每一次查询过程中,只要查到数据,就会在该数据上加锁。理论上,所有被读取的数据都已加锁,不会再被其他人读到,也就是说对数据进行的中间操作状态对所有人都不可见,当所有中间状态完成后,提交操作时,解开锁,此时数据对所有系统可见,例如在转账过程中,所有人只能看到两种状态:开始时,A有钱,B没钱;结束时,B有钱,A没钱,而中间A减掉钱,B尚未加上钱的状态被锁隐藏掉了,这个操作就是数据库中处理事务的最标准的方式。如上图所示:事务中的Trx2(JoeLock)与其他事务不相关,因此可以并行执行;Trx1需要Lock两个数据Boblock和Smithlock,而Trx3同样需要Lock这两个数据,因此Trx3必须等待,且等待在Boblock上;Joe事务会先结束,Trx3会等到Trx1完成后才会开始。

处理事务的常见方法

处理事务的常见方法有排队法、排他锁、读写锁、MVCC等方式,下面来一一解析。

排队法

 

事务处理中最重要也是最简单的方案是排队法,单线程地处理一堆数据。在Redis中,如果数据全部在内存中,则单线程处理所有Put、Get操作效率最高。这是因为多线程本质是CPU模拟多个线程,这种模拟是以上下文切换为代价,而对于内存的数据库来说,没有上下文切换时效率最高。因此,单个CPU绑定一块内存的数据,针对这块数据做多次读写操作时都是在单个CPU上完成的,单线程处理方式在内存的情况是效率是最优的。

那么什么时候事务需要用到多线程呢?这个问题的本质取决于下层所使用的存储,如果是内存操作,则可以动态地申请和销毁内存块;而磁盘的IOPS很低,但吞吐量很高。如果一个场景涉及多次读写操作,单线程可以很高的效率对于内存进行读写操作;但是,由于磁盘的IOPS仅为内存的几千分之一,如果依旧用操作内存的方式操作磁盘,那系统的整体性能将会很低,这意味着必须将大量的读写操作聚合成一个Batch后再提交时才能达到较好的性能。而将大量请求攒到一起的方式一是异步,也就是请求本身和线程不绑定,线程可以不Block(本质来说还是一种多线程的方式),处理完一个线程后再处理其他线程。这种做法的核心是将大量不同的请求提交到一个Buffer中,再由该Buffer统一读取或者写入磁盘,从而提高效率。在慢速设备中,多线程或异步非常常见,在设计系统时,面对磁盘、网络、SSD等慢速设备必须考虑使用多线程。

排他锁

 

有些场景不适合用单线程操作,可以利用排他锁的方式来快速隔离并发读写事务。数据库中有一些事务单元是共享的,如图中的事务单元1是共享的,事务单元2/3共享数据;针对事务单元2/3共享数据的所有读写Block住,事务单元1单独用一个锁来控制,用这种方式完成系统的访问控制。

读写锁

 

如果是一个只读的事务,例如只对数据进行查询操作,在该过程中数据一定不被修改,因此多个查询操作可以并行执行,因此一种针对读读场景的优化自然而然产生——读写锁。读写锁的核心是在多次读的操作中,同时允许多个读者来访问共享资源,提高并发性。

MVCC

 

在最初的数据库事务实现中是不存在MVCC的,它是Oracle在八十年代新加的功能,本质是Copy
On Write,也就是每次写都是以重新开始一个新的版本的方式写入数据,因此,数据库中也就包含了之前的所有版本。在数据读的过程中,先申请一个版本号,如果该版本号小于正在写入的版本号,则数据一定可以查询到,无需等到新版本完全写完即可返回查询结果。这种方式可以在读读不阻塞的前提下,实现读写/写读不阻塞,尽可能保证所有的读操作并行,而写操作串行。

事务的调优原则

事务的调优的思路是在不影响业务应用的前提下:

第一,尽可能减少锁的覆盖范围,例如Myisam表锁到Innodb的行锁就是一个减少锁覆盖范围的过程;对于原位锁(排他锁、读写锁等)可变为MVCC多版本(本质仍然是减少锁的范围)。

第二,增加锁上可并行的线程数,例如读锁和写锁的分离,允许并行读取数据。

第三,选择正确锁类型,其中悲观锁适合并发争抢比较严重的场景;乐观锁适合并发争抢不太严重的场景。

时间: 2024-08-03 22:40:02

【分布式】分布式事务原理与实践的相关文章

阿里沈询:分布式事务原理与实践

直播回顾视频:https://yq.aliyun.com/edu/lesson/play/508 事务简介 事务的核心是锁和并发,采用同步控制的方式保证并发的情况下性能尽可能高,且容易理解.这种方式的优势是方便理解:它的劣势是性能比较低. 计算机可以简单的理解为一个标准的打字机,尽管看起来计算机可以并行处理很多事情,但实际上每个CPU单位时间内只能做一件事,要么读取数据.要么计算数据.要么写入数据,所有的任务都可以看成这三件事的集合.计算机的这种特性引出了一个问题:当多个人去读.算.写操作时,如

C#数据库事务原理及实践(上)

数据|数据库 本文将涉及到在.net框架下使用C#语言操纵数据库事务的各个方面. 体验SQL语言的事务机制 作为大型的企业级数据库,SQL Server2000对事务提供了很好的支持.我们可以使用SQL语句来定义.提交以及回滚一个事务. 如下所示的SQL代码定义了一个事务,并且命名为"MyTransaction"(限于篇幅,本文并不讨论如何编写SQL语言程序,请读者自行参考相关书籍): DECLARE @TranName VARCHAR(20) SELECT @TranName

C#数据库事务原理及实践

数据|数据库 什么是数据库事务 数据库事务是指作为单个逻辑工作单元执行的一系列操作. 设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: · 更新客户所购商品的库存信息 · 保存客户付款信息--可能包括与银行系统的交互 · 生成订单并且保存到数据库中 · 更新用户相关信息,例如购物数量等等 正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新.但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常.该顾客银行帐户存款

C#数据库事务原理及实践(下)

数据|数据库 另一个走向极端的错误 满怀信心的新手们可能为自己所掌握的部分知识陶醉不已,刚接触数据库库事务处理的准开发者们也一样,踌躇满志地准备将事务机制应用到他的数据处理程序的每一个模块每一条语句中去.的确,事务机制看起来是如此的诱人--简洁.美妙而又实用,我当然想用它来避免一切可能出现的错误--我甚至想用事务把我的数据操作从头到尾包裹起来. 看着吧,下面我要从创建一个数据库开始: using System;using System.Data;using System.Data.Sql

大型分布式网站架构设计与实践《概述与大纲》

大型分布式网站架构设计与实践 在大型网站架构的演变过程中,集中式的架构设计出于对系统的可扩展性,可维护性,成本等多方面因素的考虑,逐渐被放弃. 分布式架构的核心思想是采用大量廉价的PC Server ,构建一个低成本,高可用,高可扩展,高吞吐的集群系统,以支撑海量用户的访问和数据存储,理论上具备无限的扩展能力. 分布式系统的设计,是一门复杂的学问,它设计通讯协议,远程调用,服务治理,系统安全,存储,搜索,监控,稳定性保障,性能优化,数据分析,数据挖掘等各个领域. 对任何一个领域的深入挖掘,都能写

Oozie分布式工作流——从理论和实践分析使用节点间的参数传递

Oozie支持Java Action,因此可以自定义很多的功能.本篇就从理论和实践两方面介绍下Java Action的妙用,另外还涉及到oozie中action之间的参数传递. 本文大致分为以下几个部分: Java Action教程文档 自定义Java Action实践 从源码的角度讲解Java Action与Shell Action的参数传递. 如果你即将或者想要使用oozie,那么本篇的文章将会为你提供很多参考的价值. Java Action文档 java action会自动执行提供的jav

RocketMQ的原理与实践

备注: 1.如果您此前未接触过RocketMQ,请先阅读附录部分,以便了解RocketMQ的整体架构和相关术语 2.文中的MQServer与Broker表示同一概念 分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一款高性能.高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的? 关键特性以及其实现

深入解析SQL Server并行执行原理及实践(下)

谈完并行执行的原理,咱们再来谈谈优化,到底并行执行能给我们带来哪些好处,我们又应该注意什么呢,下面展开.   Amdahl's  Law    再谈并行优化前我想有必要谈谈阿姆达尔定律,可惜老爷子去年已经驾鹤先去了.     其中  P:可以并行的百分比 N:算法并行计算使用的"CPU"    这里我们举个简单的例子,我们来做一份大餐,如图1-1所示:   图1-1   土豆泥,荷兰豆,鸡排还有整体组合各需十分钟.在这里前三个食材是可以共同执行的,也就是说4个步骤中3步可并行 P=3/

《 C++程序设计:原理与实践(进阶篇.》导读

本节书摘来自华章出版社< C++程序设计:原理与实践(进阶篇)>一书中作者[美] 本贾尼·斯特劳斯特鲁普(Bjarne Stroustrup) 著 刘晓光 李忠伟 王刚 译     前 言 Programming: Principles and Practice Using C++, Second Edition 该死的鱼雷!全速前进. --Admiral Farragut 程序设计是这样一门艺术,它将问题求解方案描述成计算机可以执行的形式.程序设计中很多工作都花费在寻找求解方案以及对其求精上