翻译:王学姣
审校:李浩,宇亭
责编:宇亭
导 语
本篇是StoneDB学术分享会专栏的第六篇,在上一期里,我们分享了奠定 HTAP 数据库基础的现象级论文《A Common Database Approach for OLTP and OLAP Using an In-Memory Column DataBase》,如果说,上一期 SAP 在 2009 年的论文只是初步的提出了一个看起来很强悍并且可行的理论,那么三年后,SAP 在 2012 年发表的这篇《The SAP HANA Database – An Architecture Overview》,则用一个实打实的架构体系向世界宣布了一体化 HTAP 数据库——SAP HANA 的强大(我们已经不是吹概念了,而是实现了有木有,直接给全世界看我们的架构体系啦~)
这下子,信仰“One Size Doesn't Fit All”的学者和商业团队们可慌了神,说好的,OLAP 数据库和 OLTP 数据库要分开卖的呢?你们 SAP 怎么这么不讲武德啊?一个内存数据库非要来抢我们两个派系的生意?
不过,市场并不会接受吐槽,SAP HANA 以其高水平的研发团队、极致的性能和独特的营销技巧在数据库行业开始异军突起~
摘要
随着企业发展,企业级应用对数据库的要求变得越来越严苛。这些应用程序要求数据库系统能基于事务数据生成复杂的报告,且要保证多达上万的用户能够同时对相同数据进行读取、更新操作。SAP HANA 数据库旨在使用一个数据库管理系统****同时处理事务性和分析性工作负载 。 为了实现这一目标,我们设计了一个列存引擎。该列存引擎利用现代硬件(多 CPU 内核、大容量主内存和缓存),支持数据压缩、数据库内核并行最大化,提供层次结构(hierarchy)专用的数据结构、用于特定领域的语言支持等企业应用所需的数据库扩展。在本文中,我们将重点介绍 SAP HANA 数据库的架构。我们还会公布在真实的企业应用场景中通过 SAP HANA 数据库收集的反馈和洞察。
简介
关于企业数据的全方位解读已经成为每个企业的核心资产(小编注:这就是数据价值)。企业数据通过各种渠道,如以 SAP ERP 为代表的企业资源规划系统、生产环境中使用的传感器或 Web 界面,成批或逐笔输入。举个例子,销售过程中会产生订单创建、修改和删除等操作。这些订单是生产计划和交付的基础。因此,销售过程往往会针对记录进行查找、插入和更新操作。这类数据处理通常被称为联机事务处理(Online Transaction Processing,OLTP) 。OLTP 是当前基于磁盘(disk-based)的行存(row-oriented)数据库系统的强项。(小编注:MySQL 就是这种基于磁盘和行存的 OLTP 数据库)
根据我们的仔细观察,一个看似非常简单的销售过程可能包含大量复杂的分析处理。例如,作为销售流程的一部分,检查交付产品的可用性需要汇总预期销售额、预期交付量和生产批次的完成情况,以及将最终库存与客户需求进行比较。类似地,销售组织将对基于最近的销售和成本信息生成的盈利能力度量指标感兴趣,因为这个指标方便他们进行销售策略的规划。以上这类工作负载被认为是联机分析处理(Online Analytical Processing,OLAP) 。通过将数据复制到读取优化的数据仓库中,可以执行周期性任务,如季度末结算或客户细分。对于这些类型的报告,列存(column-stores)变得越来越流行[3]。
此外,分析型应用需要过程逻辑,而过程逻辑,例如根据销售数量对不同产品进行聚类(clustering)或对客户行为进行分类,并不能用简单的 SQL 来表达。常规的做法是将所有需要的数据从数据库转移到应用上,然后在应用上进行处理。因此,优化的数据结构和元数据不能被使用,而且如果后续业务流程需要用到相关中间结果,中间结果还必须回传到数据库中。
理想情况下,数据库应该能够在单个系统中处理所有上述工作负载和特定应用(Application-specific)的逻辑[13]。这一发现促使了我们开发了 SAP HANA DB。SAP HANA DB 的 In-Memory 列式存储基于 SAP TREX 文本引擎[15]和 SAP BI 加速器(SAP BIA)[10],可快速处理 OLAP 查询。SAP HANA DB 的高性能 In-Memory 行式存储源自专为 OLTP 工作负载而设计的 P*Time[2]。SAP HANA DB 的持久性则来源于 SAP MaxDB 数据库系统的成熟技术,包括日志、恢复和持久存储特性。截至目前,SAP HANA DB 已作为 SAP HANA 设备的一部分上市。
在第2章中,我们将简要介绍 SAP HANA DB 架构中的各组件。第3章讨论了执行分析型应用特定逻辑的能力。第4章简述了 SAP HANA DB 如何实现传统数据仓库工作负载加速处理。我们在第5章讨论了如何应对企业资源规划系统中事务型工作负载的挑战,并在第6章总结了我们在 SAP HANA DB 上的工作。
SAP HANA DB 架构
SAP HANA DB 的总体目标是提供一个以内存为中心的数据管理平台,以支持传统应用的纯 SQL,以及一个更具表现力的交互模型,专门用于满足 SAP 应用的需求[4,14]。此外,该系统被设计为提供完整的事务行为,从而实现对交互式业务应用的支持。最后,SAP HANA DB 的设计特别重视并行化,从线程级并行、到内核级并行、再到跨机器的高度分布式设置。
图1:SAP HANA DB 架构概述
图1展示了的 SAP HANA DB 架构。SAP HANA DB 的核心是一组 In-Memory 处理引擎。在行列混存引擎中,关系数据存储在采用列布局或者行布局的表中,并且可以从一种布局转换到另一种布局,以允许查询表达式包含两种布局的表。图形数据和文本数据则分别存储在图形引擎和文本引擎中。得益于可扩展的架构,SAP HANA DB 还能支持更多的引擎。只要可用空间足够,所有引擎都会将所有数据保存在主内存中。SAP HANA DB 一个特有特性是所有数据结构都针对缓存效率进行了优化,而不是针对传统磁盘数据块的组织形式进行优化。此外,这些引擎采用了多种多样的压缩方案来实现对数据的灵活压缩。当可用主内存达到最低阈值时,在应用语义的控制下,表或分区等整个数据对象会从主内存中卸载掉,并在再次需要时重新加载至主内存中。
从应用的角度来看,SAP HANA DB 提供了多种接口,例如用于通用数据管理功能的标准 SQL,或者 SQLScript(参见第3章)和 MDX 等更专业的语言。SQL 查询由计划生成器翻译成执行计划,然后由执行引擎进行优化和执行。来自其他接口的查询最终也被转换为相同类型的执行计划,并在相同的引擎中执行,但首先会在计算引擎中用更具表达力的抽象数据流模型来进行描述。执行引擎无需考虑外部接口,可以使用所有处理引擎并且支持跨节点分布式执行。
为了保证高性能,几乎所有数据都由处理引擎保存在主内存中,但是数据也必须持久化至数据持久层,以便在系统显示关闭或出现故障后重启时进行备份恢复。 数据更新按需记录日志,以便数据能够恢复到数据库的最后提交状态。并且在保存点(savepoint)和合并操作期间,整个数据对象定期持久化保存至数据存储(data storage)中(详情请参见第4章)。
支持分析型应用
SAP HANA DB 的一项关键资产是其在数据库内核中执行业务和应用逻辑的能力。为此,计算引擎提供了计算模型。计算模型是逻辑执行计划的抽象表达。比如我们将 SQLScript 编译到了计算模型中。SQLScript 是一种用于将应用逻辑表示为数据流或使用过程逻辑的声明性和可优化语言。沿着这个思路,只要是编译器能够生成中间计算模型表示的应用于特定领域的语言,我们都可以提供支持。
计算模型的原语构成了一个逻辑执行计划。该计划由一个非循环数据流图形组成,图中的节点表示操作符(计划操作),途中的边缘反映数据流(计划数据)。SAP HANA DB 使用了一类操作符来实现标准的关系操作符,如连接(join)和选择(selection)。此外,SAP HANA DB 支持多种特殊运算符,用于在数据库内核中实现针对特定应用(application-specific)的组件。几乎所有这些操作符都只能加速数据处理,因为它们利用了列数据布局。而通过在计算引擎中实现特殊运算符,可以实现对多个应用域的支持:
- Statistical Algorithms:可以挂载到计算模型上,从而可以在相关的 R 运行时内执行复杂的统计计算。这包括不同的统计方法,如线性和非线性模型、统计测试、时间序列分析、分类和聚类。同时,计算模型允许利用数据库内核中预处理和后处理大数据的能力,从而将统计算法与数据库操作结合在一起[5]。
- Planning:提供了一组常用的通用计划函数,允许直接在数据库中建模和执行复杂的计划场景。Planning 的逻辑由计算引擎的数据流运算符来进行表达。此外,特殊运算符执行特定的计划算法,如分解和自定义公式[7,8]。
- Other Special Operators:由计算引擎提供,包括需要复杂运算的业务逻辑。这些运算很难使用 SQL 进行有效实现,例如货币兑换。另一个例子是描述诸如企业人力资本管理中雇员和相关信息之间的关系的大型层次结构。在这里,SAP HANA DB 提供了特定应用的操作符,利用可替代的内部数据结构来实现即时返回关于层次结构的查询结果。
特定的计算模型或逻辑执行计划一旦通过 SQLScript 或其他方式提交到 SAP HANA DB,就可以像访问数据库视图一样被访问,从而使计算模型成为一种参数化视图。 使用这种视图的查询会调用数据库计划执行(database plan exectuion)来处理执行计划,而执行计划派生自计算模型提供的逻辑数据流描述。如果计算模型包含独立的数据流路径,则派生的执行计划隐式包含运算符间并行执行(inter-operator parallel execution)。此功能的实现归功于 SQLScript 和编译到计算模型中的特定域的语言。
分析型查询处理
众所周知,列式存储非常适合用于处理对大量数据进行的分析型查询[1]。为了保证读操作的高性能,SAP HANA DB 的列式存储在使用高效的压缩方案之外,还结合了缓存感知和并行算法。每一列都基于排序字典被压缩,即每一个值都被映射到一个整数值(valueID)。此外,这些 valueID 还将进行位压缩(bit-packing)和压缩(compression)。通过游程编码(RLE)、稀疏编码或聚类编码[11,12]等方式对表中的行进行重新排序可以实现对表中的列进行最有效的压缩。数据压缩不仅使得单个节点可以保存更多的数据,同时还可以利用诸如 RLE 进行聚合计算等方式来提升查询处理速度。 通过对直接作用于压缩数据的 SIMD 算法进行极致利用来加速扫描[16]。
由于在描述的布局中,单次更新的开销很大,所以每个表都有一个增量存储(delta storage)用于实现高更新率和高性能读取之间的平衡。我们还使用了字典压缩,但是字典存储在缓存敏感的B+-树(CSB+-Tree)中。增量存储会定期合并到主数据存储(main data storage)中。为了最小化表被锁定的时间,当增量合并开始时,写操作会被重定向到新的增量存储上。在合并完成前,读操作会访问新增量存储、旧增量存储以及就旧主数据存储[9]。
查询执行通过使用操作符内并行性来利用节点内不断增加的可用执行线程数量。 例如,分组操作几乎与线程数量成线性关系,直到 CPU 达到饱和。此外,SAP HANA DB 还利用了查询执行计划内部以及跨内核和跨节点的并行性。大表可以通过各种分区标准进行分区。分区后的各表分区或者整个表可以被分配至环境中的不同节点上[10]。如果运算符可以独立处理,执行引擎会并行调度这些运算符并且尽可能在保存相关数据的节点上执行这些运算符。在工作负载变化的情况下,且数据库支持查询和更新的前提下,表的分区方案以及表至节点的分配可根据工作负载做调整适配。当 JOIN 查询涉及跨节点存储的表时,使用 semi-join reduction(半连接缩减)进行处理[6]。
事务型查询处理
很明显,列式存储非常适合 OLAP 工作负载。并且,我们认为列式存储也同样可以用于处理 OLTP 工作负载,尤其是在 ERP 系统中[9],具体原因如下:
- OLTP 场景可以极大地受益于列式存储中提供的压缩方案:在像 SAP ERP 这样高度可定制的系统中,许多列并没有被使用,只包含默认值或者为空。并且还有一些列具有很小的域,例如状态标志(status flag)。在这两种情况下,数据压缩都非常高效,这对于 OLTP 场景来说是一个决定性的优势:通过减少内存消耗,所需的存储变少,从而减少了节点的开销。此外,压缩还会降低内存带宽使用率。
- 与 TPC-C 等标准基准测试相比,实际场景中的事务型工作负载的读操作比例更大。因此,读优化的面向列的存储布局可能比基准建议更适合 OLTP 工作负载。
- 列式存储通常遵循简单的“仅追加(append-only)”方案:当对一个行进行更新操作时,当前版本失效,并追加新版本。这种方案既不需要重新排序也不需要对值进行编码,比就地更新(in-place update)简单。
- 列式存储极大减少了对索引的需求:事实上,现代硬件上的列式存储的高扫描性能允许我们只为主键、具有唯一约束的列和频繁连接的列建立索引。在其他情况下,即使没有索引,列式存储也能提供足够好的扫描性能,尤其是在多达几十万行的小表或小分区中。其优点包括大大简化了物理数据库设计,减少了主内存消耗,并消除了索引维护工作,从而提高了整体查询吞吐量。
当然,除了上述优势以外,列式存储在处理 OLTP 工作负载时,还面临着以下挑战:一个挑战直接来自基于列的数据布局。尽管基于列的数据布局支持更细粒度的数据访问模式,但为处理大量列而为每一列分配内存会导致显著的性能开销,例如,当构造由100列或更多列组成的单个结果行(result row)时。到目前为止,只要有助于降低性能开销,SAP HANA DB 就会将分配给多各列的内存合并到一起。
作为一个主要挑战,我们看到在 ERP 应用中,大量的更新是并发执行的。与批量更新的数据仓库相反,单个记录的频繁更新会不断地向增量存储中添加新的实体,从而导致了从增量存储到主数据存储的频繁合并。合并操作是 CPU 和内存密集型操作。由此带来的挑战是如何最大限度地减少其对并发处理的请求的影响。SAP HANA 通过精心设计的调度和并行化解决了这个问题[9]。
小结
在本文中,我们总结了 SAP HANA DB 的设计和实施指导原则。我们的分析表明,使用列引擎的 In-Memory 处理是同时处理分析型和事务型工作负载的最有前景的方法。 对业务应用需求和两种工作负载的强大支持使 SAP HANA DB 有别于其他列存储。毕竟,大多数 OLAP 和 OLTP 操作都是读操作,这些操作都将受益于按列进行的数据压缩。此外,列存储仅需要极少量的索引,简化了物理数据库设计并减少了内存消耗。为了进一步将当今企业应用产生的大量数据保存在内存中,SAP HANA DB 允许将数据分布在集群内的节点中。因此,在对大型数据集进行分析处理时,SAP HANA DB比传统数据库系统快几个数量级。
然而,In-Memory 分布式列存储对数据库开发提出了很多挑战,包括对分区的要求、对分布式事务的支持以及将更新合并到读优化的存储布局中的过程设计。但是这些挑战只是冰山一角,因为当我们考虑到云上的数据密集型应用、弹性要求、多租户或科学计算时,更多的挑战还在前方等着我们去解决。
参考文献
[1]D. J. Abadi, S. R. Madden, and N. Hachem. Column-Stores vs. Row-Stores: How Different Are They Really? In Proc. SIGMOD, pages 967–980, 2008.
[2]S. K. Cha and C. Song. P*TIME: Highly Scalable OLTP DBMS for Managing Update-Intensive Stream Workload. In Proc.VLDB, pages 1033–1044, 2004.
[3]S. Chaudhuri, U. Dayal, and V. Narasayya. An Overview of Business Intelligence Technology. CACM, 54(8):88–98, 2011.
[4]F. Fa¨rber, S. K. Cha, J. Primsch, C. Bornho¨vd, S. Sigg, and W. Lehner. SAP HANA Database - Data Management for Modern Business Applications. SIGMOD Record, 40(4):45–51, 2011.
[5]P. Große, W. Lehner, T. Weichert, F. Fa¨rber, and W.-S. Li. Bridging Two Worlds with RICE – Integrating R into the SAP In-Memory Computing Engine. Proc. VLDB, 4(12):1307–1317, 2011.
[6]G. Hill and A. Ross. Reducing outer joins. VLDB Journal, 18(3):599–610, 2009.
[7]B. Ja¨cksch, F. Fa¨rber, and W. Lehner. Cherry Picking in Database Languages. In Proc.IDEAS, pages 117–122, 2010.
[8]B. Ja¨cksch, W. Lehner, and F. Fa¨rber. A Plan for OLAP. In Proc.EDBT, pages 681–686, 2010.
[9]J. Kru¨ger, C. Kim, M. Grund, N. Satish, D. Schwalb, J. Chhugani, P. Dubey, H. Plattner, and A. Zeier. Fast Updates on Read-Optimized Databases Using Multi-Core CPUs. Proc.VLDB, 5(1):61–72, 2011.
[10]T. Legler, W. Lehner, and A. Ross. Data Mining with the SAP NetWeaver BI Accelerator. In Proc.VLDB, pages 1059–1068, 2006.
[11]C. Lemke, K.-U. Sattler, F. Fa¨rber, and A. Zeier. Speeding Up Queries in Column Stores – A Case for Compression. In Proc.DaWak, pages 117–129, 2010.
[12]M. Paradies, C. Lemke, H. Plattner, W. Lehner, K.-U. Sattler, A. Zeier, and J. Kru¨ger. How to Juggle Columns: An Entropy-Based Approach for Table Compression. In Proc.IDEAS, pages 205–215, 2010.
[13]H. Plattner. A Common Database Approach for OLTP and OLAP Using an In-Memory Column Database. In Proc.SIGMOD, pages 1–2, 2009.
[14]H. Plattner and A. Zeier. In-Memory Data Management: An Inflection Point for Enterprise Applications. Springer, Berlin Heidelberg, 2011.
[15]F. Transier and P. Sanders. Engineering Basic Algorithms of an In-Memory Text Search Engine. ACM TOIS, 29(1):2, 2010.
[16]T. Willhalm, N. Popovici, Y. Boshmaf, H. Plattner, A. Zeier, and J. Schaffner. SIMD-Scan: Ultra Fast in-Memory Table Scan using on- Chip Vector Processing Units. Proc.VLDB, 2(1):385–394, 2009.
如果您对我们的源码感兴趣,欢迎到我们的 GitHub 代码仓库阅读查看,觉得不错记得点个 Star 哦~
StoneDB 代码仓库:https://github.com/stoneatom/stonedb
StoneDB 社区官网:https://stonedb.io/
END