审校:李浩、宇亭
设计:Yeekin
责编:宇亭
导语
摘要
一、简介
-
成本问题 :维护成本会随着代码行数线性增长,甚至增长得更快。 -
兼容性问题 :所有的应用都必须能够支持每一行代码。 -
销售问题 :销售人员不知道该向顾客推销哪种产品。 -
营销问题 :如果使用多行代码,那么每一行代码必须有清晰、准确的市场定位。
二、数据仓库
众所周知,仓库应用使用位图索引可以运行得更好,而 OLTP 用户则更倾向于使用 B-tree 索引。产生这种差异的原因很简单:位图索引在仓库工作负载上更快、更紧凑,但在 OLTP 环境中则收效甚微。因此,许多供应商在其 DBMS 产品中同时支持 B-tree 索引和位图索引。
另外,物化视图在仓库环境中是非常有效的优化策略,但在 OLTP 环境中却毫无作用。OLTP 环境更适合使用普通视图(也称为虚拟视图)。
概括来讲,大多数供应商都有一个仓库型的 DBMS 和一个 OLTP 型的 DBMS。仓库型的 DBMS 使用位图索引、物化视图、星型模式以及针对星型模式查询的优化策略,OLTP 型的 DBMS 则 B-tree 索的引和一个标准的基于成本的优化器。二者由一个通用的解析器连接起来,如图2所示。
图2: 当前的 DBMS 架构
请先看图2中的例子。此例中,两个系统共用同一个用户界面(user interface)。这就给大家造成了一种假象:“One Size Fits All”具有可行性。接下来我们看看在流处理市场中,多个系统共用同一前端的想法是多么的不切实际。在这个市场中,不仅会有不同的引擎,而且会有不同的前端。“One Size Fits All”的可行性假象将会在这个市场中被无情的戳破。
三、流处理
最近,研究界兴起了流处理应用的兴趣【7、13、14、20】。这种兴趣的来源于市场对未来几年内传感器网络的商业可行性的预期。虽然射频识别技术(Radio Frequency Identification,RFID)最近受到了所有媒体的关注,并将在零售行业中的供应链优化应用中得到广泛使用,但还有许多其他技术(例如 Lojack【3】)值得我们关注。大量低成本传感器设备的使用给人们的生活带来了翻天覆地的变化,也衍生出了监控应用这个新兴市场。许多行业专家将眼光投向了这片蓝海。
#3.1 传感器应用的兴起
传感器网络技术在军事领域有着广泛应用。例如,美国陆军正在研究在所有士兵身上安装生命体征监视器,从而可以实现在战时优化医疗分类。许多军用车辆中已经安装了 GPS 系统,但这些 GPS 系统之间尚未连接形成一个闭环。而陆军希望能够监控到所有车辆的位置,实时识别出哪些车辆偏离了路线。在炮塔上安装传感器也列入了考虑范围。这样再加上位置信息,陆军就能检测到交火情况。另外,如果在汽油表上安装传感器,就可以实现优化加油。总之,一个由30,000人和12,000辆车组成的军营很快将会被一个由几十万个节点组成的大规模传感器网络所覆盖。这个网络需要实时传送车辆状态和位置信息。
这就要求网络中的处理节点和下游服务器必须能够处理这种“流水”数据。必需操作包括复杂的警报(例如,“排里的4辆车,什么时候有三辆车进入到前线?”)、历史查询(例如,“在过去的两个小时内,编号12的车辆去了哪里?”)、以及纵向查询(例如,“部队现在的总体准备状态是什么?”)。
随着时间的推移,基于传感器的监控应用会逐渐出现在非军事领域中,比如交通拥堵监控以及旅游路线推荐。还有一个和军事领域相似的应用:可变的、基于拥堵的高速公路系统收费系统。这个应用的灵感来源于《线性道路基准(Linear Road Benchmark)》【9】。游乐园将很快使用传感器来取代顾客使用的普通腕带,这样不仅可以优化游乐设施还可以定位走丢的小朋友。手机早已活跃于人们日常生活中。我们可以幻想有这么一个服务可以为饥肠辘辘的用户定位到最近的餐馆。甚至是图书馆里的书籍也可以被贴上带有传感器的标签。这样就不用担心被放错书架的书本难以找回了。
人们推测,传统的 DBMS 将不再适用于这种新型的监控应用。事实也是如此。根据线性道路基准来测试,传统解决方案比专用流处理引擎慢了近一个数量级【9】。传统的 DBMS 技术不适用于流应用。当前流数据应用领域的研究也论证了这个观点。接下来我们将分享一个我们在处理金融信息流(financial feed)的应用上的经验。
#3.2 一个现有的应用:金融信息流处理
虽然这个示例应用只是实际生产系统中使用的应用逻辑的一个子集,但它代表了一个易于指定的任务,其性能很容易被测量,因此极具代表性。现在我们来对比下这个示例应用在流处理引擎上和关系型 DBMS 上的速度。
四、性能对比
上一章中讨论的示例应用是在 StreamBase 流处理引擎【5】中实现的,它基本上可以看作是Aurora 【8,13】的商业、工业级版本。我们使用的2.8 Ghz 奔腾处理器规格为512 MB 内存,拥有一个 SCSI 磁盘。在 CPU 饱和之前,图3中的工作流可以以每秒160,000条消息的速度执行。相比之下,StreamBase 的工程师使用主流的商业关系型 DBMS 实现同一个应用时,每秒只能处理900条消息。
在本章中,我们将讨论造成这种性能差异的主要原因。正如我们下面即将讨论的,差异的产生与入站处理模型、正确的流处理原语以及 DBMS 处理与应用处理的无缝集成有关。另外,我们还考虑了另一主要因素:事务性操作。
#4.1 “入站”与“出站”处理
我们称之为“出站”处理的流程是 DBMS 模型的基本组成流程,如图4所示。具体可分为三步:
1. 将数据插入(updates)数据库。
2. 为数据创建索引并提交事务(pull processing),从而后续步骤可以使用该数据。
3. 将处理结果(results)呈现给用户。
这种“存储后处理(process-after-store)”的模式是所有传统 DBMS 的核心,毕竟 DBMS 的主要功能是接收数据并保证数据不会丢失。
图5:“入站”处理
当然,也许有人会问“DBMS 能支持入站处理吗?”DBMS 最初被设计为出站处理引擎,但是在多年以后才想到将触发器移植到它们的引擎上进行补救。使用触发器存在许多限制,比如每个表允许使用的数量。另外,使用触发器的安全性没法保证,我们无法确保触发器不会进入无限循环(infinite loop)中。总体看来,关于触发器的编程支持少之又少,甚至于没有。例如,用户无法查看到应用中存在哪些触发器,也无法通过图形用户界面将触发器添加到表中。此外,DBMS 为常规表提供了虚拟视图和物化视图,但却不为触发器提供。最后,触发器在现有引擎中经常会出现性能问题。当 StreamBase 的工程师尝试在信息流告警应用(feed alarm application)中使用触发器时,仍然无法实现高于每秒900条消息的性能。总之,触发器作为现有设计中的“外来者”,在当前的系统中处于二等公民的地位。
因此,关系型 DBMS 其实质是出站引擎,仅有限地提供一些入站处理能力。相比之下,Aurora 和 StreamBase 之类的流处理引擎基本上是入站处理引擎。入站引擎与出站引擎是完全不同的。例如,出站引擎使用“拉取(pull)”处理模型,即:当一个查询被提交之后,由引擎来实现从存储中高效拉取满足查询的记录。相反,入站引擎使用“推送(push)”处理模型,即当一个查询被提交之后,由引擎来按照应用中指定的处理步骤来高效地推送传入消息(incoming message)。
出站引擎和入站引擎还有一个很大的区别。出站引擎先存储数据然后根据存储的数据执行查询。而入站引擎恰好相反,入站引擎先存储查询,然后通过查询传递传入消息。
很明显,构建一个同时拥有出站和入站引擎能力的引擎是拥有可行性的也是值得研究的。同时,DBMS 针对出站处理进行了优化,而流处理引擎则针对入站处理进行了优化。在信息流告警应用中,这种原理上的差异是造成我们观察到的性能差异的主要原因。
#4.2 正确的原语
SQL系统包含一个复杂的聚合系统,用户可以通过该系统对数据库表中的记录分组进行统计计算。下述代码提供了一个标准的示例:
Select avg (salary)
From employee
Group by department
在信息流告警应用中,每个窗口为两个 tick,但 tick 有超时设置,超时时间为5秒或60秒。如果两个连续 tick 之间的间隔时间超过用户定义的超时阈值,对应窗口将会被关闭。超时设置能够有效地发现滞后数据,这算是高度调整的集合逻辑所带来的一个意外之喜。在示例应用中,每个聚合后的框在丢弃掉有效数据之后,只保留超时消息。应用的其他部分对这些超时执行必要的分类记录(bookkeeping)。
系统底层使用正确的原语可以实现非常高的性能。相比之下,关系型引擎不包含这样的内置结构。用传统的 SQL 模拟这种内置结构的效果不仅繁冗复杂,并且导致了第二个显著的性能差异。
SQL 支持添加时间窗口,但是这样做对存储的数据没有任何意义。因此,窗口构造必须集成到某种入站处理模型中。
#4.3 DBMS 处理和应用逻辑的无缝集成
-
DBMS 处理,例如聚合和过滤框(filter box) -
控制逻辑,用于将消息导向正确的下一个处理步骤 -
应用逻辑
图6:Count100 的逻辑
实际上,信息流告警应用混合了 DBMS 风格的处理、条件表达式和传统编程语言中的自定义函数。StreamBase 在单个地址空间内执行这种组合,无需进行任何进程切换。Rigel【23】和 Pascal-R【25】在多年前就提出了这种将 DBMS 逻辑与传统编程工具无缝集成的设想,但从未在商业化的关系型系统中实现。
取而代之的是,主流供应商实现了存储过程,这是一个非常有限的编程系统。最近,市场上出现了使用对象-关系(object-relational)引擎的刀片服务器和扩展程序,它们比存储过程更强大,但仍然不支持灵活的控制逻辑。
嵌入式系统不需要 C/S 架构的 DBMS 进行保护,这种两层架构只会造成更大的开销。这是造成我们观察到的性能差异的第三个原因。
另一个集成问题是流式应用中状态信息的存储。信息流告警应用不涉及该问题。大多数流处理应用都需要保存一些状态信息,小到几 MB,大到几千 GB。这些状态信息可能包括:1. 参考数据(即,市场对哪些股票感兴趣);2. 转换表(以防不同信息流来源使用不同的符号代表同一股票)3. 历史数据(例如,“在去年中,每天观察到多少个滞后 tick?”)。因此,大多数流处理应用都要求对数据进行表格式存储。
StreamBase 在 BerkeleyDB 中内嵌了状态存储功能【4】。然而,在 StreamBase 地址空间中调用 BerkeleyDB 和在不同的地址空间中以 C/S 模式调用 BerkeleyDB 之间存在大约一个数量级的性能差异。这也是为何要在一个地址空间中混合 DBMS 和应用处理来避免进程切换的另一个原因。虽然有人可能会建议通过增强 DBMS 的编程模型来解决这个性能问题,但是 DBMS 采用 C/S 模型有其必要性,因为大多数业务数据处理应用需要这种模型来提供保护。存储过程和对象-关系刀片都是一种将部分客户端逻辑移至服务端以提高性能的尝试。为了更进一步,DBMS 必须实现一个嵌入式和一个非嵌入式模型,并且这两个模型使用不同的运行时系统(runtime system)。这种做法等同于放弃了“One Size Fits All”策略。
相反,信息流处理系统都是嵌入式应用。应用和 DBMS 的作者是相同的,并由外部数据源驱动,而非由人工输入的事务驱动。因此,没有理由针对应用给 DBMS 提供保护,且二者在同一地址空间运行是完全可以接受的。在嵌入式处理模型中,对应用逻辑、控制逻辑和 DBMS 逻辑进行自由混合是合理的,而 StreamBase 也确实完成了该实现。
#4.4 高可用
许多基于流的应用都要求高可用性和24/7不间断运行。标准 DBMS 日志记录和崩溃恢复机制(例如【22】)不适合流数据市场,主要原因如下:
首先,基于日志的恢复可能需要几秒到几分钟。在此期间,应用将被“关闭”。这种行为在许多实时流领域(例如,金融服务)中显然是不能接受的。第二,如果系统崩溃,必须采取措施来缓冲传入数据流,否则这些数据将在恢复过程中永久丢失。第三,DBMS 恢复将只处理表格状态,忽略了操作员(operator)状态。例如,在信息流告警应用中,计数器并未存储在表格中。如果系统崩溃,计数器的状态信息将会丢失。一个简单的解决方法是将所有操作符状态强制转换到表中,使其适用于 DBMS 风格的恢复;但是,这种解决方案会大大降低应用的速度。
一个常见的高可用替代方案是使用依赖于串联式进程对(Tandem-style process pair)【11】的技术手段。该替代方案的基本思路是,在系统崩溃的情况下,应用通过故障恢复,恢复到备机(backup machine)上运行。备机通常以“热备(hot standby)”方式部署,并和主机(active machine)之间保持极小的时延。这种方法免除了日志记录的开销。再以 StreamBase 为例,StreamBase 关闭了 BerkeleyDB 中的日志记录。
与需要精确恢复以确保正确性的传统数据处理应用不同,许多流处理应用可以容忍并能受益于没那么严格的恢复概念。换句话说,故障恢复并不总是需要“完美”的。监控应用操作的数据流的值会被定期刷新。如果由于系统崩溃造成的业务终端时间很短,这种程度的元组丢失对于监控应用而言通常是可以容忍的。即,如果在故障恢复期间丢失了信息流告警应用中的几个 tick,正确性可能仍然可以保障。相比之下,一些用于在某些事件组合发生时触发告警的应用则要求没有元组丢失,但可以容忍短暂的重复。例如,患者监控应用可能能够容忍元组重复(“心率是79”),但不能容忍元组丢失(“心率已经变为零”)。当然,总有一类应用需要强大、精确的恢复保证,例如基于单个股票交易执行投资组合管理的金融类应用。
因此,当应用对准确性要求不那么严格的时候,可以考虑采用低开销的简化版的故障恢复方案。近期出现了很多关于如何在流领域实现高可用的详细研究【17】。
# 4.5 同步
许多基于流的应用依赖于共享数据和计算。共享数据通常包含在一个表中。有的用户会查询表中的更新,而有的仅读取数据。例如,线性道路应用要求使用车辆位置数据来更新高速公路使用情况的统计数据,然后读取这些数据来确定高速公路上每个路段的过路费。因此,消息隔离是一个基本需求。
传统的 DBMS 使用满足 ACID 属性的事务来实现多个用户之间提交的并发事务的隔离。在非多用户的流系统中,这种隔离可以通过简单的临界区(critical section)有效地实现,临界区可以通过轻量级信号量(semaphore)来实现。由于完全符合 ACID 属性的事务不再是必需,使用重量级基于锁的机制也并非必要。
总之,大多数流处理应用不需要 ACID 属性,因此可以使用更简单、更专业的性能结构。
五、One Size Fits All?
上一章已经指出了一系列造成专用流处理引擎和传统 DBMS 之间的性能差异的架构因素。这些设计上的不同选择同时还导致了两种引擎之间巨大的内部差异。事实上,StreamBase 使用了完全不同于传统的 DBMS 的运行时代码。这样做的结果是大大提高了一类实时应用的性能。这些考量将导致针对流处理使用单独的代码,当然产生这种情况的前提是市场足够大。
在本章中,我们概述了其他几个市场。这些市场有着一个共同点:有专用数据库引擎的潜在需求。
# 5.1 数据仓库
在第2章中我们讨论到的 OLTP 和仓库数据库系统之间的架构差异只是冰山一角,随着时间的推移,二者之间会产生更大的差异。接下来我们讨论下我们可能关注到的最大的架构差异:列式存储和行式存储的选择。
#5.2 传感器网络(Sensor networks)
传感器网络中的处理节点用于管理网络的传感器。而在这些处理节点上运行传统 DBMS 是一个不切实际的想法。这些新兴的设备网络平台的应用正在被探索中,包括、环境和医疗监控、工业自动化、自主机器人团队和智能家居【16、19、26、28、29】。
为了能在通信和能源领域开发出这些系统的全部潜力,组件被设计成无线的。在这种环境下,带宽和功率成为需要省着用的关键资源。此外,与处理或存储访问相反,通信是能源的主要消耗者。因此,标准的 DBMS 优化策略并不适用,需要另寻突破口。事务处理能力也并未纳入仓库系统的考虑范围。
一般来说,仓库系统需要设计灵活、轻量级的数据库抽象(如 TinyDB【18】),针对数据移动进行优化,而不是数据存储。
#5.3 文本搜索(Text search)
目前的文本搜索引擎都没有使用 DBMS 技术进行存储,即使它们处理的是海量的、不断增长的数据集。例如,Google 构建了自己的存储系统(称为 Google File System,GFS【15】),它的性能优于传统的 DBMS 技术以及文件系统技术。产生这种性能优势的原因我们已经在第4章中讨论过了。
一个典型的搜索引擎工作负载【12,15】由需要清洗并合并到现有搜索索引中的入站流数据(来自网络爬虫)和现有索引上的即席查找(ad hoc look-up)操作组成。尤其是,大多数写操作只涉及数据追加(append),而大多数读操作都是顺序读(sequential read)。对同一文件的并发写(即追加写)是获得良好性能的必要条件。最后,由商品零件组成的大量存储机器确保了故障是常态而非例外。因此,高可用是设计考虑的一个关键因素,并且只能通过快速恢复和复制来实现。
可以很明显的看出,这些应用的特征与传统的业务处理应用有很大的不同。这样就导致即使一些 DBMS 具有内置的文本搜索能力,但却过于笨重、不灵活,依然无法满足这个领域对于性能和可用性的要求。
#5.4 科学的数据库(Scientific databases)
各种类型的传感器不断地收集大量数据,这些传感器连接着卫星和显微镜等设备,或者由高分辨率科学和工程人工模拟生成。
关于这类数据集的分析能够帮助我们更好地了解物理现象,并且在许多科学研究领域变得越来越普遍。对这些庞大数据库的有效分析和查询需要高效的多维索引结构和特定应用的聚集技术。此外,对高效的数据存档、分级、沿袭和错误传播技术的需求可能会在这个重要领域中产生对另一个专用引擎的需求。
#5.5 XML 数据库(XML databases)
半结构化数据无处不在。但是这类数据不能立即适应关系模型。关于怎么存储和操作 XML 数据才是最好的方式存在着巨大的争议。尽管有些人认为关系型 DBMS(带有适当的扩展)是可行的,但其他人会认为需要一个专门的引擎来存储和处理这种数据格式。
大多数流应用需要以下三项基本服务:
消息传输: 许多流应用要求数据能在多个分布式机器间高效、可靠地进行传输。原因有三:第一、数据源(source)和传输的目的地(destination)通常在地理上是分散的。第二、高性能和高可用要求使用多台服务器。第三、几乎所有大型企业系统都是一个嵌入了 SPE (单对以太网,single-pair Ethernet)的复杂业务应用网络,而这些应用分散运行在大量的机器上。因此,来自外部应用的输入和输出消息在经过 SPE 时需要正确地路由到恰当的其他外部应用中
状态存储:如4.3节所述,除了最简单的应用之外,所有应用都需要存储状态。状态通常存储在只读引用表、只读历史表以及读写变换(read-write translation, 如哈希)表中。
应用逻辑的执行:许多流应用要求特定域的消息处理中穿插查询。一般来说,仅使用内置查询原语来表示这种应用逻辑既是不可能的也是不现实的,比如通过解读遗留代码。
流处理应用的传统设计将整个应用逻辑分布在三个不同的系统中:
1. 消息传递系统(例如 MQSeries、WebMethods 或 Tibco):将各组成系统可靠地联系起来,通常使用发布/订阅范例;
2. DBMS(如 DB2 或 Oracle):保证状态信息的持久性;
3. 应用服务器(如 WebSphere 或 WebLogic),为一组定制编码的程序提供应用服务。图7展示了该种三层配置的架构。
图7:多层流处理架构
这种将所需功能分散在三个重量型系统软件上的设计在性能上却不尽如人意。例如,每个需要查找状态和应用服务的消息都需要在这些不同的服务之间进行多次切换。
为了说明每条消息的开销,我们来看看消息处理时涉及的步骤。在步骤1中,传入的消息首先经过总线,被总线转发给自定义应用代码,后者清理并处理该消息。如果消息需要与历史数据相关联或者需要访问持久数据,那么则会进行步骤2和3,向 DB 服务器发送一个请,DB 服务器会访问 DBMS。步骤4和5描绘了请求响应路径,方向和应用代码路径刚好相反。在最后一步(步骤6)时,消息处理后的结果被转发到客户端的任务 GUI。总的来说,处理一条消息涉及6次“跨界(boundary crossing)”。除了引发明显的上下文切换之外,每次从消息总线中提取消息并传递到消息总线时,还需要使用恰当的适配器将消息即时地转换为系统的本机格式或从系统的本机格式转换为目的端格式。这就导致了极低的有效工作:开销比(useful work:overhead)。即使对消息进行一定程度的批处理,开销也依然很大并且限制了系统的性能实现。
为了避免这种性能损失,流处理引擎必须在一个系统软件中提供所有三种服务,该软件在其运行的每台机器上作为一个多线程进程执行。因此,SPE 必须具有 DBMS、应用服务器和消息传递系统三要素。实际上,一个 SPE 应该“在一个屋檐下”提供所有三种软件的功能。
这一观察提出了这样一个问题,即当前将系统软件分解成组件(例如,应用服务器、DBMS、ETL 系统、消息总线、文件系统、web 服务器等)的做法是否是最优解。毕竟,这种特殊的分解方案一部分是历史产物,而另一部分则是偶然的营销事件。这样看起来系统服务的其他分解方案似乎也是合理的。这也意味着组件定义和分解在未来将迎来巨大的发展。
七、结束语
加入微信群:添加社区助理-小石侠;加入钉钉群:扫描下方钉钉群二维码。开源之夏活动火热报名中,感兴趣的同学可以添加小助手微信回复“开源之夏”,拉您进活动专属群。
StoneDB 亮相 2023 数据技术嘉年华(DTC 2023)
点击阅读原文,给 StoneDB 点个 Star 鼓励一下吧~
本文分享自微信公众号 - StoneDB(StoneDB2021)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。