OceanBase如何获得TPCC测试第1名

57次阅读

共计 14661 个字符,预计需要花费 37 分钟才能阅读完成。

阿里妹导读:TPC- C 是 TPC 组织(国际事务性能委员会)制定的关于商品销售的订单创建和订单支付等的基准测试标准,是数据库联机交易处理系统的权威基准测试标准。

蚂蚁金服自研的分布式关系数据库 OceanBase 获得 TPC- C 测试第一名后,引起了大量关注,今天,我们邀请了 OceanBase 的核心研发人员对本次测试做专业的技术解读。

一、OceanBase 如何做 TPC- C 测试

有机会挑战 TPC- C 测试相信是所有数据库内核开发人员的梦想,但 TPC- C 测试标准非常复杂。由于这是国产数据库同时也是分布式数据库第一次冲击这个榜单,为了完成这次挑战,OceanBase 团队前后准备时间超过一年。

前期准备

TPC- C 测试首先需要找到官方唯一认证的审计员来对测试进行审计监察,他们对这次 OceanBase 的审计也相当重视,全世界仅有的三个审计员这次就有两个参与到测试审计工作中。

测试系统

目前市面上基本找不到一个能够开箱即用的符合 TPC- C 标准的测试工具。以目前各个厂商 PoC 环境最常遇到的 benchmarksql 为例,可以说只是模拟 TPC- C 压力模型的压测工具,连最基本的数据导入都不合规,大量的字符串生成未保证全局随机,缺乏压测阶段最基本的 think time、keying time 这些基本配置导致极小的数据量就能跑出很高的 tpmC,最关键的是它将测试模型大大简化为工具直连 DB 测试,完全没有遵守 TPC- C 测试标准规范。

在标准定义中,测试系统可以分为 RTE(Remote Terminal Emulator)和 SUT 两部分,但实际上从角色上看 SUT 可以进一步拆分为两部分:WAS(web application server) 和 DB Server。

这其中 DB Server 是每个测试厂商的数据库服务;RTE 扮演的角色是测试模型中的客户终端,事务的触发、RT 的统计等都在这里完成;标准明确要求每一个用户 terminal 都必须保持一个长连接,显然在海量 Warehouse 时 DB 是无法承受这么多连接的,WAS 就是 RTE 和 DB 之间桥梁,标准定义可以使用连接池,在保证对应用透明的情况下它可以做所有请求的管理。

这三个角色中,WAS 和 DB 是必须商业化可购买且提供支付服务的,OceanBase 这次是使用了 OpenResty 作为 WAS 供应商。而 RTE 则一般由各个参测厂商自行根据标准实现,但所有实现代码必须经过审计的严格审计,OceanBase 这次完整的实现了一整套完全合规的 RTE,并且支持在大规模测试系统中部署。要知道在实际的 TPC- C 测试流程中,不只是对 DB 端能力的考验,RTE 端同样存在极大的资源消耗和压力。以这次 6088w tpmC 测试结果看,我们一共在 64 台 64c128G 的云服务器上运行了 960 个 RTE 客户端,来模拟总计 47942400 个用户 terminal,最后还需要基于这么多 RTE 统计结果进行一致性和持久化审计验证。

虽然只是测试客户端,但 RTE 的中同样有大量的可能导致最后测试失败的小细节,比如大家可能注意不到的所有事务都因为用了 web 端模拟终端后需要增加的 100 毫秒 rt,又比如为了模拟用户终端输出显示的 100 毫秒延时。

测试规划

TPC- C 从来都不是一个简单的测试,它很科学并没有给出强制的软硬件配置,只是给出测试规范和各种审计检查限制标准,所有数据库厂商可以根据自己的特性充分调优来拿到一个最好的性能或性价比。但这同时也对所有参测厂商提出了一个巨大的难题,如何对已有的资源进行合理规划来保证顺利完成一次对 TPC- C 榜单的冲击。

  1. 硬件选型,这里不仅要对数据库服务器选型,还需要对 RTE 以及 WAS 服务器选型。这之前需要先期进行大量的测试和调优,来摸出在保证性价比的前提下每个角色服务器的资源配置是多少刚好。这次 OceanBase 测试最大的优势就是全部使用了云化资源,我们不需要再关注最底层机房、机柜、布线这些细节,只需要通过快速的规格调整来拿到我们需要的机型。
  2. 参数选择,如何选择合适的配置参数是一个非常令人头疼的问题。举个例子,一个最典型的问题就是我们最终要跑多少个 Warehouse,每个数据库服务器上承载多少 Warehouse。TPC- C 标准为了尽可能模拟真实业务场景,通过每个事务限定不同的 think time 和 keying time 保证了一个 warehouse 的数据最多能够提供 12.86tpmC 值,因此数据库厂商想要拿到更高的成绩就必须装载更多的 warehouse,但是另一方面单机的存储空间又有预计 80%(经验值)需要预留给 60 天增量存储。在分布式数据库架构下,为了能让每个数据库服务器跑满又能充分利用本地存储空间,让每个服务器的 CPU、内存、IO 能力、存储空间的资源最大化利用,我们前后调整优化了近一个月时间。

性能压测

最受关注的性能压测部分在 TPC- C 标准中规定了以下三个状态:

  1. Ramp-up,标准允许每个数据库进行一定时间的预热来达到稳定状态,但是 ramp-up 阶段的所有配置必须和最终报告配置保持一致。
  2. Steady state,保证 ACID 及可串行化隔离级别前提下,数据库需要能够以最终报告 tpmC 值在稳定状态无任何人工干预前提下保持运行 8 小时以上,每隔半小时需要完成一次 checkpoint。
  3. Measurement Interval,标准规定了需要能够支持 8 小时稳定运行,但性能采集阶段只需要保设置 2 小时以上即可。这个阶段还需要保证累计 tpmC 波动不能超过 2%,并且必须完成至少 4 个以上的 checkpoint。

所以之前一般数据库进行性能压测一般是以下的流程,先进行一段时间的预热到达稳态,等待稳定运行一段时间并完成一个 checkpoint 后开始进入 2 小时的性能采集阶段。

而 OceanBase 这次是使用了 TPC- C 测试迄今以来最严苛的一个流程来完成这个性能测试的,我们首先使用了 10 分钟进行预热,然后在 6088w tpmC 稳态保持运行 25 分钟并完成一个检查点,再继续跑了完整的 8 小时性能压测采集阶段,总耗时超过 8 个半小时,中间性能最大波动不到 0.5%,最终结果也让审计员异常兴奋。

整个性能测试前后,审计员还需要进行数据及事务随机分布检查,简单说来就是大量全表扫描和统计 sql,最大的一条 sql 需要访问超过万亿行的 order_line 表结果,可以算是 TPC- C 里的“TPC- H 测试”。现场审计第一次遇到这些 sql 时我们也大量的出现 sql 执行超时情况,但后续基于 OceanBase2.2 版本最新的并行执行框架我们还是很快搞定了这些大 sql,所以要顺利完成 TPC- C 测试并不能只是一个偏科生,保持自身没有短板才是真正意义上的通用关系数据库,从这点上说 Oracle 仍是 OceanBase 学习的榜样。

ACID

  1. A 测试,通过提交和回滚 payment 事务来确认数据库对原子性支持,和 I 测试一样,OceanBase 的 A 测试跑了两遍,分别应对分布式事务和本地事务。
  2. C 测试,标准里的 C 测试一共包含 12 个 case,前四个是必须要完成验证的,每个 case 其实都可以认为是一个复杂的大 sql,而对于分布式数据库来说重点是需要始终保证全局一致。
  3. I 测试,标准要求 TPC- C 模型里 5 个事务除了 StockLevel 事务都需要满足最高的可串行化隔离级别,并构造了 9 个 case 来验证隔离性。对于分布式数据库而言,这个要求并没有那么容易实现,所幸 OceanBase 在 2.x 版本中提供了全局时间戳的支持,所以的 I 测试都在审计员的特别要求下跑完了全本地和全分布式两种模式的两轮测试,这也应该是 TPC- C 测试中首次有数据库厂商需要做两轮 I 测试跑 18 个 case 的,也许在不久后 TPC- C 标准定义也会因为 OceanBase 的这次测试而带来针对分布式数据库的相关更新。
  4. D 测试,OceanBase 在这个场景其实相对传统数据库是有较大天生优势的,OceanBase 每个 Warehouse 数据有两份数据三份日志,通过 paxos 强同步,保证 RPO= 0 的前提下只有秒级 RTO。

面对 D 测试标准中最严格的一项 - 部分存储介质永久故障,OceanBase 还使用了最严苛的测试场景,在使用超出标准要求的全量 6000W tpmC 压力下,我们强行销毁了一个云服务器节点,整体 tpmC 在两分钟内恢复到 6000w 并持续跑到测试时间结束,这些表现都是远远超过 TPC- C 规范要求的,相比较而言其它传统数据库基本面对有日志的存储介质故障 D 测试场景都是依赖磁盘 RAID 来恢复,OceanBase 应该算是首个没有 raid 完全依赖数据库自身恢复机制完成全部 D 测试的数据库厂商了。

同时我们在 D 测试中是连续杀掉了两台服务器节点,首先杀掉一个数据节点,等待 tpmC 恢复且稳定 5 分钟后,再次杀掉了 rootserver leader 节点,tpmC 仍然快速恢复。

二、TPC- C 基准测试之 SQL 优化

对 TPC- C 有所了解人都知道,TPC- C 是一个典型的 OLTP (On-Line Transaction Processing) 场景测试,考察的是数据库在高并发压力场景下的事务处理能力,最终的性能指标以 tpmC(transaction per minute,也即每分钟系统处理 TPC- C 模型中的 new order 事务的数量) 和平均到每 tpmC 的系统成本作为衡量标准。在 OLTP 场景中,每条请求的响应时间都是极短的。因此,各个数据库厂商在进行 TPC- C 测试时,都会尽一切可能将每一个操作时间压缩到最短,不夸张的说,在 TPC- C 的测试中,一些关键操作的优化往往需要细化到 CPU 指令级。

在进入我们的主题前,我们先来谈谈 TPC- C 中的事务模型,主要分为五种事务,订单创建、订单支付、订单查询、订单发货以及库存查询,这五种事务按照一定的比例发生,测试最终衡量的是每分钟订单创建事务的执行个数。大家知道,每一个数据库的事务,其实就是由一定逻辑关系关联的若干条 SQL 语句组成,他们在一个事务中,要么全部成功,要么全部失败,这个在数据库中称为“原子性”,也就是 ACID 中的“A”。那么 TPC- C 中的一个事务的耗时大约是多久呢?看一下报告就很清楚了——只有十几个毫秒。考虑到一个事务由多条 SQL 构成,那么每一条 SQL 的平均耗时都不到 1 毫秒!

在 C /S(client-server)模型中,一条 SQL 语句从发起到执行完成需要经历从客户端输入、网络传输、SQL 优化、执行、结果返回到客户端这样一个流程。而具体每一条 SQL 的执行可能只是做一个字段的更新,所需要的执行时间是非常短暂的,从整个链路的角度来看,大量的时间会花费在与客户端的交互过程中,造成资源的浪费和耗时的增加。那么如何解决这个问题的呢?答案就是使用存储过程。

存储过程

所谓“存储过程”就是数据库为用户提供的一种面向过程的编程语言。基于这种语言,用户可以将应用程序的逻辑封装为一个可调用的过程(procedure)存放在数据库中并随时进行调用。通过这种方式,用户可以将本来需要与数据库进行多次交互才能完成的工作通过一次交互完成,省去了中间网络的传输和等待时间(参见图 1)。假如一条事务的网络开销平均是 30%,也就是说 30% 的 CPU 都花在了网络的收发和解析上。那么在 6 千万规模 tpmC 测试中节省下来 30% 的 CPU 资源换算成系统处理能力是惊人的。使用存储过程还可以带来事务响应时间的下降,导致数据库内核中事务锁的临界区缩短,间接的提升了系统 CPU 利用率,整个吞吐量也随之提高。存储过程在缩短应用端的等待耗时上同样有很大作用。

在 TPC- C 中,存储过程对于整个系统的执行效率提升是至关重要的。OceanBase 的 2.2 版本不仅全面支持了存储过程,而且对存储过程的执行效率做了大量极致的优化。

编译执行

存储过程作为一种面向过程的高级语言,需要转换成机器码才能够执行。这个过程一般可以分为“编译执行”和“解释执行”两种,一般来说,编译执行相比解释执行有代码优化充分、执行效率高等特点。OceanBase 利用近两年逐渐成熟的 LLVM 编译器框架实现了一个支持存储过程的编译器,通过动态编译(Just-in-Time Compilation)的方式将存储过程翻译成高效的二进制可执行代码,在执行效率上获得了数量级的提升。同时,过程中 LLVM 框架将存储过程转换为与机器无关的中间代码,使得存储过程也自然而然地获得了跨平台的编译执行能力,LLVM 内置的优化过程确保我们在各种不同的硬件平台上都可以获得正确、高效的可执行代码。

Array Binding

另外一个在 TPC- C 测试中发挥了重要作用的功能就是对 DML 语句进行批量处理的能力,在 Oracle 中该功能也称为“Array Binding”。一条 SQL 在数据库中的执行过程大致上可以分为“计划生成”和“执行”两个阶段。尽管我们对 SQL 的执行计划做了高速缓存,但找到一个合适的执行计划在整个执行过程中仍然是比较耗时的一个部分。那有没有办法省去这个时间呢?当一组 SQL 的执行计划完全一样而只有执行参数不同时,在存储过程中我们可以通过特定的语法将他们的执行做成一个批量处理的过程,此时“计划生成”只需要做一次即可,这就是所谓的“Array Binding”。

在 Array Binding 中,数据库会首先找到需要使用的计划,然后执行该计划,并在每次执行完毕后,重新执行参数绑定(binding)的过程。打个比方,这就像是在一个 C 语言的 for 循环中,反复赋值而不是重新定义一个数据结构。Array Binding 的使用受用户控制,需要在存储过程中使用 FORALL 关键字来触发这一功能,在 TPC- C 的测试过程中,我们多次使用了 Array Binding 来提升系统的处理能力,效果非常明显。

Prepared Statement 与执行计划缓存

Prepared Statement 是一种二进制的请求交互协议,可以大大降低系统的交互成本。OceanBase 不仅支持用户程序与数据库间使用 Prepared Statement, 也支持在存储过程引擎调用 SQL 引擎执行时使用这种交互方式。存储过程在对 SQL 进行一次 Prepare 操作并获取唯一 id 后, 后续的每次执行仅需要传入该 id 和对应的参数, 系统可以通过高速缓存找到对应的存储过程或 SQL 计划开始执行。该过程相比使用 SQL 文本的交互方式,省去了大量请求文本解析的 CPU 开销。

OceanBase 内部实现了高速缓存来缓存存储过程的可执行代码及 SQL 执行计划, 不同参数的存储过程和 SQL 可以通过这一高速缓存快速获取需要的执行对象, 耗时一般在几十微秒以内, 有效避免了重新编译带来的毫秒级的延迟和 CPU 消耗。

可更新视图

在 OLTP 场景中,通过减少应用与数据库的交互次数来实现性能提升的例子很多,可更新视图就是其中之一。我们常见的数据库视图通常是只读的,通过定义视图,用户可以定义自己感兴趣的数据以及其获取接口,但视图同时也可以作为更新操作的入口,比如在 TPC- C 的 new order 创建场景中,应用需要得到商品信息,更新库存并得到更新后的值。一般可以通过两条 SQL 实现这一过程:

select i_price,i_name, i_data from item where i_id = ?;

    UPDATE stock
      SET s_order_cnt = s_order_cnt + 1,
          s_ytd = s_ytd + ?,
          s_remote_cnt = s_remote_cnt + ?,
          s_quantity = (CASE WHEN s_quantity< ? + 10 THEN s_quantity + 91 ELSE s_quantity END) - ?
      WHERE s_i_id = ?
          AND s_w_id = ?
      RETURNING s_quantity, s_dist_01,
          CASE WHEN i_data NOT LIKE'%ORIGINAL%' THEN 'G' ELSE (CASE WHEN s_data NOT LIKE '%ORIGINAL%' THEN 'G'ELSE 'B' END) END
      BULK COLLECT INTO ...;

但通过建立一个可更新视图:

  CREATE VIEW stock_item AS
      SELECT i_price, i_name, i_data, s_i_id,s_w_id, s_order_cnt, s_ytd, s_remote_cnt, s_quantity, s_data, s_dist_01
      FROM stock s, item i WHERE s.s_i_id =i.i_id;

我们就可以通过一条语句更新库存并得到商品和库存信息:

UPDATE stock_item
      SET s_order_cnt = s_order_cnt + 1,
          s_ytd = s_ytd + ?,
          s_remote_cnt = s_remote_cnt + ?,
          s_quantity = (CASE WHEN s_quantity< ? + 10 THEN s_quantity + 91 ELSE s_quantity END) - ?
      WHERE s_i_id = ?
          AND s_w_id = ?
      RETURNING i_price, i_name, s_quantity,s_dist_01,
          CASE WHEN i_data NOT LIKE'%ORIGINAL%' THEN 'G' ELSE (CASE WHEN s_data NOT LIKE '%ORIGINAL%' THEN 'G'ELSE 'B' END) END
      BULK COLLECT INTO ...;

这样就省去了一条语句的交互,并且更新逻辑更加直观。可更新视图允许用户可以像普通表一样操作视图,但不是所有视图都可以定义为可更新视图。比如带 distinct, group by 的视图,具体更新哪些行语义是不明确的,因此不能允许更新。具体到上面的 stock_item 两表 join 的视图,需要满足所更新表的 unique key 在 join 之后保持 unique(key-preserved table),即 item.i_id 必须是唯一的这个前提。

需要强调,TPC- C 规范禁止使用物化视图,而可更新视图并没有改变底层数据表格的存储形式,是符合规范的。

因为 TPC- C 的设计原则是尽可能的“真实”反应一个 OLTP 系统的运行场景,我们所做的很多优化都具有广泛的适用性。例如,对于一个高并发的 OLTP 系统来说,大部分的 SQL 请求的耗时是非常短的,采用纯粹的 C / S 交互模型的后果必然使系统的时间浪费在应用与数据库的频繁交互中,而使用存储过程可以大大缓解这种交互的耗时,并且增强系统对于网络抖动的免疫力,这种核心能力对于一个分布式 OLTP 数据库是不可或缺的。

在这次的 TPC- C 测试中,我们采用了 OceanBase 2.0 版本开始支持的 Oracle 兼容模式,存储过程和 SQL 全部使用了兼容 Oracle 的数据类型和语法,这样做也是为了在追求极致优化的同时,确保产品迭代可以沿着通用和正规的方向发展。

三、TPC- C 基准测试之数据库事务引擎的挑战

OceanBase 这次 TPC- C 测试与榜单上 Oracle 和 DB2 等其他数据库在硬件使用上有非常大的不同,OceanBase 的数据库服务器使用的是 204+ 3 台型号是 ecs.i2.16xlarge 阿里云 ECS 服务器,其中 204 台作为 data node,还有 3 台作为 root node,每位读者都可以在阿里云网站上轻松按需购买。如果读者翻看 Oracle 和 DB2 的 TPC- C 测试报告会发现,这些数据库都会使用专用的存储设备,例如前最高记录保持者 Oracle 在 2010 年的测试,使用了 97 台 COMSTAR 专用的存储设备,其中 28 台用来存储数据库的重做日志(Redo Log)。

硬件的差异给软件架构提出了完全不同的挑战,专用的存储设备其内部通过硬件冗余实现了设备自身的可靠保证,数据库软件在使用这样的存储设备时就天然的预设了数据不会丢失。但是,这种方式带来了成本的极大消耗,专用的存储设备的价格都是特别昂贵的。

OceanBase 使用通用的 ECS 服务器提供数据库服务,并且只使用 ECS 机器自带的本地硬盘做数据存储,这是最通用的硬件条件。但是这种方式对软件架构提出了很大的挑战,因为单个 ECS 服务器的不如专用的存储设备可靠性高。这也对 OceanBase 的事务引擎提出了很大的挑战,OceanBase 是在普通的 ECS 服务器上就可以实现 ACID 特性。

TPC- C 测试是对事务 ACID 特性有完整并且严格的要求。下面分别介绍 OceanBase 针对事务 ACID 的特性的解决方案。

Paxos 日志同步保证持久性(Durability)

OceanBase 数据库的事务持久性(Durability)保证是依赖事务重做日志(Redo Log)的持久性来达成的。所有的 Redo Log 会实时强同步到另外两台数据库服务机器上,包含产生 Redo Log 的机器在内,总共会有三台机器在硬盘中持久化 Redo Log。

OceanBase 采用了 Paxos 一致性同步协议来协调这三台机器上 Redo Log 的持久化,Paxos 协议采用超过半数(也叫“多数派”)成功即算成功的算法(三个副本时,两个成功即超过半数),当其中两台机器完成持久化后,事务即可完成提交,剩下的一台机器的 Redo Log 在通常情况下,也是立即就持久化完成了。但如果这台机器碰巧出现异常,也不会影响事务的提交,系统会在其恢复后自动补齐所缺失的 Redo Log。如果机器永久故障,系统会将故障机器所应负责同步的数据分散给集群内的其他机器,这些机器会自动补齐所缺失内容,并跟上最新的 Redo Log 写入。

使用 Paxos 一致性协议的最大优势是数据持久化和数据库服务可用性的完美平衡。当使用三个副本时,任何时候坏掉一个副本时至少还有另一个副本有数据,并且写入还可以持续,因为还剩下两个副本,后续的写入也不受影响。

所以,OceanBase 在保证了事务持久性的同时,也大大提升了数据库的连续服务能力。TPC 组织的审计员在现场审计 OceanBase 持久性能力时,在客户端持续产生压力的情况下,从 OceanBase 集群中随意挑选了一台机器做了强制断电操作,发现数据库的数据不仅没丢,数据库不需要任何人工干预还能持续的提供服务,审计员们都很吃惊,并且对 OceanBase 大为赞赏。

依靠自动两阶段提交解决原子性(Atomicity)

TPC- C 测试模型的五种事务中的“订单创建”和“订单支付”两个事务分别会对很多数据做修改,是其中相对复杂的两个事务。TPC- C 标准对事务的原子性(Atomicity)是强制性的要求,要求一个事务内部对仓库、订单、用户等表格的修改一定要原子的生效,不允许出现只有一半成功的情况。

OceanBase 的数据是按照仓库 ID(Warehouse_ID)拆分到多台机器上的,如果所有的事务都是发生在同一个仓库内部,那么无论数据量有多大,事务的修改都只会涉及一台机器的数据,也就是在一台机器上完成事务提交,这是一种完美的线形扩展的场景。但是这不符合实际的业务场景,大多数的实际业务都会有很多不同维度之间的数据交互。TPC- C 测试标准也是对此认真考虑,所以对于事务操作数据的随机性规则提出了要求,最终要保证产生 10% 的“订单创建”事务和 15% 的“订单支付”事务要操作两个及以上的仓库。在 OceanBase 数据库内,这样就产生了跨机器的事务操作,而这必须使用两阶段提交协议来保证原子性。

OceanBase 会自动跟踪一个事务内所有 SQL 语句操作的数据,根据实际数据修改的位置自动确定两阶段提交的参与者,事务开始提交时,OceanBase 自动选择第一个参与者作为协调者,协调者会给所有参与者发送 Prepare 消息,每个参与者都需要写各自的 Redo Log 和 Prepare Log(也意味着每个参与者各自做自己的 Paxos 同步),等协调者确认所有参与者的 Redo Log 和 Prepare Log 完成后,然后再给所有参与者发送 Commit 消息,再等所有参与者的 Commit 工作完成。整个协议是在事务提交过程中自动完成,对用户完全透明。OceanBase 为每一个两阶段提交事务自动选择一个协调者,整个系统任何机器都可以分担协调者工作,所以 OceanBase 可以将事务处理能力进行线形扩展。

多版本并发控制保证事务的隔离性(Isolation)

TPC- C 标准里要求“订单创建”、“订单支付”、“订单配送”、“订单支付”事务之间都是串行化隔离级别(Serializable)。OceanBase 采用的方法是基于多版本的并发控制机制。事务提交时会申请一个事务的提交时间戳,事务内的修改以新的版本写入存储引擎,并且保证之前版本的数据不受影响。事务开始时会获取一个读取时间戳,整个事务内数据的读取操作只会看到基于读取时间戳的已提交数据。所以,事务的读取不会遇到脏数据、不可重复读数据以及幻读数据。同时,事务的修改会在修改的数据行上持有行锁,保证两个并发的修改相同行的事务会互斥。

OceanBase 的全局时间戳生成器也是由多副本组成,可以独立部署在三台机器上,也可以像这次 TPC- C 评测中一样部署在 root node 机器上,与 root node 共享资源。全局时间戳的三副本是一种极高可用的架构,任何一次时间戳的获取操作都至少在三台机器上的两台获得了确认,所以任意一台机器出现故障,获取时间戳的操作不会有一点影响。

按照 TPC- C 标准,OceanBase 准备了 9 种不同的场景测试有读 - 读、读 - 写冲突时事务的隔离性,最终都完美通过了审计员的审计。

一致性保证(Consistency)

在有了上述的事务能力后,OceanBase 可以完美的保证各种数据的一致性的约束。TPC- C 标准里提出了 12 种不同的一致性测试场景在各种测试运行前后对数据库内的数据进行一致性校验。因为 OceanBase 此次测试数据规模庞大,一致性校验的 SQL 需要核对大量的数据,所以一致性校验的挑战在于校验的 SQL 本身运行的效率。基于 OceanBase 的并行查询能力,发挥整个集群所有的计算资源,校验 SQL 的运行时间均缩短了几个数量级,很好的完成一致性功能的审计工作。

复制表

TPC- C 测试模型中有一张商品(ITEM)表,这张表的内容是测试所模拟的销售公司所有售卖的商品信息,包含了商品的名字、价格等信息。“订单创建”事务执行中需要请求这张表内的数据来确定订单的价格信息,如果商品表的数据只存放在一台机器上,那么所有机器上发生的“订单创建”事务都会请求包含商品表的机器,这台机器就会成为瓶颈。OceanBase 支持复制表功能,将商品表设置为复制表后,商品表的数据会自动复制到集群中的每一台机器上。

TPC- C 标准不限制数据的副本数,但是不管数据的组织形式,标准里要求事务的 ACID 一定要保证。OceanBase 使用特殊的广播协议保证复制表的所有副本的 ACID 特性,当复制表发生修改时,所有的副本会同时修改。并且,当有机器出现故障时,复制表的逻辑会自动剔除无效的副本,保证数据修改过程中不会因为机器故障出现无谓的等待。复制表在很多业务场景中都有使用,例如很多业务中存储关键信息的字典表,还有金融业务中存储汇率信息的表。

四、TPC- C 基准测试之存储优化

TPC- C 规范要求被测数据库的性能(tpmC)与数据量成正比。TPC- C 的基本数据单元是仓库(warehouse),每个仓库的数据量通常在 70MB 左右(与具体实现有关)。TPC- C 规定每个仓库所获得的 tpmC 上限是 12.86(假设数据库响应时间为 0)。

假设某系统获得 150 万 tpmC,大约对应 12 万个仓库,按照 70MB/ 仓库计算,数据量约为 8.4TB。某些厂商采用修改过的不符合审计要求的 TPC- C 测试,不限制单个 warehouse 的 tpmC 上限,测试几百到几千个 warehouse 全部装载到内存的性能,这是没有意义的,也不可能通过审计。在真实的 TPC- C 测试中,存储的消耗占了很大一部分。OceanBase 作为第一款基于 shared nothing 架构登上 TPC- C 榜首的数据库,同时也作为第一款使用 LSM Tree 存储引擎架构登上 TPC- C 榜首的数据库,在存储架构上有如下关键点:

  1. 为了保证可靠性,OceanBase 存储了两个数据副本和三个日志副本,而传统的集中式数据库测试 TPC- C 只存储一份数据;
  2. 由于 OceanBase 存储两个数据副本,再加上 OceanBase TPC- C 测试采用了和生产系统完全一样的阿里云服务器 i2 机型,SSD 硬盘的存储容量成为瓶颈。OceanBase 采用在线压缩的方式缓解这个问题,进一步增加了 CPU 使用;相应地,集中式数据库测试存储一份数据,不需要打开压缩;
  3. OceanBase LSM 引擎定期需要在后台做 compaction 操作,而 TPC- C 要求测试至少运行 8 小时且 2 小时之内抖动小于 2%,因此,OceanBase 存储需要解决 LSM 引擎后台操作导致的抖动问题;

两份数据

为了保证可靠性和不丢数据(RPO=0),有两种不同的方案:一种方案是在硬件层面容错,另一种方案是在软件层面容错。OceanBase 选择在软件层面容错,优势是硬件成本更低,带来的问题是需要冗余存储多个副本的数据。OceanBase 使用 Paxos 协议保证在单机故障下数据的强一致。在 Paxos 协议中,一份数据需要被同步到多数派(超过一半),才被认为是写入成功,所以一般来说副本个数总是奇数,出于成本考虑最常见的部署规格是三副本。

三副本带来的首要问题就是存储成本的上升,之前商业数据库的 TPC- C 测试大多基于磁盘阵列,而 TPC- C 规范中明确对磁盘阵列不做容灾要求,使用相对于传统数据库三倍的存储空间进行 TPC- C 测试显然难以接受。

我们注意到这样一个事实,通过 Paxos 协议同步的只是日志,日志需要写三份,但数据不是,数据只需要有两份就可以完成单机故障的容灾了,当一份数据由于服务器宕机不可用时,另一份数据只要通过日志把数据补齐,就可以继续对外提供访问。

和数据存储相比,日志的存储量比较小。我们将数据与日志分开,定义了三种不同的副本类型:F 副本既包含数据又同步日志,并对外提供读写服务;D 副本既包含数据又同步日志,但对外不提供读写服务;L 副本只同步日志,不存储数据。当 F 副本出现故障时,D 副本可以转换为 F 副本,补齐数据后对外提供服务。在 TPC- C 测试中我们使用 FDL 模式进行部署(一个 F 副本,一个 D 副本,一个 L 副本),使用了两倍数据副本的存储空间。无论是 D 副本还是 L 副本,都需要回放日志,D 副本还需要同步数据,这些都是都会消耗网络和 CPU。

在线压缩

在 sharednothing 架构下,OceanBase 至少需要存储两份数据才可以满足容灾的要求,这意味着 OceanBase 需要比传统数据库多耗费一倍的存储空间。

为了缓解这个问题,OceanBaseTPC- C 测试选择对数据进行在线压缩,Oracle 数据库中一个 warehouse 的存储容量接近 70MB,而 OceanBase 压缩后存储容量只有 50MB 左右,大幅降低了存储空间。TPC- C 规范要求磁盘空间能够满足 60 天数据量的存储,对于 OceanBase,由于需要保存两份数据,虽然可靠性更好,但需要保存相当于 120 天的数据量,这些存储成本都要计入总体价格。

OceanBase 使用了 204 台 ECS i2 云服务器存储数据,服务器规格和线上真实业务应用保持一致。每台服务器的日志盘 1TB,数据盘接近 13TB。计算两份压缩后的数据 60 天的存储空间之后,服务器的数据盘基本没有太多余量, 从服务器的资源成本消耗来看,已经达到了比较好的平衡。如果 OceanBase 的单机性能 tpmC 进一步提升,磁盘容量将成为瓶颈。OceanBase LSM 引擎是 append-only 的,它的优势是没有随机修改,能够在线压缩。无论是 TPC- C 测试,还是最核心的 OLTP 生产系统(例如支付宝交易支付),OceanBase 都会打开在线压缩,通过 CPU 换存储空间。

存储性能平滑

TPC- C 测试很大的挑战在于在整个压测过程中性能曲线要求是绝对平滑的,曲线上的波动幅度不能超过 2%,这对于传统数据库来说都是一件困难的事情,因为这要求对于所有后台任务的精细控制,不能由于某个后台任务的资源过度使用导致前台请求的阻塞积压。而对于 OceanBase 而言,事情变得更为困难,因为 OceanBase 的存储引擎是基于 LSM Tree 的,在 LSM Tree 要定期执行 compaction 操作。Compaction 是个非常重的后台操作,会占用大量 CPU 和磁盘 IO 资源,这对前台的用户查询和写入天然就会造成影响。我们做了一些优化,来平滑后台任务对性能的影响,从最终的测试结果来看,性能曲线在整个 8 小时压测过程中的抖动小于 0.5%。

  • 分层转储

在 LSMTree 中,数据首先被写入内存中的 MemTable,在一定时候为了释放内存,MemTable 中的数据需要与磁盘中的 SSTable 进行合并,这个过程被称为 compaction。在很多基于 LSM Tree 的存储系统中,为了解决写入的性能问题,通常会将 SSTable 分为多层,当一层的 SSTable 个数或者大小达到某个阈值时,合并入下一层 SSTable。多层 SSTable 解决了写入的问题,但是 SSTable 的个数过多,会极大拖慢查询的性能。OceanBase 同样借鉴了分层的思路,但同时使用了更加灵活的 compaction 策略,确保 SSTable 总数不会太多,从而在读取和写入性能之间做了更好的平衡。

  • 资源隔离

Compaction 等后台任务需要消耗大量的服务器资源,为了减少后台任务对用户查询和写入的影响,我们在 CPU、内存、磁盘 IO 和网络 IO 四个方面对前后台任务做了资源隔离。在 CPU 方面,我们将后台任务和用户请求分为不同的线程池,并按照 CPU 亲和性做了隔离。在内存方面,对前后台请求做了不同的内存管理。在磁盘 IO 方面,我们控制后台任务 IO 请求的 IOPS,使用 deadline 算法进行流控。在网络 IO 方面,我们将后台任务 RPC 和用户请求 RPC 分为不同队列,并对后台任务 RPC 的带宽使用进行流控。
存储 CPU 占用

TPC- C 基准测试主要考察整体性能 tpmC,很多人也会关注单核的 tpmC。然而,这个指标只有在相同架构下才有意义。对于存储模块的 CPU 占用,有如下三点:

  1. 对于集中式架构,除了数据库使用 CPU 之外,专用存储设备也需要使用 CPU。例如,第二名 Oracle 3000 多万 tpmC 的测试中,数据库使用了 108 颗 T3SPARC 处理器,共有 1728 个物理核心和 13824 个执行线程,同时存储设备使用的是 Intel 服务器作为机头,总共使用了 97 台服务器,194 颗 Intel X5670 CPU,2328 个物理核心。
  2. 集中式数据库使用高可靠硬件,只需要存储一个副本,而 OceanBase 通过软件层面容错,虽然硬件成本更低但需要两个数据副本和三个日志副本,维护多个副本需要耗费大量 CPU;
  3. OceanBase 在 TPC- C 测试和生产系统中都打开了在线压缩,进一步增加了 CPU 使用;

因此,简单地对比 OceanBase 和 Oracle 的 CPU 核是不科学的,还需要算上共享存储设备的 CPU 核,以及 OceanBase 存储多副本和在线压缩带来的 CPU 开销。TPC- C 推荐的方案是不关注具体的软件架构和硬件架构,关注硬件总体成本。在 OceanBase 的测试中,硬件成本只占整体成本的 18% 左右,只考虑硬件的性价比大幅优于集中式数据库。

后续发展

OceanBase 的优势在于采用分布式架构,硬件成本更低,可用性更好且能够做到线性扩展,但是,OceanBase 单机的性能离 Oracle、DB2 还有不小的差距,后续需要重点优化单机存储性能。另外,OceanBase 的定位是在同一套引擎同时支持 OLTP 业务和 OLAP 业务,而目前 OceanBase 的 OLAP 处理能力还不如 Oracle,后续需要加强存储模块对大查询的处理能力,支持将 OLAP 算子下压到存储层甚至在压缩后的数据上直接做 OLAP 计算。

本文作者:阳振坤(OceanBase 创始人)、曹晖(OceanBase 技术专家)、陈萌萌(OceanBase 资深技术专家)、潘毅(OceanBase 资深技术专家)、韩富晟(OceanBase 资深技术专家)、赵裕众(OceanBase 高级技术专家)

阅读原文

本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

正文完
 0