[关闭]
@liuhui0803 2016-11-20T03:05:50.000000Z 字数 16668 阅读 2930

为OLTP选择适合的RDMBS

数据库 设计 系统架构


【负责发布的编辑请注意:本文内容包含较多脚注,可能是作业部落的Bug,脚注的显示顺序和编号被弄乱了,但实际上每个脚注的内容、链接和顺序是正确的,发布前还请酌情调整】

摘要:

我们经常需要为OLTP(事务/运营)数据库选择适合的RDBMS,决策过程中需要考虑哪些注意事项?市面上不同的RDBMS产品哪个最适合自己?

正文:

此处输入图片的描述

[[本文摘自即将出版的图书《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处理角度来说,我曾经见到过:

另外有必要注意,如果使用了单一写入连接(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不间断运行有关(例如游戏服务器,总得全天候运行对吧)。这些功能包括:

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

性能

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

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

SQL编译器的提示

人类从不以史为鉴,这本身就是最重要的“鉴”。
— 奥尔德斯·赫胥黎 —

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

为解决此类(以及其他类似)灾难,人们发明出一种所谓的“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提供了内存中处理功能。这些功能主要可分为两类:

然而非持久内存中处理技术通常并不适合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的许可情况分析如下。
首先是几个备注:

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基本类似,但存在下列差异:

是否可以将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最为重要的特性均使用了粗体字 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(并且已经获得了不错的成绩)。然而这毕竟不是决定项目生死的问题,具体怎样做还要由你来决定。所有跨平台的做法面临着一个共同的情况:一开始很痛苦,但长远来看终究会让你获益。

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

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

最后同样重要的是,对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] 对单一写入数据库连接应用来说这完全不算问题,最新值可以很轻松地进行缓存。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注