当前位置:   article > 正文

OceanBase简介及其与MySQL的比较

oceanbase

概述
OceanBase是阿里巴巴和蚂蚁金服完全自主研发的通用的分布式关系型数据库,定位为商用企业级数据库。OceanBase能提供金融级别的可靠性,目前主要应用用于金融行业,同时也适用于非金融行业场景。它融合传统关系数据库和分布式系统的优势,利用普通的PC服务器组成数据库集群,拥有出色的线性扩展性。

通过在底层分布式引擎实现的Paxos多数派协议和多副本特性,OceanBase拥有了令人称道的高可用和容灾能力,不负“永不停机”的数据库系统的盛名,可以完美支持多地多活、异地容灾等高可用部署。

OceanBase是一个准内存数据库系统,独有的读写分离架构和面向SSD固态盘的高效存储引擎,为用户带来了超高性能的体验。

OceanBase定位为云数据库,通过在数据库内部实现多租户隔离,实现一个集群可以服 务多个租户,且租户之间完全隔离,不会相互影响。

OceanBase目前完全兼容MySQL,用户可以零成本从 MySQL 迁移到OceanBase。同时OceanBase在数据库内部实现了分区表和二级分区功能,可以完全取代MySQL常用的分库分表方案。

OceanBase的存储引擎
OceanBase本质上是一个基线加增量的存储引擎,跟关系数据库差别很大。 存储机制是LSM树(Log-Structured Merge Tree,日志结构合并树),这也是大多数NoSQL使用的存储机制。OceanBase采用了一种读写分离的架构,把数据分为基线数据和增量数据,其中增量数据放在内存里(MemTable),基线数据放在SSD盘(SSTable)。虽然不是刻意设计的,但OceanBase确实比传统数据库更适合像双十一、秒杀以及优惠券销售等短时间突发大流量的场景:

短时间内大量用户涌入,短时间内业务流量非常大,数据库系统压力非常大
一段时间(几秒钟、几分钟、或半个小时等)后业务流量迅速或明显回落
OceanBase是“基线数据(硬盘)”+“修改增量(内存)”的架构,如下图所示。


整个数据库以硬盘(通常是SSD)为载体,对数据的修改都是增量数据,只写内存,新近的增、删、改数据(修改增量)在内存,所以DML是完全的内存操作,性能非常高。而基线数据在保存在硬盘上,因此OceanBase可以看成一个准内存数据库。这样做的好处有:

 

写事务在内存(除事务日志必须落盘外),性能大大提升。
没有随机写硬盘,硬盘随机读不受干扰,高峰期系统性能提升明显;对于传统数据库,业务高峰期通常也是大量随机写盘(刷脏页)的高峰期,大量随机写盘消耗了大量的IO,特别是考虑到SSD的写入放大,对于读写性能都有较大的影响。
基线数据只读,缓存(cache)简单且效果提升。
读数据的时候,数据可能会在内存里有更新过的版本,在持久化存储里有基线版本,需要把两个版本进行合并,获得一个最新版本。同时在内存实现了Block Cache和Row cache,来避免对基线数据的随机读。当内存的增量数据达到一定规模的时候,会触发增量数据和基线数据的合并,把增量数据落盘(称为转储,又叫minor freeze)。同时每天晚上的空闲时刻,系统也会自动每日合并(简称合并,major freeze)。

OB为何采用这种特殊架构,简要来说,就是基于这样一条理论基础——尽管数据库本身的数据量越来越大,记录数越来越多,但每天的增删改数据量并不大,仅仅只占数据库总量一个很小的比例。 这个情况不只是对支付宝的支付数据,对其它大部分数据库实际应用情况也适用,是OB建立上述存储引擎的重要理论基础。


Log-Structured Merge-Tree (LSM-Tree),log-structured,日志结构的,只需要不断地Append就好了。“Merge-tree”,也就是“合并-树”,把多个文件合并成一个。LSM-tree 最大的特点就是写入速度快,主要利用了磁盘的顺序写。LSM树存储引擎和B树存储引擎一样,同样支持增、删、读、改、顺序扫描操作,而且通过批量存储技术规避磁盘随机写入问题。当然凡事有利有弊,LSM树和B+树相比,LSM树牺牲了部分读性能,用来大幅提高写性能。

 


LSM树的设计思想非常朴素:将对数据的修改增量保持在内存中,等到积累到指定大小后,再使用归并排序的方式将内存内的数据合并追加到磁盘队尾(因为所有待排序的树都是有序的,可以通过合并排序的方式快速合并到一起)。不过读取的时候稍微麻烦,需要合并磁盘中历史数据和内存中最近修改操作,所以写入性能大大提升,读取时可能需要先看是否命中内存,否则需要访问较多的磁盘文件。

 

日志结构的存储引擎是一个相对较新的方案,其关键思想是系统地将磁盘上的随机写入转为顺序写入,由于硬盘的性能特性,写性能比B-Tree存储引擎高数倍,读性能反之。B树把所有的压力都放到了写操作的时候,从根节点索引到数据存储的位置,可能需要多次读文件;真正插入的时候,又可能会引起page的分裂,多次写文件。而LSM树在插入的时候,直接写入内存,只要利用红黑树或跳表等有序数据结构保持内存中的数据有序即可,所以可以提供更高的写吞吐。LSM树的基本思想足够简单有效,可以有效地支持区间查询,支持非常高的写入吞吐量。但当LSM-Tree查找某个数据库中不存在的key时,需要检查索引及所有的段文件,为了优化这种情况,存储引擎通常会使用布隆过滤器。

OceanBase如何保证写的原子性
分布式数据库技术具体难在哪里呢?简单说,要想账头一分钱都不错,数据库要支持事务,事务拥有ACID原则,这四个字母分别代表:A原子性、C一致性、I隔离性、D持久性。

原子性:表示事务中的多个操作要么全部完成,要么全部失败,不会出现中间状态,例如A转给B100块钱,A账户扣除100块的同时,B账户必须增加100块钱。这两件事必须像一个原子一样紧紧抱在一起,决不允许“A已经扣钱,B还没加钱”的事情发生。
一致性:A转给B100块钱,转账完成的一瞬间,A瞬间再查询自己的最新余额,必须显示已经扣除100之后的金额,B必须瞬间查到已经加上100块之后的余额。所有的账目在任何一个时间切面必须完完全全对得上。
隔离性:表示多个并发事务之间不互相影响,A转给B100块钱,不能对C有任何影响。
持久性:表示事务一旦成功就不会丢失,A转给B100块钱,这笔转账一旦完成,就永远生效。
其中一致性是目的,原子性隔离性和持久化是手段,只要做好ACID中的AID,C自然就能满足。

由于数据散落在多台数据库服务器上,库作了拆分。分布式写最大的难度其实就在于保证ACID中的那个A——原子性。

举个例子,假设A给B转100块钱,由于是“分布式数据库”,A用户的账户数据存在A机器上,B用户的账户数据存在B机器上。

如果交易发生时,负责给A账户扣100块钱的A机器死机,没有扣成功,而负责给账户B加100块钱的B机器工作正常,加上了100——这就会造成支付宝损失100块。

 

反之,如果负责给A账户扣100块钱的A机器正常,已经扣掉100,而负责给账户B加100块钱的B机器死机,100块没加上,那么用户就会损失100——最后支付宝还要赔偿用户100块。


为了保证以上这两种尴尬的局面不发生,OceanBase 1.0采用了整整一组技术,但最主要的是两个。

 

投票机制
数据库采用“三副本”,也就是任何一个账户,都有一个主咖两个备胎共三份相同的数据。

举例来说:账户A的数据一定同时存在三台机器上。转账时,至少两台机器执行完毕才算转账完成,这意味着,三台机器里有一台坏掉,并不影响转账的执行。同时,三台机器之间相互实时发送“心跳信号”,如果有一台机器挂了,其他两台马上就能感觉到,处理完手头这个交易后,马上向系统发送警报,系统自动为他俩匹配一个新搭档,三台机器继续工作。而换下来那个坏机器,交给技术人员维修,修好后重新上架成为备用机器,等待进入战斗序列。

也就是说,除非两台机器在同年同月同日同分同秒同毫秒坏掉,否则数据库的工作不受影响。


即使是这还不够,在关键的节点,OceanBase 会采用五个节点投票。也就是除非三台机器在同年同月同日同分同秒同毫秒坏掉,否则数据库的工作不受影响,这个概率已经低到尘土里了。

 

 


OceanBase在存储层,通过分区级Paxos日志同步实现高可用和自动扩展,支持灵活的存储架构,包括本地存储,以及存储计算分离。经典集中式数据库往往采用主备同步方案,有两种同步模式:第一种是强同步,每个事务操作都需要强同步到备机才可以应答用户,这种方式能够做到服务器故障不丢数据,但必须停服务,无法保证可用性;另外一种是异步,每个事务操作只需要在主机成功就可以应答用户,这种方式能够做到高可用,但主库和备库之间数据不一致,备库切换为主库之后会丢数据。


强一致和高可用作为数据库最重要的两个特性,在主备同步模式下,鱼和熊掌不可兼得。Paxos是一种基于多数派的分布式投票协议,每个事务需要成功写入超过一半服务器才可以应答用户。俗话说得好,“三个臭皮匠顶过一个诸葛亮”,假设总共有3台服务器,每个事务操作要求至少在2台服务器上成功,无论任何一台服务器发生故障,系统中还有1台包含了全部数据的服务器能够正常工作,从而做到完全不丢数据,并在30秒之内选出新的主库恢复服务,RPO等于0,RTO小于 30秒。所有保证RPO=0的协议都是Paxos协议或者Paxos协议的变种,Raft协议就是其中之一。

 

监督机制
监督机制其实是对两阶段提交协议(2PC)的实践,仔细想想,除了机器坏掉,还有一些情况会破坏交易的原子性。

例如:A账户要扣掉100块,但是它的余额只有90块,或者已经达到了今天的转账限额,这种情况下,如果贸然给B账户加了100块,A账户却不够扣,就会陷入麻烦了。

反之如果B账户状态有异常,不能加100块,同样会有麻烦。解决这个问题的方法,就是引入一位“裁判员”。裁判员站在A账户和B账户旁边,它的工作流程是这样的:

裁判员问A账户:你的三台机器都没问题吧?A账户说:没问题。
裁判员问A账户:你的账户允许扣100吗?A账户说:允许。
裁判员问B账户:你的三台机器都没问题吧?B账户说:没问题。
裁判员问B账户:你的账户状态能接受加100吗?B说:允许。
这时,裁判员吹哨,A、B账户同时冻结。
A扣100,B加100,双方向裁判汇报“成功”。
裁判员再吹哨,A、B账户同时解冻。
以上7步,都是按时间顺序完成的,卡在任何一步,账目都不会乱,一分钱都不会丢。完全符合“原子化”的要求。


裁判员充当2PC中的协调器角色。

 

OceanBase如何保证事务的隔离性
数据库系统不能只服务一个用户,需要允许多个用户同时操作数据,即并发。所以需要保证多个并发事务的隔离,这里涉及到并发控制技术,常见的并发控制方法有基于锁的并发控制(Lock based Concurrency Controll)和多版本并发控制(Multiple version Concurrency Controll)

基于锁的并发控制
数据库系统对用户在事务过程中操作的每一行数据都加锁,读操作加读锁,写操作加写锁。读写阻塞,写写阻塞。如果两个不同的事务试图修改同一行数据,事务1先加上写锁正常执行,事务2就只能阻塞等待,当事务1执行结束释放写锁后,事务2再继续执行。

以转账操作为例,A账户有100元,B账户有200元,如果事务1执行从A账户转10元到B账户,那么在事务1执行过程中,A B两行账户数据都会被加上写锁。如果事务2执行另一次转账操作,从A账户转50元到B账户,那么给A加写锁时失败,事务2会一直等待直到加写锁成功为止。

如果在事务1与事务2的执行过程中,又来一个事务3想要查询A B两个账户的余额总和,那么需要读取A、B两行,读之前要先加读锁,但是在事务1和事务2操作时,读锁加不成功,那么事务3就需要等待事务1和事务2都结束了才能执行。

多版本的并发控制
在上面例子中,一个读取A、B两账户余额总和的操作,无论事务1和事务2是否执行完成,其结果都是确定的(300元)。但基于锁的并发控制,读写是阻塞的,极大的降低了数据库的并发性能,所以出现了MVCC的方法来做并发控制。对于数据库的数据,每次修改都保留历史版本,这样读操作可以直接在历史版本上执行,不会被写操作阻塞。

在MVCC方法下,每一个事务都会有一个提交版本,继续上面事务三的例子。假设数据的初始版本是98,假定事务1是的版本号100,事务2是101。那么修改都完成后,数据库中的数据状态如下:


每次数据修改的记录都会被串联起来。另有一个全局变量Global Committed Version(GCV) 标示全局最后提交的版本号。在事务1执行之前GCV是98,事务1提交之后GCV变成100,事务二提交之后GCV变成101。所以,当事务3开始执行时,先获取GCV,然后根据这个版本号去读相应的数据。

 

MVCC的修改操作依然会依赖上面提到的锁机制,所以写操作之间的冲突依然需要等待。但是MVCC最大的优势就是读操作与写操作完全隔离开,互相不影响,对于数据库的性能和并发能力提升非常有益。

OceanBase使用的方案
使用MVCC方案时GCV的修改需要依次递增,如果GCV被修改成了101,表示101及之前的所有事务都提交了。OceanBase使用了分布式事务后,这个保证变得困难,例如,版本号为100的事务可能是分布式事务,101可能是单机事务,分布式事务的提交过程要显著长于单机事务。结果,版本号101的事务先完成,GCV就被修改成了101。但是此时版本号为100事务还在提交过程中,并不能被读取。

所以,OceanBase采用了MVCC和Lock-based结合的方式,读取操作先获取GCV,然后按照这个版本号读取每一行数据。如果这行数据上没有修改,或者有修改但是修改的版本号会大于GCV,那么这行数据可以直接按照版本号读取。如果这行数据上有一个正在提交中事务,并且版本号有可能小于读取使用的版本号,那么读取操作就需要等待这个事务结束,就好像Lock-based方案中读锁等待写锁一样。但是,这个发生的概率极低,所以整体的性能还是像MVCC一样好。

OceanBase的高可用
高可用是数据库的基本需求之一,传统数据库允许通过日志同步实现主备镜像;然而,由于主备镜像中主库与备库无法完全同步,因此传统数据库的高可用其实是建立在传统的高可靠服务器和高可靠共享存储之上的。

OceanBase同样使用性价比较高、可靠性略低的服务器,但同一数据保存在多台(>=3)服务器中的半数以上服务器上(例如3台中的2台,5台中的3台等),每一笔写事务也必须到达半数以上服务器才生效,因此当少数服务器故障时不会有任何数据丢失。不仅如此,传统数据库主备镜像在主库发生故障时,通常需要外部工具或人工把备库升级成主库,而OceanBase底层实现了Paxos高可用协议,在主库故障后,剩余的服务器会很快自动选举出新的主库,并继续提供服务,OceanBase数据库能做到自动切换且完全不丢数据。

OceanBase与MySQL的比较
1、 OB的redo log是使用分布式一致性算法Paxos实现的。所以在CAP理论中,虽然OB使用的是强一致模型,但是OB能在一定网络分区的情况下做到高可用(通俗点讲就是多余半数机器还活着的时候就能干活),官方的MySQL目前做不到这一点。

2、OB的存储结构使用的是两级的LSM tree。其中内存中的C0 Btree叶节点不需要和磁盘上的btree一样大小,所以能做得比较小,对CPU的Cache比较友好,并且不会有写入放大的问题。使得OB的写性能有极大的提升。同时磁盘上的C1 tree不是一个传统意义上的Btree(Btree未经压缩可能浪费一半空间)。空间利用率大大提高。简单来说就是速度快,省成本。

3、 数据库自动分片功能(支持hash/range,一级二级等等分片方式),提供独立的proxy路由写入查询等操作到对应的分片。这意味着数据量再大也不需要手动分库分表了。并且分片能在线的在各个server之间迁移,解决热点问题(资源分配不均的问题,做到弹性加机器和减机器)。每个分片(确切的说是被选为主的分片)都支持读写,做到多点写入(高吞吐量,性能可线性扩展)。

4、数据库内部实现的无阻塞的两阶段提交(跨机事务)。

5、数据库原生的多租户支持,能直接隔离租户之间的cpu、mem、io等资源。

6、高可用,对OceanBase而言,同一数据保存在多台(>=3)台服务器中的半数以上服务器上(例如3台中的2台),每一笔写事务也必须到达半数以上服务器才生效,因此当少数服务器故障时不会有任何数据丢失,能够做到RPO等于零。不仅如此,OceanBase底层实现的Paxos高可用协议,在主库故障后,剩余的服务器会很快自动选举出新的主库,实现自动切换,并继续提供服务,在实际的生产系统中做到RTO在20秒之内。


7、扩展能力。MySQL在数据库中间件的帮助下,可以通过分库分表来实现水平扩展。这种方案解决了传统数据库需要垂直扩展的通病,但还是存在相当的局限性,比如扩容和缩容困难、无法支持全局索引,数据一致性难以保证等。OceanBase则从数据库层面提供了真正意义上的水平扩展能力。OceanBase基于分布式系统实现,可以很方便地进行扩容和缩容,且能做到用户无感知。同时,OceanBase所具备的集群内动态负载均衡、多机分布式查询、全局索引的能力更进一步加强了其可扩展性。对于用户的分库分表方案,OceanBase提供了分区表和二级分区的功能,可以完全取而代之。

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/435798
推荐阅读
相关标签
  

闽ICP备14008679号