BT

您是否属于早期采用者或者创新人士?InfoQ正在努力为您设计更多新功能。了解更多

为OLTP选择适合的RDBMS

| 作者 “No Bugs” Hare 关注 0 他的粉丝 ,译者 大愚若智 关注 5 他的粉丝 发布于 2017年1月3日. 估计阅读时间: 4 分钟 | 硅谷人工智能、机器学习、互联网金融、未来移动技术架构 ,尽在QCon上海2017

[[本文摘自即将出版的图书《Development&Deployment of Multiplayer Online Games》第2卷“Beta”版第11(f)章。目前这本书正处于Beta测试阶段,Beta测试意在改善图书质量,并为协助改善本书的热心人提供免费的“可发行”电子版本,更多详情请参阅“图书的Beta测试”。Beta测试过程中发布的所有内容可能会在图书正式出版前有所改动。

若要完整浏览本书目录,请参阅Development&Deployment of MOG:内容目录。]]

我们经常需要为自己的OLTP(事务/运营)数据库选择适合的RDBMS(关系型数据库管理系统)。虽然通过编写可移植的SQL可以暂时避免进行这样的选择,但迟早要做出这样的选择,至少需要进行这样的尝试(例如意识到具体的选择不够明确,因此决定选择跨RDBMS的SQL)。

生产环境OLTP选择RDBMS的标准

在发起“到底哪个RDBMS最好”的圣战之前,也许需要首先明确一下对于24x7运行的生产级OLTP RDBMS,到底需要具备哪些必不可少的功能。

基于锁,或是基于MVCC

考虑到并发性,目前几乎所有RDBMS无外乎基于锁的(Lock-Based),或基于MVCC(多版本并发控制)的。从写负载更重的OLTP处理角度来说,我曾经见到过:

  • 对于读写混合型负载(例如OLTP事务和报表),基于MVCC的RDBMS表现会比基于锁的略好一些。
    • 如果使用高于Read Uncommitted的隔离级别,效果还会更好,最适合用于读取/报表用途。
    • 另一方面,OLTP很少会遇到大量并发读取的情况,如果真的遇到这种情况,通常可通过副本(Replica)执行此类读取,因此不会造成太严重的问题。
  • 对于大部分情况下以写入为主的OLTP(没有太多报表需要创建),基于锁的RDBMS要比基于MVCC的表现略好一些。
    • 然而如果能让OLTP工作负载使用INSERT代替UPDATE,此时MVCC的效率更高。

另外有必要注意,如果使用了单一写入连接(Single-write-connection)数据库架构,基于锁和基于MVCC的RDBMS之间的逻辑差异将显得微乎其微(尽管性能略有差别,但其他方面几乎相同,基于锁的RDBMS通常略微领先一些)。

ACID保障

对于OLTP数据库,我们需要为涉及多行和多表的事务提供ACID保障。

如上所述,对于OLTP数据库,我们需要为事务提供全面的ACID保障。更重要的是,需要保障涉及多行和多表的事务具备ACID特性。虽然这一规则也有例外,但这种例外情况实际上极为罕见。

这几乎已自动将MySQL+MyISAM用作OLTP数据库的可能性彻底排除在外。但是也要注意,MySQL+ISAM可能是少数应用(例如作为快递追踪系统或系统监视工具的后端)的好选择,但并不适合涉及某类与金钱有关信息的常规OLTP处理。

此外RDBMS提供的ACID保障差不多等同于意味着需要使用数据库日志,同时也意味着一旦RDBMS崩溃,随后需要通过数据库日志进行自动恢复(并自动前卷(Rollforward))。

支持24×7运行

作为联机备份的备选方案,可使用异步主从复制(Replication)

我们需要的另一系列功能主要与24×7不间断运行有关(例如游戏服务器,总得全天候运行对吧)。这些功能包括:

  • 联机备份。无论做什么都肯定需要备份,24x7不间断运行更是少不了联机备份。
    • 通常来说,联机备份意味着需要具备“日志前卷”能力。大部分时候是这样工作的:创建两个数据库,一个作为“主”,一个作为“从”,随后从“主”获取日志文件并发送给“从”,然后在从数据库上进行“前卷”。
      • 此外有些数据库可以对处于“日志前卷”状态下的“从”数据库执行只读请求(实际上等同于创建了一个只读从副本)。然而其他一些RDBMS不能处理这样的请求(例如需要首先完成“日志前卷”操作才能让从RDBMS能够接受查询操作)。
    • 作为联机备份的备选方案,也可以通过异步主从复制获得近乎完全同步的备份副本(这种做法对MySQL+InnoDB是一种尤为有趣的选项)。
      • 需要注意,这样的副本也许可以或无法支持联机备份+前卷那样的“时点”恢复(具体情况请参阅文档)。虽然只在从一些非常糟糕的情况下恢复时需要“时点”恢复(实际生产环境中我从未遇到需要这种恢复的情况),不过真遇到这种糟糕的情况至少也能助我们一臂之力。
    • “即时”的ADD COLUMN语句。我们可能需要对生产环境的数据库进行扩展,这一点是确定无疑的。大部分时候这是通过ALTER TABLE… ADD COLUMN语句实现的。面对ADD COLUMN语句,很多RDBMS会简单地将整个表重写为新格式的行。如果表包含10亿行,这一过程可能需要数小时??(在进行复制的过程中,整个表将完全无法访问,导致数据库在数小时内无法使用??)。让ADD COLUMN能够近乎即时(考虑到表的大小,可能需要几毫秒的时间)执行完成并不需要什么艰深的技术,有些RDBMS也确实能做到这一点,但是也不能忽视,这并不是一种普遍特性??。
      • 预算不足时的备选方案是实现无锁ADD COLUMN(以及常规的ALTER TABLE),方法如下:
        • 用新的结构创建“影子”表
        • 通过触发器将对当前表的所有改动写入影子表
        • 将数据从当前表复制到影子表(一定要忽略已存在的行,因为触发器已经在其中写入内容了)
        • 用影子表取代当前表
      • 这种“廉价”的ADD COLUMN方法相当繁琐(全过程会对性能产生极大影响),但如果没有其他更好的方法,这种做法至少可以起到一定的效果。
      • “即时”ALTER COLUMN(字段拓宽,Widening field)也是个很好的功能,但因为字段拓宽可通过ADD COLUMN模拟,因此显得并不是太重要。
      • 联机表优化。这个功能需要介绍一下。由于RDBMS会不断修改表内容,表的性能会逐渐退化(实际上取决于所用存储引擎,从“行溢出(Overflow row)”到“死行(Dead row)”,我们会遇到各种不希望出现的情况)。为此有必要进行一定的优化(例如InnoDB的OPTIMIZE TABLE,DB/2的REORG TABLE,Postgres的VACUUM等),并且我们会需要联机完成这些操作(无需让整个数据库彻底停摆,因为对包含数百万行内容的表进行优化通常需要花很长时间)。
        • 大部分时候,此类优化需要创建“影子副本”(由数据库自行创建,这总好过需要我们手工创建),这也意味着需要额外的存储空间。不过至少有一个RDBMS提供了“原地”表优化功能。
    • 容器的重新平衡。虽然不像上文列出的其他问题那么重要,但我始终认为“容器的重新平衡”也是RDBMS需要考虑的一个重要问题。简单来说,这个问题主要出现在添加存储数据的新硬盘(这种情况时有发生),以及通过将数据分散在所有硬盘上实现提速时。此时可通过下列两种方法之一实现:(a) 使用RAID-10(这样就无需考虑数据库存储数据的方式了),以及 (b) 通过多个RAID-1磁盘使用数据库容器(因为数据库本质上采用了类似RAID-0的工作原理)。只要无需添加新硬盘(实际上通常在添加时,为了实现冗余往往会成对增加硬盘),所有系统基本上是均等的,然而在添加了一对新硬盘后,我们需要对硬盘进行“重新平衡”,借此实现负载的重新平衡,这一“重新平衡”的工作分别是由RAID或数据库进行的。RAID级别的重新平衡对服务器性能的影响远大于数据库级别的重新平衡(尤其是有些情况下系统甚至完全无力承担RAID级别重新平衡过程中产生的负荷)。因此我更乐于选择使用由数据库管理的容器(会在增加容器后重新平衡,整个过程会保持尽可能平缓)。

随着RDBMS不断修改表内容,表的性能会逐渐退化

性能

不幸的是,缺乏具体用例情况下进行的数据库性能评测其实没有任何意义

当然,性能(尤其是写性能)对OLTP数据库至关重要。不幸的是,缺乏具体用例情况下进行的数据库性能评测其实没有任何意义??。因此我只能尽量介绍一些与性能有关的知名RDBMS架构功能及对某些功能的误解。

SQL编译器的提示

人类从不以史为鉴,这本身就是最重要的“鉴”。

— 奥尔德斯·赫胥黎 —

在向RDBMS提交SQL语句时,语句会被编译为“执行计划”。而(无论数据库开发者怎么想或数据库产品的销售人员怎么说)这样的编译器时不时总会出错??。例如下面列出了一个常见的此类错误:

  • 我们正在使用基于统计信息(即基于成本)的SQL编译器。
  • 有一个很大的历史表,其中包含一个TIMESTAMP字段(很常见的情况)。
  • 统计信息恰好有些陈旧,例如晚了几小时/几天(总是会这样)。
  • 我们正在编译的SQL语句会获取“T=上一小时”之后的数据。
    • 此时SQL编译器查看统计信息发现我们所请求的T之后没有任何数据,并决定针对上一小时的数据进行索引扫描(并预期到将会读取回0行数据)。
      • 其实还有其他(实际上更好的)执行计划(基于其他索引),但SQL优化器(预期会通过索引扫描取回0行数据)决定使用基于时间的索引。
    • 然而在上一个小时里产生了几百万笔事务,导致这次索引扫描工作需要耗费极长的时间??。

为解决此类(以及其他类似)灾难,人们发明出一种所谓的“SQL编译器提示(Hint)”功能。“提示”可供我们强制RDBMS使用我们选择的执行计划,(对于99%的OLTP语句实际上都可以实现确定最优化的执行计划)。

如果有人告诉你“嘿,数据库总是比你更了解实际情况”,你可千万别相信(通常确实如此,但总是这个词用的有些太绝对了)

另外,如果有人告诉你“嘿,数据库总是比你更了解实际情况”,你可千万别相信(通常确实如此,但总是这个词用的有些太绝对了)。在现实世界中,除了像上文提到的这种“壮烈”的优化器失败,还有另一个有趣的故事。在RDBMS的远古时期,IBM DB/2团队曾坚定不移地严格禁止使用提示,就是这样(“我们比你更懂!我们不允许,这其实是我们的Bug,马上就会修复。”)然而(与其他所有空话一样)事情并没有像他们说的那样发展。经过一段时间的发酵,DB/2编译器选择错误执行计划的问题甚至催生了一种事实标准的实践:“如何欺骗DB/2优化器”,例如在WHERE子句中添加“OR 1=0”,借此对编译器产生影响(实际上“OR 1=0”就可以看作一种SQL编译器提示)。后来这个技巧被广泛采用(尽管DB/2团队依然在说“我们始终比你更懂”),以至于DB/2团队最终不得不承认“OR 1=0”的作用很重要,他们会保证该方法以后可以永远使用下去??。但是故事还没完,大概10年前(坚持认为“我们比你更懂”大约20年后),DB/2开始支持提示(虽然面子上过不去,但至少好过“OR 1=0”这样的做法)。

目前Postgres团队正在坚守与DB/2团队30年前相同的立场,对此我唯一感到好奇的并不是Postgres以后是否会改变有关提示的立场,而是什么时候会改变。不幸的是,大家从历史教训中学到的唯一经验就是:人们从不会以史为鉴??。

OLTP的性能问题

某些RDBMS会让人感觉它们在设计时从未考虑过主要以写操作为主的OLTP(而是更专注于读取查询)。虽然这并不意味着此类RDBMS从本质上就很糟糕(毕竟大部分数据库确实主要以读取查询为主要任务),但在现实世界中,面对需要执行大量写操作的OLTP环境,这会成为一个不容忽视的问题??。一起看看这些相当著名的问题吧。

Postgres:甚至对非索引字段进行更新也会导致Ctid的变化(存在争议)

有报道称现实用例中对包含大量索引的数据库进行更新时,Postgres的数据库会遇到严重的性能问题。相关问题的详细讨论可参考StackOverflow.PostgresUpdatesKlitzke,在我看来问题主要在于:

“由于索引需要通过Ctid引用行,一个简单的UPDATE(哪怕针对非索引列执行)也会改变Ctid,导致引用了被更改行的表中每个索引中的Ctid均需要重写。”

这就很糟了,对写操作负担重的OLTP数据库尤为如此??。另外从Postgres 8.3开始提供了一种所谓的Heap-Only Tuples(HOT)功能,该功能至少在理论上应该能消除大部分相关问题(然而我没找到任何能确认这一点的现实用例),该功能的简要介绍可参阅Postgres.HOT。这个功能的大致思路是:在HOT正常工作的前提下,如果新行可以放入同一页,那么无论Ctid如何变化,索引依然会指向同一页,因此无需更新索引。当然这种想法有一定效果,但前提是新行可以放入同一页,为此似乎可以通过“机会型的(Opportunistic)Mini-vacuum”实现:尽管Postgres依然无法清理(Prune)需要更新的Tuple(出于MVCC的考虑必须保持精简),但(据推测)可以对同一页中较旧的Tuple进行清理,这样也许可以在同一页中保存新行并避免更新索引。

底线是:虽然Postgres存在不必要的索引更新问题,但通过HOT功能大幅缓解了这个问题,但HOT能否完全解决这个问题还有待讨论(这种缓解过程可能需要额外的配置以便在页中为HOT提供所需的空间),但至少我们可以针对数据库实例监视HOT的运行效率(可参阅Postgres.HOT)。

MemSQL:投票式日志写入

虽然内存中数据库为OLTP应用提供了巨大收益,但我并不会出于这种用途考虑选择MemSQL,原因如下。

正如Mituzas所述,MemSQL会使用耗时50毫秒的投票发起数据库日志写入操作。对任何类型的OLTP数据库来说这都是一种很糟糕的做法,但如果你考虑我的建议选择单一写入数据库连接架构,MemSQL的这种所谓“功能”会造成极为严重的后果??。一定要反复核实该产品是否还在使用这个功能,如果在使用,至少应该尽量避免使用单一写入数据库连接的配置。

执行计划和Profiling

为了对SQL语句进行调试和Profiling,至少需要具备一个能展示SQL查询“执行计划”的工具。

面对生产数据库,我们需要对SQL语句进行调试和Profiling。至少需要具备一个能展示SQL查询“执行计划”的工具。这样才能预测查询的执行方式(即,SQL语句编译后的执行计划将用于生产数据库,或从生产数据库状态导入的数据库)。

另外执行计划只能告诉我们预测的执行成本(通过数据库状态计算而来),但可能与实际情况存在数量级的差异。

为此可以使用某些类型的实时Profiling技术。这类工具可能有一定的作用,但在我看来并非绝对必要:通常来说只要具备一些经验和常识,就可以很容易地发现这些与查询有关的性能问题(一般来说,迫使数据库使用我们指定的查询计划,这往往要比确定当前所用查询计划表现欠佳的原因更为困难)。

内存中处理

目前已经有不少RDBMS提供了内存中处理功能。这些功能主要可分为两类:

  • 非持久内存中处理。例如通过RAM磁盘运行RDBMS,以及为MySQL使用MEMORY存储引擎。但这种方式通常无法用于OLTP数据库。
  • 持久内存中处理。这种方式类似于在应用和RDBMS之间添加了一层内存缓存(实际上Oracle的TimesTen IMDB Cache就是作为一种缓存进行宣传的)。下文将要介绍的所有大型商用RDBMS供应商都提供了类似技术,但每种技术都需要耗费血本??。

然而非持久内存中处理技术通常并不适合OLTP数据库

复制

面对极高的负载,我们迟早需要为数据库创建(只读的)副本(Replica)。如果所用RDBMS产品支持复制(并能正确使用),就可以自动创建所需副本??。

大部分时候我们最需要的是一种所谓的主从异步复制(这样从副本的延迟才不会影响主副本)。此外可能还会用到其他相关功能,例如副本合并(同样适用于简单的主从异步环境,但绝对不会产生任何冲突)。

然而从我个人的经验来看,RDBMS提供的复制功能在高负载情况下通常表现都很糟??。有这样一个极端案例:在负载持续多天维持每天不超过1百万笔事务的情况下,复制功能总是因为一些难以理解的错误而失败,需要对副本进行完整的重新同步(这也是个非常头疼的问题??)。这种情况告诉我们:

在实际使用前一定要通过极为严苛的负载对复制机制进行测试

DUD

设备或机械由于无法正常工作或运转失败而显得无用

— 维基词典 —

好在如果你选择的复制技术恰好就是这样的“DUD”(并且使用了单一连接的方法),还可以用相对较为简单的方法自行进行复制。

分区

RDBMS提供的分区(Partitioning)是一种实现可缩放性的工具,但往往会被过度吹捧。但是我本人也倾向于选择无需共享(Share-Nothing)的模式(并采用应用层面的分区),因为相比将一个数据库分区至多台服务器,这种方式可以上线更为线性的缩放能力。但有些情况下RDBMS提供的分区功能也会显得较为有用,因此如果提供有这样的功能,也可以将其看作一个“加分项”(尽管可能并不像RDBMS销售人员说的那么天花乱坠)。

对OLTP而言不是问题

在比较不同RDBMS时,你肯定会看到有关不同RDBMS对JOIN的支持情况,或对SQL标准不同解释的大量争议。然而有一件事必须注意:

虽然所有这些问题对“报表”和“分析”数据库非常重要,但从以往经验来说,对OLTP数据库并不重要

OLTP数据库是一种很奇怪的东西,尤其是这一领域很少会使用JOIN语句。当然,你可能有时候会需要JOIN(毕竟这是SQL的全部??),但大部分情况下OLTP数据库并不需要JOIN(哪怕真的需要JOIN,也可以非常简单地实现)。因此除非为“报表”和“分析”使用同一个数据库(下文将详细介绍),这个问题其实并不重要。

然而有些时候确实需要为“报表”和OLTP使用同一个RDBMS

然而有些时候确实需要为“报表”和OLTP使用同一个RDBMS,尤其是恰巧在这两类数据库之间进行了RDBMS级别的复制时,可以无需自行实现,直接获得所需副本(过程较为简单,但非常耗时)。

RDBMS供应商(尤其是商用供应商)还过度鼓吹了另一个问题:容错。使用容错功能的数据库服务器并不能保证可以改善MTBF(考虑到容错系统本身的MTBF并非无限的,很容易得出这样的结论)。更重要的是,现实情况告诉我们,容错功能的MTBF通常低于高质量服务器硬件自身的MTBF,这意味着如果不使用容错机制,系统本身的MTBF反而更高(这也是现实世界中经验得出的结论)。换句话说,对于高质量服务器,硬件(例如CPU或主板)故障几率远低于容错系统出错(进而导致各种类型的麻烦,直到最棘手的“裂脑(Split brain)”)的几率。

当然,有些情况下确实需要容错(例如证交所或银行的系统),但这些系统很可能运行在DB/2 / Oracle产品之上,它们在这方面表现其实差不多,因此RDBMS的容错问题也就不那么重要了。

许可

一旦开始考虑商用RDBMS的许可问题,你会发现这些产品不仅昂贵,而且许可机制极为复杂,可能需要花费数天时间才能理解到底要花多少钱

最后同样重要的一个问题:还需要考虑许可的获取及相关成本。一旦开始考虑商用RDBMS的许可问题,你会发现这些产品不仅昂贵,而且许可机制极为复杂,可能需要花费数天时间才能理解到底要花多少钱。我对截止2016年底市面上三大商用RDBMS的许可情况分析如下。

首先是几个备注:

  • 我会尽可能以“每内核”方式比较不同产品的价格。
  • 我只关注面向生产环境的许可,“开发者版”、“学生版”,只能通过托管供应商获得的版本等特殊版本不予考虑。
  • 此外我还会忽略“授权的客户端”这种许可模式(毕竟这种模式无法适用于用户数未知的部署)。
  • 声明:有关许可的介绍信息基于“我本人尽最大努力后的理解”,但不提供任何保证。在制定任何决策,尤其是要购买昂贵的产品前,还行自行分析相关信息。
  • 另外需要注意,虽然存在一些共同的趋势(例如免费提供较为基本的数据库产品),但商用数据库的许可经常会发生变化,尤其是内核数方面的限制,通常数量可能增加,但也有可能降低??。
  • 最后同样重要的是:一定要与经销商好好砍价,有时候甚至能达到50%的折扣,对于更大金额的合约甚至折扣可以高达80%。

Microsoft SQL Server 2016

在各大主要商用数据库中,MS SQL Server是最便宜,许可模式最简单的产品之一(没错,按照商用RDBMS的标准来看真的是既便宜又简单)。注:下列数据来自SQLServer.Editions

Microsoft SQL Server Express

成本:免费。

局限:最多1颗处理器(或4个内核,取较小值),1GB内存,数据库体积上限10GB。SQL Server 2016中这些限制适用于每实例,主要限制了每个实例(而非每台数据库服务器)可用资源总量,通过一台物理服务器运行多个实例绕过这些每实例限制的做法是官方允许的,详情请参阅SQLServer.CapacityLimits

考虑到每个数据库10GB容量的限制,就算为每个服务提供一个数据库,也会很快达到上限

因此该版本非常适合为每个服务提供一个数据库(无论是否使用单一数据库连接)的模式。然而考虑到每个数据库10GB容量的限制,就算为每个服务提供一个数据库,也会很快达到上限??。

功能:基本的SQL功能,支持24×7运行,可充当复制关系中的客户端。

缺乏的功能:分区,充当复制关系中的主副本。

当然,该版本可以由用户自行进行分区和复制,如果希望针对企业版之外SQL Server版本自行分区,可使用一些工具,例如Clement实现。

Microsoft SQL Server Standard

成本:约每内核2千-4千美元(可参阅OzarSQLServer.Pricing)。

局限:最多4颗处理器(或24个内核,取较小值),128GB内存,数据库大小几乎无上限。

功能:基本的SQL,支持24×7运行、复制,及SQL Profiler。

缺乏的功能:分区。

只要预算允许,SQL Server Standard是一款完整功能的RDBMS产品,很适合用于OLTP负载。我通常更愿意选择该产品而非MySQL(出于可靠性和功能丰富程度的考虑),然而如果预算极为充足,我会考虑用DB/2或Oracle产品代替(虽然通常更贵,但相比MS SQL而言,长远来看通常会更可靠[1])。

Microsoft SQL Server Enterprise

成本:每内核7千-1.4万美元。

局限:无。

功能:需要的一切功能,外加内存中OLTP处理。

缺乏的功能:无。

SQL Server Enterprise无疑很贵,老实说我没看到该版本有任何实际用例,除了内存中OLTP(在这一领域SQL Server在价格方面远超其他所有商用RDBMS)。其实如果你按照本书其他章节提供的思路来设计数据库架构,除非每天写入事务量上亿,否则通常并不需要内存中OLTP,这样价格也就显得不是那么的高。

IBM DB/2 10.5

IBM DB/2在一个领域是不容置疑的冠军:尽可能让价格高到离谱让人难以置信??[2]。然而DB/2也确实具备一些不错的技术特性(我本人就有良好的使用体验),因此成本分析中也包含了这个产品。

DB/2 Express-C

成本:免费。

局限:最多2个内核,16GB内存,数据库体积上限15TB。这一系列限制适用于每台服务器(而非每个实例),但也可适用于每个虚拟化会话,详情请参阅RadaMelnyk

功能:基本的SQL,支持24×7运行。

缺乏的功能:分区,复制。

总的来说,对于大部分单一写入数据库连接部署(尤其是使用副本作为报表用途时),2内核的限制并不是太糟,通常可在无需面临太多局限的情况下满足要求。其他局限其实也显得不是太糟糕了。

另外还可参阅上文自行实现分区和复制的介绍(DB/2的自行分区实现方式与SQL Server差不多)。

DB/2 Express

DB/2 Express主要有两种值得我们考虑的定价模式。

成本:DB/2 Express主要有两种值得我们考虑的定价模式。其中之一基于一种名为PVU(暂不考虑其含义)的概念:约为每PVU 70美元[3]及每内核100PVU,换算后价格为每内核7千美元。另一种定价模式基于所谓的FTL概念,可将其简单理解为包年订阅的全套方案(初始TCO较低,长期范围内较高)。然而我暂时没找到有关DB/2最新FTL定价的标准??。

局限:最多8内核,64GB内存(每服务器),数据库大小上限15TB。

功能:基本的SQL,支持24×7运行和复制(一种名为SQL Replication的复制方式)。

缺乏的功能:分区,Q Replication。

DB/2 Express相当贵,但功能也相当强大。对于OLTP应用,通常使用中不可能达到规格上限,但对报表(和分析)副本,这样的上限略微有些低。

DB/2 Workgroup

顾名思义,DB/2 Workgroup与DB/2 Express基本类似,但存在下列差异:

  • 上限提高至16个内核与128GB内存(每服务器)。
  • 相比DB/2 Express,成本提高约1.5倍(大约每内核1万美元左右)。

是否可以将Workgroup版用于OLTP应用这不太好说,但报表副本可以从该版本提高的上限中获益。

DB/2 Enterprise

相比DB/2 Workgroup,上限有所提高,但价格也有了5倍-6倍的提升(约为每内核5万美元左右!)。此外Enterprise Server还提供了一些花哨的功能(例如Q Replication),但老实说与其支付对这么贵的价格,不如自行开发复制机制 ;-)。

实际上我没看到任何将DB/2 Enterprise用于OLTP的用例(甚至银行/证交所也不会这样做)。

DB/2 Advanced * Server

为了让许可机制变得更复杂,DB/2还提供了Advanced Workgroup Server和Advanced Enterprise Server版本。这些版本的价格高得离谱(Advanced Workgroup的价格与非Advanced Enterprise版价格类似,但Advanced Enterprise的价格比非Advanced Enterprise版高了1.5倍)。另外他们还提供了每TB容量定价的模式(Advanced Workgroup版每TB容量约5万美元,Advanced Enterprise版每TB10万美元)。OLTP数据库的容量通常不会超过1TB(但他们没提供低于1TB容量的许可),因此可以将其理解为实际成本。

在OLTP处理方面,DB/2 Advanced Workgroup Server的用例可能只有一个:那就是你真的非常“不差钱”,并且同时你还需要内存处理技术。

Oracle Database 12c

相比BD/2,Oracle的许可机制略微简单,但实际价格更加昂贵??。

Oracle DB Express (DB XE)

成本:免费

局限:11GB用户数据,最高1GB内存,单一内核。

功能:基本的SQL,支持24×7运行。

缺乏的功能:分区,复制。

在我看来,11GB用户数据的限制使得该产品基本无法用于现实环境,哪怕为每个服务使用一个数据库也是如此。然而对于OLTP,也不是完全不现实。

Oracle DB Standard Edition 2 (DB SE2)

成本:每内核17500美元[4](永久许可),每内核3500美元(1年期限),此外如果稍后需要使用其他功能,需要随时准备好为这些功能额外付费??。

局限:最多16个内核(或2个处理器,取较小值)。

(包含的)功能:基本的SQL,支持24×7运行,复制。

缺乏的功能:分区。

老实说,SE2应该已经可以满足所有OLTP负载的需求(内存中处理除外),但成本同样很高??。

Oracle DB Enterprise Edition (DB EE)

成本:每内核47500美元(永久许可),每CPU 9500美元(1年期限),此外如果稍后需要使用其他功能,需要随时准备好为这些功能额外付费??。

局限:无。

(包含的)功能:基本的SQL,支持24×7运行,复制,分区。

(额外付费的)可选功能:内存中处理(适用于Oracle EE的TimesTen In-Memory Cache)。

我认为唯一OLTP环境中有必要使用Oracle EE的唯一原因是TimesTen,而这技术真是贵得过分??。

与OLTP有关的RDBMS功能对比表格

上文内容可总结在下表中(但是要注意:下表列出的都是对OLTP生产环境较为重要的因素,与报表、分析等场景的关系不大。也就是说,下表并不能告诉你“总的来说最棒的RDBMS是哪个”,而是会告诉你“以写操作为主的OLTP应用最适合的数据库是哪个”):

注意:对OLTP最为重要的特性均使用了粗体字

注意:对OLTP最为重要的特性均使用了粗体字 MySQL + InnoDB [1][2] PostgreSQL MS SQL Server IBM DB/2 Oracle
类型 MVCC MVCC 基于锁或MVCC 基于锁 MVCC
ACID保证 多行ACID 多行ACID 多行ACID 多行ACID 多行ACID
    24×7运行      
联机备份 第三方,可使用异步复制代替 支持 支持 支持 支持
ADD COLUMN 复制整个表,很慢;基于第三方触发器的方式[1] “即时” “即时”[1] “即时” “即时”
表优化 联机[1] 联机 联机 联机就地[1] 联机
添加磁盘 依赖文件系统,添加磁盘会导致文件系统不平衡或需要RAID级别的平衡 依赖文件系统,添加磁盘会导致文件系统不平衡或需要RAID级别的平衡 虽然使用了容器,但似乎无法进行明确的重新平衡[1] 容器重新平衡 容器重新平衡
    OLTP性能      
提示 USE INDEX 不支持[1] WITH(INDEX) 可行但效果一般[1] INDEX/NO_INDEX
已知的OLTP性能问题   非索引更新重写整个行[1]      
执行计划/Profiling EXPLAIN、Profiling[1] EXPLAIN SHOWPLAN_*、Profiler[1] EXPLAIN、Profiler EXPLAIN、Profiling
内存中处理(耐久) 不支持[1] 不支持 支持(贵) 支持(贵) 支持(贵)
    复制/分区      
异步主从复制 支持 支持 支持[1] 支持[1] 支持[1]
分区 支持 支持 支持[1] 支持[1] 支持[1]
    定价      
定价选项1 免费[1] 免费 免费(最多10GB数据) 免费(最多2内核) 免费(最多11GB数据)
定价选项2 每服务器每年5千美元   每内核2千-4千美元 每内核7千美元 每内核1.75万美元或每内核每年3.5千美元
定价选项3(包含内存中处理)     每内核7千-1.4万美元 每内核4万美元或每TB 5万美元 每内核7.05万美元

选择最适合自己的

从上表中可以发现,RDBMS的选择并不像想象中那么容易。免费的数据库固然很有吸引力;-),但一些问题使其无法用于生产环境。老实说,如果能忽略价格,我肯定会选择上述一种商用RDBMS来使用(也许会选择DB/2或Oracle)。然而就算“标准”、“Express”之类版本的商用RDBMS,价格也显得非常高,对于企业级的版本,简直有些高得让人无法接受??,实际上通常我们并不需要这些产品??。

因此如果要开始一个全新的项目,我也许会考虑各种不同选项,并根据项目的具体需求权衡利弊。

On Cross-RDBMS SQL

对于“我们要使用哪个RDBMS”这样的问题,最可行的回答也许就是:“哪个都行”??。这是个很有趣(并且很可行)的选项,为此我们需要确保自己的SQL语句可以跨越不同RDBMS使用。

*所有*RDBMS供应商都在努力实现供应商锁定,并且通常都会成功

虽然可以编写与具体RDBMS无关的SQL语句,但通常来说这样做的难度会介于“相当难”和“十分难”之间??(在我看来,远比编写跨平台C++更难,而C++本身就够难着手了)。如此难的主要原因在于所有RDBMS供应商都在努力实现供应商锁定,并且通常都会成功??。如果你向负责数据库的同事询问这类夸RDBMS的方法,他们有99%的可能性会让你别犯傻了,为啥放着<他们自己所熟悉的任何RDBMS产品>那么棒的功能不用。

作为各类供应商锁定做法始终不渝的反对者,我非常提倡跨RDBMS SQL(并且已经获得了不错的成绩)。然而这毕竟不是决定项目生死的问题,具体怎样做还要由你来决定。所有跨平台的做法面临着一个共同的情况:一开始很痛苦,但长远来看终究会让你获益。

如果你也打算朝着这个方向努力,需要注意一些重要的常见问题:

  • 不要使用存储过程(Stored procedure) – 不同供应商的做法完全不同。你可以通过应用级别的“数据库服务器”将数据库与应用隔离,并且实际操作远比听上去简单很多(妥善规划的语句通常可实现极为类似的性能)。
  • 不要使用触发器。大部分情况下并不需要它们(虽有例外,但很罕见也很少见)。
  • 不要使用自动增量之类的措施[5]
  • 不要使用特定供应商专有的功能(最常见的例子是CURRENT_TIMESTAMP/CURRENT TIMESTAMP/getdate()/Now())。

另外,无论负责数据库的那帮人怎么跟你说,具体供应商专有的扩展都不是获得更高性能所必需的。

最后同样重要的是,对SQL绑定(Binging)进行编译(下文将进行介绍,出于很多原因考虑这都是一种很好的做法)可以对跨平台SQL的实现提供巨大的帮助。

免费数据库也不错

跨平台SQL姑且不谈,看看都有哪些选项吧。最主要的方法是使用免费的RDBMS。

如果为OLTP应用使用免费的RDBMS,我更愿意选择MySQL+InnoDB而非Postgres。在我看来,有关Postgres的设计决策更适合读取密集型工作负载而非写入密集型负载,有报道Postgres面对写入密集型OLTP环境存在严重的性能问题。另外根据第三方报道,很多非常大型的公司(例如Skype)已经成功使用PostgreSQL运行了非常的规模的负载,因此在OLTP应用中使用Postgres是非常可行的。

另一方面我要说的是,如果将MySQL用作OLTP数据库,生产环境中的运行并不像你想象的那么简单,尤其是为表添加新字段是一种相当繁琐的操作(但也是可以实现的)。

关于RDBMS还有个问题需要注意:当同一时间有成千上万用户后,任何停机事件都会造成巨大的损失。这方面商用RDBMS通常比MySQL的社区版做得更好(社区版在这方面的改动比商用数据库更频繁,详情可参阅Schwartz的讨论),当然也比Postgres做得好(例如可以参阅Klitzke有关间歇性数据不一致问题的抱怨)。如果选择MySQL企业版,其实从价格方面考虑已经和另一个竞争者Microsoft SQL Server的价格相差无几了(如果要在不考虑价格的前提下从这两者中做选择,我更愿意选择至少为OLTP使用SQL Server)。

Microsoft SQL Server,以及更多Microsoft SQL Server产品

Microsoft SQL Server的定位恰巧位于两个极端(免费的数据库,极为昂贵的DB/2和Oracle)之间。很多实际用例中,用户会出于稳定性(24x7连续运行)和价格的折衷而选择更显合理的SQL Server。

这样的搭配(总成本约为4万-8万美元)通常可以应对同时访问的成千上万个用户

如果选择SQL Server,也许可以首先从免费的SQL Server Express着手(并在数据库容量超过不怎么大的“10GB上限”之前继续使用),随后可以考虑为OLTP购买SQL Server Standard的4内核许可,并随着需求的增加为报表副本购买2个8内核许可。这样的搭配(共20个内核的许可,总价格约为4万-8万美元)通常可以应对同时访问的成千上万个用户。如果预算允许,这将是一种非常可行的选项。

但我想强调的是,从功能和可靠性的角度考虑(暂不考虑SQL Server过去20年来脱胎换骨的改进),我依然不认为MS SQL Server可以成为DB/2和Oracle势均力敌的对手。然而考虑到其价格(相比其他商用产品更便宜),选择SQL Server也是一个适度的妥协。

商用RDBMS OLTP + 基于免费RDBMS的副本

我认为比较可行的第三种方法是,使用商用RDBMS(我个人在使用DB/2时获得了不错的体验)作为OLTP数据库,从个人经验来说,此时最多只需要4个内核。同时依照个人经验,OLTP数据库通常并不大(大部分空间都用来保存历史数据,这些数据其实可以转移到副本中),因此大部分情况下就算为OLTP系统使用免费版RDBMS也是可行的(考虑到各自的局限,免费版DB/2的可行性高于Oracle和SQL Server,但超出免费版限制后DB/2的成本会更高。

如果/当免费版不够用时,通常使用“标准版”、“Express”版OLTP数据库(但并不用于报表副本)也是可以的(至少你已经考虑了成本的问题,而1万-3万美元的成本也并没有高到离谱)。

如果为报表副本使用商用RDBMS(MS SQL Server除外),很可能需要付出更高成本。为了避免这种问题,我们可以使用自行实现的副本,并通过首选RDBMS之外的其他产品运行这些副本(例如Postgres,但有必要进行相应的测试以确保复制写操作负载的处理速度足够快)。

如果不差钱(证交所/赌场):DB/2或Oracle

最后同样重要的是:如果是证交所、银行、赌场的系统,如果不愿意承担任何风险,此时最佳做法是完全使用DB/2或Oracle。这些行业通常很赚钱,DB/2或Oracle的许可成本完全不是问题,并且这些RDBMS也是公认的高负荷OLTP环境最佳选择(并提供了这些环境必须的功能)。然而就算这种环境,大部分情况下Workgroup/SE2版的OLTP数据库也足够了(但也要具体问题绝体分析)。

[[待续……

本文摘自即将出版的图书《Development and Deployment of Multiplayer Online Games (from social games to MMOFPS, with social games in between)》Beta测试版中的第17(f)章。我们还将发布第17(g)章的内容,其中将介绍SQL绑定的“编译”(很多情况下都需要使用该技术))]]

卡通插画作者:Sergey GordeevIRL,来自布拉格Gordeev Animation Graphics

作者“No Bugs” Hare阅读英文原文Choosing RDMBS for OLTP DB

  1. 不考虑MySQL+MyISAM原因在于缺乏对多行ACID事务的支持。
  2. 我没有资格告诉你MariaDB+XtraDB与MySQL+InnoDB有多大差异,也许相差无几,但我也不敢保证。
  3. 至少有Percona提供的解决方案,自行实现是可行的。
  4. 从SQL Server 2012开始,以往的限制似乎已经取消了,参阅:Rusanu
  5. 从MySQL 5.7.4开始。
  6. Express-C版似乎不支持就地重构。
  7. 参阅Randal
  8. 虽然可以通过一些方式修改Postgres的优化器(例如可参阅Postgres.QueryPlanning),但无法针对每查询进行,因此虽然理论上可以实现,但具体过程的麻烦程度远非“太不方便了”那么简单??。
  9. 基于XML的“Profile”?省省吧。类似DB/2中经典的“OR 1=0”这种玩弄优化器的手段只会更糟。
  10. 虽然可通过HOT加以缓解,但效果是否全面尚不明确。
  11. 可视化功能需要额外付费。
  12. Profiler要求至少使用SQL Server Standard。
  13. MEMORY存储引擎或通过RAM磁盘运行任何引擎的做法缺乏耐久性,不予考虑。
  14. 充当复制主副本的系统至少要运行SQL Server Standard。
  15. 至少需要DB/2 Express(老实说,对于OLTP我强烈推荐Q Replication,该功能要求具备DB/2 Enterprise,有些超范围了)。
  16. 至少需要Oracle SE2。
  17. 至少需要SQL Server Enterprise。
  18. 需要DB/2 Enterprise。
  19. 需要Oracle Enterprise。
  20. 有付费支持的选项。
  21. 15年前SQL Server运行崩溃的情况远远高于已经较为成熟的DB/2和Oracle,然而在这之后MS SQL逐渐迎头赶上。现在具体情况如何,大家各持己见。
  22. 我比较好奇的是,DB/2营销团队需要用多长时间才能意识到因为价格问题,他们已经流失了大量新客户?
  23. 注意:DB/2未提供公开的售价信息??,详情需要联系经销商,但具体金额是可以谈的。
  24. Oracle的定价是“每处理器”的,但对于比较新的x64 CPU,“处理器”等同于“内核”。
  25. 对单一写入数据库连接应用来说这完全不算问题,最新值可以很轻松地进行缓存。

感谢木环对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT