最佳实践7| SequoiaDB巨杉数据库跨引擎事务

01 前言

 

在最佳实践系列第六篇中,我们利用多副本,实现了OLTP、OLAP的负载隔离。那么,单就OLTP系统而言,能否实现跨引擎事务功能呢?比如我们有2套应用系统,一套基于MySQL开发,一套基于PosgreSQL开发,两个应用系统能否灵活地实现数据互相访问,并且实现事务隔离?

在以往,这是不可能完成的。如果非要这样做,则需要将其中一套数据库,进行异构数据迁移,应用程序要做改造(SQL语句、存储过程等)。为了改造后达到兼容,还伴有大量的功能测试、性能测试,这样庞大的工作量,往往令人望而却步,转而走向业务的重新开发。

如果现在有这样一种技术,能让你在一个数据库里实现2种SQL引擎的访问,更为不可思议的是,不同的SQL引擎还可以实现事务,并支持4种事务隔离级别,你会相信么?

是的,您没有听错,巨杉数据库SequoiaDB的跨引擎事务特性,将这个需求的实现变成了可能。本文将进行讲解,便于您充分了解该技术特性,进而把它运用到适合的业务场景中,如微服务改造等。 

 

 

02 背景

 

目前,市面上主流的数据库,基本上都支持事务功能,网上也有很多技术资料,介绍数据库的事务功能及原理。

跨引擎事务则是一种新兴的技术概念。在这种技术下,同一个数据库,可以被不同的SQL引擎(如MySQL、PostgreSQL)访问,并且提供多种隔离级别、并发控制机制,实现事务的ACID。

目前,随着微服务架构的火热,各个应用系统都运行在相对独立的微服务中。这些服务是围绕业务功能构建的,因此,在软件开发阶段,软件厂商更倾向于采用自己惯用的SQL引擎。长此以往,就出现了多种数据库形态,如MySQL、PostgreSQL等,这导致不同的业务系统之间,不能够灵活的互相访问和数据共享。

巨杉数据库SequoiaDB,是一款多引擎数据库,提供一个统一的存储引擎作为底座,上层提供多种SQL引擎,如MySQL、PostgreSQL等,对数据进行访问。同时,为了支持更复杂的业务场景,提供了多种事务隔离级别。

结合巨杉数据库的高并发、在线弹性伸缩、海量数据存储等优势,可以很好地解决微服务架构下的数据碎片化、性能瓶颈和弹性扩张等问题。

 

 

03 SequoiaDB巨杉数据库跨引擎事务

 

3.1 并发事务的数据读取

在对数据库系统进行并发访问时,可能会出现几种情况:

1、 脏读

某事务,读取到了脏数据(正在被其它事务操作,但未提交的数据)。换句话说,数据查询结果,受到其他事务对数据的操作所影响,比如增、删、改等,尽管这些操作尚未提交。试想,一旦这些操作回滚,意味着读取到了无效数据。

例:情人节,小王的给他爱人转账520元(未提交),以表心意。小王老婆打开了账上银行APP,发现收到了520元的转账,喜笑颜开。但是,不料,小王提交转账订单时,网络中断,交易异常终止,转账操作被后台回滚,导致小王老婆空欢喜一场。在真实的业务场景中,在转账事务确认完成前,其他事务不应当感知到未提交的数据操作带来的影响,否则就会读取到无效数据,像本例中小王爱人收到的转账,就是无效数据。

为了避免这种情况,就需要读已提交隔离级别(Read-Committed)。

2、 不可重复读

一个事务中,对于相同的数据集,多次读取但得到的结果不一致(事务内,同一行数据多次查询不一致,因为被更新)。例:情人节,小王打算给老婆转520元,以表心意。他打开掌上银行APP,查询余额,发现账上还有1000元,因此发起转账,但操作时,APP却提醒他,余额不足,卡上只有400元。小王纳闷了,明明刚才还显示1000元,怎么余额不足了呢?打开账单明细发现,原来,不巧就在刚刚查询后到发起转账的短短的几秒钟,自动扣除了600元的自动还款,因时余额已经不足够完成此次的转账。

这就是一个不可重复读的例子。为了避免这种情况,就需要可重复读隔离级别(Read-Repeatable)。

3、 幻读

同一个事务中,多次查询返回的结果集数目不一致。例如:事务A新增了一条记录,事务B在事务A提交前、后读到的结果可能不一致,提交后多查到一条,就好像“幻象”一样,多出来一条记录。幻读是由其他事务插入(或删除)导致的。因为新增数据无法加行锁,所以无法通过MVCC或者锁表来解决幻读。

需要强调一下,不可重复度和幻读,描述有些相似,都是指在同一个事务中,对多次查询可能得不到一致的结果。区别是:不可重复读,主要是针对数据更新,幻读主要是针对数据结果集的变化,如增加、删除等。

 

3.2 事务隔离级别

在实际的业务系统中,不同的业务,对于事务并发访问的要求不同。为了达到其业务目的,避免上述的一种或多种问题,通常的做法,就是设置事务隔离级别。

巨杉分布式数据库SequoiaDB,提供了四种事务隔离级别。每种隔离级别,与其对应的并发问题处理能力如下:

隔离级别

脏读

不可重复度

幻读

读未提交 RU

可能

可能

可能

读已提交 RC

不可能

可能

可能

读稳定性 RS

不可能

不可能

可能

可重复读 RR

不可能

不可能

不可能

1. 读未提交(Read Uncommitted,简称RU):一个事务,能够访问到其他事务未提交的数据,这是最低隔离级别。在这种隔离级别下,上述所有的问题都会发生,如脏读、不可重复读、幻读。

2. 读已提交(Read Committed,简称RC):事务只会读取每条数据最新被提交的状态,从而避免了脏读。但是,无法保证事务中多次查询数据得到一致的结果,也就是说,仍无法避免不可重复读、幻读的发生。

3. 读稳定性(Read Stability,简称RS):事务中对同一份数据的多次读取,其结果与事务中首次读取到的数据一致,在该事务结束前,该查询结果保持不变。因此,在RC的基础上,进一步避免了不可重复读。

4. 可重复读(Repeatable Read,简称RR):事务中对同一份数据的多次读取,其结果与事务中首次读取到的数据一致,在该事务结束前,该查询结果保持不变。且符合查询条件的结果集记录数,也不会因为其他事务对数据的操作而改变。在该隔离级别下,脏读、不可重复读、幻读的问题都得到了避免。

Note: 

还有一种隔离级别经常被提到,那就是串行化读(Serialization)。这是一种十分严苛的隔离级别,解决了所有并发问题,如脏读、不可重复读、幻读等。但在实际业务系统中,这种隔离级别采用得很少,因为它要求事务必须串行化执行,不允许事务并发,这样等同于完全牺牲了系统的并发能力。

从以上可以看出,巨杉提供的四种隔离级别中,可重复读(RR)隔离级别最高:

  • 本身已包含读已提交(RC),避免了脏读;

  • 当事务对数据进行首次读取时,其查询结果已经被确定,在该事务结束前查询到的结果,不会因其他事务对数据的修改而改变,避免了不可重复读;

  • 不会因为其他事务对数据的新增和插入,而改变结果集的记录个数,避免了幻读。

 

3.3 SequoiaDB 跨引擎事务

巨杉数据库SequoiaDB,作为分布式数据库,将数据分布在多台服务器中的数据节点中。

  • 由SequoiaDB分布式存储引擎和SQL实例构成,底层的存储引擎提供统一的数据存储,上层的SQL实例只完成SQL语法的解析;

  • 由底层的SequoiaDB分布式存储引擎实现事务的并发控制,如事务隔离、锁机制等;

  • 通过二阶段提交协议实现分布式事务,支持跨表跨节点的事务原子操作;

  • 只需要适配对应SQL引擎的语法,即可达到跨引擎事务的效果。

SequoiaDB 巨杉数据库的可重复读级别(Repeatable Read,以下简称RR),通过多版本并发控制(MVCC,Multi-Version Convurrency Control)来实现。MVCC 是一种数据库常用的数据库并发控制机制,通过保存数据在某个事务时间点的快照来进行事务隔离控制。

RR级别使用STP(时间序列协议,Serial Time Protocol),为分布式事务分配全局时间,并使用全局事务一致性的仲裁机制,对分布式事务实现了因果排序,再结合 MVCC 的可见性算法,从而实现了分布式事务的全局一致性(可参考 时间序列服务)。

下文中,我们通过实验,来验证SequoiaDB的事务隔离级别,在并发场景中的表现。

 

04 分布式数据库HTAP最佳实践

 

4.1 环境描述

巨杉分布式数据库SequoiaDB,能够提供RU、RC、RS、RR四种隔离级别。RR是SequoiaDB提供的4种隔离级别中,最严格的一种,而且这也是MySQL的默认级别。

传统的关系型数据库,一般都只能实现RC级别。

因此,下文以RR、RC隔离级别来测试事务的隔离性。其他隔离级别的测试流程类似。

内容

隔离级别

RR、RC

SQL引擎

MySQL、PostgreSQL

测试项

RC:脏读

RR:脏读、不可重复读、幻读

本文中,采用了2个SQL实例,一个MySQL实例,一个PostgreSQL实例,底层使用一个统一的巨杉分布式存储引擎。

 

4.2. 参数设置

在SequoiaDB中,为了实现RR级别,需要通过数据库参数,开启全局事务和MVCC。此外,还需要时间序列服务(STP)的支持。

1. SequoiaDB数据库参数设置:​​​​​​​

//开启全局事务db.updateConf( { globtranson:true } );
//开启MVCC(需重启数据节点)db.updateConf( { mvccon:1 } );

2. 查看参数设置

db.snapshot(SDB_SNAP_CONFIGS, { Role: "data" }, { NodeName: "", transisolation: "" ,transactionon: "",globtranson:"",mvccon: "" });

参数解释:

Transisolation表示在开启事务的情况下,使用的事务隔离级别。

0:表示 RU, 

1:表示 RC, 

2:表示 RS, 

3:表示 RR。

3. 开启并检查STP服务​​​​​​​

//开启全局事务stpstartsdblist -t all -l |grep stp

4. 为了便于演示,本实验环境关闭了SQL客户端的自动提交​​​​​​​

//MySQLset  AUTOCOMMIT=off//PostgreSQL\set AUTOCOMMIT off

 

4.3. 测试数据准备

1. 登陆MySQL实例,创建bills数据库,创建一张orders表。​​​​​​​

$ 登陆mysql实例mysql -uroot  -proot -h 127.0.0.1 -P 3306
//创建databasecreate database bills;use bills;
//创建orders表create table bills.orders ( order_id int, p_date date, location varchar(100) , primary key (order_id));

 2. 向bills.orders表中插入4条记录,并查询​​​​​​​

insert into bills.orders values(10001,'2017-06-01','Beijing');insert into bills.orders values(10002,'2018-06-01','Shanghai' );insert into bills.orders values(10003,'2019-06-01','Guangzhou' );insert into bills.orders values(10004,'2020-06-01','Shenzhen' );commit;select * from orders;

 3. 登陆PostgreSQL实例、创建bills数据库​​​​​​​

$ psql -p 5432create database bills;\c bills

4. 创建SequoiaDB的连接器sdb_server和外部表orders,其中连接器默认开启事务​​​​​​​

# 加载 SequoiaDB 连接驱动create extension sdb_fdw;
# 创建sdb_server连接器create server sdb_server foreign data wrapper sdb_fdw options(address 'localhost', service '11810', transaction 'on');
# 创建外部表order外表create foreign table orders (  order_id int,  p_date date,  location varchar(100))server sdb_server options ( collectionspace 'bills', collection 'orders', decimal 'on' ) ;

 5. 数据查询验证

在PostgreSQL中查询orders表的数据。

select * from orders;

结果显示,PostgreSQL中的数据,与MySQL中插入的数据一致,说明数据正确,PostgreSQL和MySQL使用相同的数据源。

 

4.4. 测试过程

4.4.1. RR模式测试

1. 设置SequoiaDB存储引擎事务隔离级别为RR

db.updateConf( { transisolation:3 } )

2. 修改MySQL的事务隔离级别(下一个事务开始生效)。

注:虽然在事务隔离级别SequoiaDB存储引擎中已经设置,但MySQL实例中仍需设置。PostgreSQL中因为使用了外部表,因此无需设置。​​​​​​​

//MySQL中设置事务隔离级别为RRset transaction_isolation='REPEATABLE-READ';
//查询select @@tx_isolation;

3. 在MySQL会话中开启事务,将order_id=10001的订单数据的location字段,由’Beijing’修改为’Nanjing’,暂不提交。​​​​​​​

begin;update   orders set location='Nanjing'  where  order_id=10001;

4. 在PostgreSQL会话中开启事务,查询数据。​​​​​​​

begin;select * from orders;

可以看到,在MySQL中未提交的数据,在PostgreSQL中查询不到。说明未发生脏读。

5. 在MySQL会话中,将会话提交。

commit;

6. 在PostgreSQL中,再次查询数据。

select * from orders;

可以看到,即便MySQL中已将update操作提交,但在PostgreSQL中,查到的数据,仍然是事务中首次查询时的状态。说明未发生不可重复读。

7. 在MySQL会话中执行insert操作,插入一条order_id为10005的订单数据,并提交。​​​​​​​

insert into bills.orders values(10005,'2021-01-01','Hangzhou' );commit;select * from orders;

8. 在PostgreSQL会话中,再次查询

select * from orders;

可以看到,即便MySQL中插入了一条数据,且已提交,但在PostgreSQL中,查到的数据,仍然是事务中首次读取的状态,结果集的数量也没有发生改变。说明未发生幻读。

通过上述步骤可以验证,由两个不同SQL引擎发起的事务,能够达到RR(可重复读)隔离级别,避免了脏读、不可重复读、幻读的情况。

4.4.2. RC模式测试

1. 在MySQL中,将测试数据初始化​​​​​​​

delete from orders;insert into bills.orders values(10001,'2017-06-01','Beijing');insert into bills.orders values(10002,'2018-06-01','Shanghai' );insert into bills.orders values(10003,'2019-06-01','Guangzhou' );insert into bills.orders values(10004,'2020-06-01','Shenzhen' );commit;select * from orders;

2. 设置SequoiaDB存储引擎的事务隔离级别为RC。

db.updateConf( { transisolation:1 } )

3. 设置MySQL的事务隔离级别为RC(下一个事务开始)。​​​​​​​

set transaction_isolation='READ-COMMITTED';select @@tx_isolation;

4.在MySQL会话中开启事务,将order_id=10001的记录的location字段由’Beijing’修改为’Nanjing’,暂不提交;​​​​​​​

begin;update   orders set location='Nanjing'  where  order_id=10001;select * from orders;

5. 在PostgreSQL会话中结束刚才的事务,并开启新的事务,查询数据。​​​​​​​

rollback;begin;select * from orders;

可以看到,在MySQL中未提交的数据,在PostgreSQL中查询不到。说明未发生脏读。

6. 在MySQL会话中,将会话提交。

commit;

 7. 在PostgreSQL中,再次查询数据。

select * from orders;

可以看到,MySQL中将update操作提交后,在PostgreSQL中,可以查询到提交后的数据。说明实现了RC(读已提交)隔离级别。

 

 

05 总结

 

在本文中,我们为大家介绍了SequoiaDB巨杉数据库的事务隔离级别,以及每种事务隔离级别,对应的并发问题处理能力。SequoiaDB支持RU、RC、RS、RR四种事务隔离级别,本文重点对的RR、RC级别,进行了验证。

通过验证,SequoiaDB的RR级别,能够避免脏读、不可重复读、幻读等数据可见性问题;RC级别,能够避免脏读问题。其他的隔离级别,读者朋友们有兴趣的话可以自行验证一下~

另外,我们将在近期推出《SequoiaDB数据库HDD/SSD混合部署最佳实践》,请期待!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值