挑战:支持多个存储引擎

以下内容并不是新发现:行优化存储适用于OLTP和运营工作负载,而列存储适用于BI和分析工作负载。频繁写入的工作负载适用于行式存储。对Hadoop而言,Hbase适合低延迟工作负载,列式ORC文件或Parquet适合BI和分析工作负载。业界(尤其是内存数据库厂商)宣称:列结构可以很好地为各种工作负载服务。实际上,当相同的数据结构用于处理不同访问模式的工作负载时,通常存在性能折中。Cloudera承诺的Kudu存储引擎将能满足混合工作负载的要求,但它明确指出,低延时性能低于HBase,BI和分析工作负载性能低于Parquet。

NoSQL技术革新已经表明,为了满足当今工作负载的不同需求,支持多种数据模型是很有必要的。但是,为了减少数据的复制和移动,理想方案是单个查询引擎可以支持多个存储引擎。数据可以驻留在数据结构/存储引擎中,对于所需的数据访问模式而言,这种情况是最理想的,而且查询引擎可以透明地支持所有这些操作。为此,Hive、Impala、Drill、Spark、Presto和其他SQL-on-Hadoop解决方案支持多种数据结构。但是,这些查询引擎还不支持OLTP或运营工作负载。

问题不仅在于存储引擎无法服务于多种工作负载,而且查询引擎也难以支持多个存储引擎。为了支持混合工作负载,可能需要将数据从一个存储引擎转换和迁移到另一个存储引擎,但这存在许多挑战,接下来我们讨论其中某些挑战。

统计

如前所述,为了生成优良的查询计划、或理解工作负载是运行型或分析型,我们需要统计信息以支持所有类型的查询工作负载。因此,当添加新的存储引擎时,您还需要添加对收集统计信息的支持功能。存储引擎有高效机制来对行进行抽样吗?通过增量统计,计算它是否有一个简单的方法来查询新的数据?它是否收集行数和其他可用于快速统计收集的指标?为了使查询引擎决定何时对其统计信息做另一次更新,它是否收集增删改查记录的计数量?您需要回答诸如此类的一系列问题来设置对统计数据的收集,与存储引擎高效地工作。

键结构

对于运营工作负载而言,键入访问对亚秒级响应时间非常重要。单行访问需要通过键进行访问。由于事务或事实表总是具有多列键,理想情况下,键值应支持多列键。如果不支持多列键,则查询引擎需要将多个主键列映射到单个存储引擎键。此外,较短的运营查询通常需要聚集访问来检索少量行。聚集键的范围扫描有助于运营工作负载满足服务级别协议(SLA, Service Level Agreements)。为了实现最高效的访问,查询引擎需要了解存储引擎可用的键入访问选项,并为其支持的每个存储引擎优化此访问。

分区

对于查询引擎而言,了解存储引擎如何跨磁盘和节点对数据进行分区,这一点非常重要。它是否支持哈希和/或范围分区,或这些分区的组合?如何确定这种分区?为了平衡各个分区的负载和避免性能瓶颈,查询引擎是否需要对数据进行加盐(salt data)?如果需要,如何添加一个加盐键(salt key)(例如,表格键的最左边的列)并且仍然避免全表扫描?当集群在扩展或收缩时,存储引擎是否重新分区或重新平衡分区,或者由查询引擎来执行此操作?在对数据重新分区时,用户可能需要全盘读取和写入,所以这可能会变得非常复杂。如果查询引擎将对来自这些分区的数据执行并行处理,那么数据如何在分区间进行传播是非常重要的。它需要尝试将访问本地化,减少数据的再分区(也称为shuffle),或尽可能多地跨节点分布数据。在未理解存储引擎的键和分区结构的情况下,不可能有效地处理查询数据。运营查询可能不会经常遇到并行处理数据的一些挑战,但是,如何对数据进行分区将影响是否能通过访问单个分区、磁盘或节点来处理快速运营查询,而不必通过访问多个分区来满足具有严格服务级别的目标。

数据类型支持

查询引擎需要了解存储引擎支持哪些数据类型,以及存储引擎对这些类型实施的约束条件,以便查询引擎可以执行存储引擎不会执行的任何约束条件。例如,在某些情况下,如果存储引擎只支持字符串存储,那么查询引擎最好将数据存储在自己的编码数据类型中。或者,如果查询引擎会强制执行CHECK限制条件,那么它是否可以将CHECK约束转包给存储引擎,或由查询引擎来执行它们?当然,存储引擎一般不会支持引用约束检查。
如果存储引擎能提供完整的字符集支持,那么存储引擎和查询引擎便能通过UTF-8进行通信;排序规则也是如此。

存储引擎是否提供压缩或加密支持,或由查询引擎提供上述支持?查询引擎很可能发出DDL语句(创建表格),它还需了解哪些选项用于数据块级别压缩和键压缩,以及需要向用户公开的其他表结构选项。在一些情况下,可能会将存储引擎表格映射到表的查询引擎视图。

投影和选择

大多数存储引擎支持投影,存储引擎只返回需要的列,否则查询引擎必须解压数据并进行投影。同样,需要了解存储引擎是否可以提供谓词求值的能力。 存储引擎能够为哪些谓词(=、<、>、<>、between、LIKE)求值?它能在多列上评估谓词或评估多列谓词((a,b)>(5,1))吗?它能处理IN列表吗?支持多长IN列表?一般来说,它是否能处理ORs和ANDs的组合以及能处理何种复杂级别?它能自动确定应用谓词的最有效的顺序(例如,首先评估能最大程度减少基数的列上的谓词,尤其是当存储引擎为列式存储时)吗? 它能处理涉及同一表格的多个列的谓词(例如,c1>c2)吗?除了文字,能处理字符串表达式(STR(c1,3,2)='10')或日期和时间表达式吗?这些表达式有多复杂?存储引擎如何处理缺省或缺失值(NULLs)?查询引擎需要了解存储引擎的所有这些方面,以确定下推哪些谓词到存储引擎、哪些谓词由查询引擎评估。

内存价格的下降让我们能为每个节点配置大量的内存,非易失性存储器的广泛使用也即将实现。为了访问事务和分析工作负载的数据,存储引擎不仅在内存中设计高效的结构,而且正在实施使投影和选择等操作更高效的技术。存储引擎利用L1、L2和L3 CPU高速缓存来处理数据,其速度甚至比主存储器处理数据的速度更快。通过矢量化方法同时处理多组行/列的数值,并提出其他的创新方式,例如,最小化或消除序列化/反序列化的成本,最大程度地提高数据处理速度的同时最大限度地利用硬件设施。这样,瓶颈将从磁盘移动到主内存,最终移动到CPU。高效地使用CPU非常重要,查询引擎必须挖掘存储引擎的效率,并尽可能地减少CPU使用率。

可扩展性

为了在存储引擎/服务器端实现更多功能,一些存储引擎可以运行用户自定义的代码(例如,在HBase上的协处理器、前触发器或后触发器),从而减少信息流量开销并提高效率。

例如,如果优化器能将聚合下推到存储引擎,则它可能有处理积极聚合的能力。当数据在GROUP BY列聚集或分组数目较小时,该方法极为有效。如果存储引擎不支持该操作,则查询引擎能使用协处理器来执行相同操作。可以在此层级执行具有表达式和函数的复杂谓词求值、并发连接和索引维护、安全执行和某些ANSI触发器操作,甚至事务支持。

安全执行

安全处理是查询引擎和存储引擎之间的信息交互点。存储引擎可能有自己的底层安全实现方式,如果它能良好地与SQL模型进行集成,则查询引擎可以使用它。否则,在细粒度访问控制的情况下,查询引擎必须管理schema、表、列和行的权限。它可能需要将自己的授权框架与存储引擎的授权框架进行集成(甚至映射)。考虑到其他安全问题,例如,Hadoop安全解决方案(Sentry或Ranger管理这些对象),查询引擎需要与该安全框架进行集成。根据对安全日志及其他安全信息和事件管理(Security Information and Event Management, SIEM)功能的支持,查询引擎必须能与存储引擎和平台功能进行集成,或自身提供相关功能。对于混合事务/分析处理(Hybrid Transaction / Analytical Processing,HTAP)而言,由于可能需要支持多个存储引擎,这将变得更加复杂。

事务管理

假设一个存储引擎提供某种级别的高可用复制、备份和恢复以及某种级别的多数据中心支持。但是,事务性支持可以完全不同。事务管理具有ACID模型(原子性 [Atomic]、一致性 [Consistent]、隔离性 [Isolated] 和持久性[Durable])以及BASE模型(基本业务可用性 [Basic Availability]、柔性状态[Soft-state] 和 [Eventual consistency])。根据搜索引擎提供的支持,查询引擎可能需要提供完整的多行、多表格和多语句的事务支持,任一时间点的在线备份和事务一致性恢复,以及为多数据中心提供双活同步更新和最终一致性的支持。查询引擎需要与预写式日志和存储引擎的其他机制集成,以便利用引擎的底层复制和其他高可用性功能。这些可以具有很大差别,例如Cassandra、HBase或Hive,它们各自都有自己的事务模型。

此外,回到存储引擎功能的可扩展性(例如,HBase的协处理器),查询引擎需要实现此事务功能,尽可能地与查询引擎接近并进行集成,以获得可分布和最佳性能。否则,它最终只是一个更通用的、而不是可扩展的和高效的实现方式。

元数据支持

查询引擎需要为正在支持的存储引擎表添加元数据支持。存在可能映射(例如,目录、名称、位置和数据类型映射);针对存储引擎的特定扩展选项(例如,压缩选项);支持多列族 – 例如,将数据分区选项映射到底层存储引擎结构(例如,Hbase regions)等。当有人在外部更改存储引擎表时,如何更新该元数据?或者如何将其标记为无效,直到有人修复了差异?

实际上,如果数据库能访问外部存储引擎,那么需要处理大量不可预知的问题,例如,如何保证事务一致性和数据完整性?如果列中的数据与其应该具有的数据类型不一致、或包含无效数据(可能它已通过其他方式更新),那么查询引擎应如何操作?此外,您是否允许在此类表格上创建二级索引、视图、限制条件和物化视图等?上述情况不仅需要提供元数据支持,而且必须解决可能由外部访问引起的潜在的不一致性问题。

运营工作负载与BI和分析工作负载所需的元数据支持存在差异。例如,运营功能需要参照完整性、触发器和存储过程,而BI不需要;运营工作负载不太需要物化视图。

性能、扩展和并发性考虑事项

查询引擎为了支持HTAP负载,在和不同的存储引擎集成时,需考虑不同存储引擎的性能、扩展性和并发性等关键因素。例如,是否有可用的批量加载机制,以及它在此类加载期间对事务一致性和可用性有什么影响?是否支持批量插入,从而可以有效地进行大量插入操作?批量提取功能是否可用,以在每个缓冲区返回行集,而不是一次返回一行的接口?是否有更快的扫描选项(例如,快照扫描)?当查询引擎了解将会扫描大量数据时(可能是针对数据抽取或大型复杂查询),能请求预取大块数据吗?查询引擎如何进行并行更新和访问存储引擎?如果查询引擎支持执行进程进行并行查询,那么它如何最高效地访问存储引擎文件/分区和区域?存储引擎能支持什么级别的并发访问?查询引擎如何最高效地利用存储引擎所支持的功能和填补其不支持的功能?这些都很难确定,更难以实现。

错误处理

查询引擎可能需要支持HTAP,因此,每个存储引擎的错误处理方式也不相同。存储引擎提供的错误处理机制是什么?如何记录这些错误?存储引擎记录错误吗?或者查询引擎需要解释每种错误类型并记录它吗?需要向用户提供某些重大错误消息和补救指导吗?

其他运营考虑事项

除了前文提到的错误处理,还需要考虑其他方面。例如,HBase的合并或拆分问题。这些对性能和用户工作负载很重要,对事务工作负载的影响更大。如何通过查询引擎管理这些以提供最佳客户体验?

简单地说,支持存储引擎并非一项简单任务。当然,您可以走捷径,例如,支持 InputFormat或OutputFormat;甚至使用UDF或某些连接器技术来使查询引擎与存储引擎进行通信。但要真正集成存储引擎,让其发挥最佳性能,并提供最高效的并行处理,需要投入大量的努力。如果您需要支持多个存储引擎,以获取在多个存储引擎之上的查询引擎的终极数据库,这是非常困难的。

IT行业齐心协力共同为查询引擎创建标准接口,例如,Java数据库连接(Java Database Connectivity, JDBC)和开放数据库连接(Open Database Connectivity , ODBC)。如果不同的存储引擎能为查询引擎提供通用的接口,这将是一件非常好的事。查询引擎能通过接口快速省力地识别存储引擎的能力,再与存储引擎进行集成,并充分利用存储引擎的功能。如果能实现这个目标,IT行业将会到达发展的成熟阶段。但目前来看,各种存储引擎的API及其功能并不统一。

虽然某些挑战看起来与数据联邦引擎必须应对的挑战极为相似,但不同的是,查询引擎使用标准JDBC / ODBC接口与数据联邦引擎连接,即将查询转包至另一个查询引擎。这种抽象层次与更深层次的集成不同,更深层次的集成能大幅提高效率和性能,它用于查询引擎和存储引擎之间。试想将一个专有RDBMS,例如,将Oracle拆分成一个查询引擎和一个存储引擎,该方法与联邦引擎连接至Oracle实例的过程不同。

挑战:适于所有工作负载的相同数据模型

正如IT行业的许多其他模糊术语一样,data model这个术语包含很多不同的含义。在RDBMS背景下,数据模型(data model)是实现的规范化级别。用于运营工作负载的数据是从第一范式到第六范式。对于BI和分析工作负载使用的历史数据,您需要不同的数据模型,例如,星型schema或更复杂的包含维度表和事实表的雪花schema等。数据模型大相径庭,以适应在OLTP和运营查询中的不同访问模式,这些访问模式侧重于特定实体,(例如,客户、订单、供应商和产品),而不是侧重于BI或分析查询的大量历史数据。

HTAP是否无需描述数据模型?一些内存数据库供应商声称已经达到这种效果,但尚未撰写出任何性能基准报告——人工(TPC)或真实世界——即BI和分析工作负载在第三范式中性能良好。现在,还没有任何数据表明OLTP /运营系统能在星型schema中表现良好,不管是内存数据库还是非内存数据库。除了基准外,性能还由客户运行的工作负载的种类决定,这些工作负载与TPC基准不同,甚至不存在一点交集。

因此,您明白存在一定级别的数据重复、转换、聚合以及从一个数据结构、数据模型和存储引擎到另一个数据结构、数据模型和存储引擎的移动,而且您希望查询引擎能将所有都无缝集成。虽然这很难,但还是可以实现。然而,完全不同的是,您不需要复制、转换、聚合或移动数据,也不需要为任何工作负载降低性能。随着Kudu的问世,Cloudera希望市场上有需要单一数据副本、愿意降低高端运营和分析性能的需求,即为了提高设计、开发和运营简单性,他们愿意降低性能。最终结论尚待分晓,但是,如果IT行业在积极地追寻了NonSQL若干年后,又将钟摆摇回预期方向,这将非常有趣。如今,性能扩展和高并发不仅是一项要求,而是唯一要求。

但是,如前所述,数据模型(data model)有不同的定义:键值、有序键值、Bigtable、文档、全文搜索和图形数据模型。为了实现单个存储引擎的终极数据库,人们试图让这些数据模型处理它们本来不擅长的业务,从而充分挖掘它们的潜力。因此,文档中的整个父-子关系表明不再需要RDBMS功能,并且文档的存储能满足所有工作负载要求。或者,现在是图形数据库的时代吗?我们是否可以在边缘和顶点中填充各种参数以支持各种工作负载?事实上,即使每个数据模型确实解决了某些问题,但它们并不能独立地支持当今企业需要解决的各种工作负载。

文档功能、文本搜索(必要时)、图形结构(需要快速访问的层级或网络类型关系)、支持半结构化或非结构化数据的基于键值的模型,和完全结构化的关系数据库能针对不同需求给出不同的令人满意的结果。尽管一些查询引擎全力支持,但挑战是有效地将存储引擎与查询引擎进行集成。另外,为其他数据模型加入标准SQL API(实际上它并非标准,因为每个数据库有它特有的实施方式)和非标准API,这也是一项挑战。

无论您怎样理解“数据模型”一词,如果HTAP以相同的查询引擎来支持所有企业工作负载的多个(非全部)数据模型,那么它需要克服许多挑战。

挑战:企业级能力

大企业开始将BI工作负载扩展至分析工作负载,再扩展至高级分析引用(例如,数据挖掘和机器学习),他们最初在专有数据库和平台上运行BI和分析工作负载,在Hadoop上运行大数据的其他工作负载。但随后许多企业将某些在专有数据库中运行的部分工作负载迁移至Hadoop上运行,一些企业正在提供运行全面的RDBMS OLTP和在Hadoop上运行运营工作负载的能力,从而将工作负载类型向混合事务型和分析模型扩展。但要真正处理所有工作负载,包括关键任务工作负载,则HTAP数据库引擎需要提供企业级能力,我们将在以下部分对此进行讨论。

高可用性

对任何数据库而言,可用性是一项重要指标。例如,您可以通过HBase得到99.99%(也被称为“4个9”)的可用性,即每年有约52.56分钟的非计划停机时间。许多关键任务应用都努力实现99.999%(也被称为“5个9”),即每年5.26分钟的停机时间。当然,可用性所增加的成本可能是巨大的。现在的问题是:查询引擎与存储引擎结合在一起,能提供何种程度的高可用性?

通常,数据库很难实现高可用性。如果想要实现,需要解决以下问题:

  • 当需要读写数据,在不能停机的情况下,您能将底层OS、Hadoop发行版、存储或查询引擎升级至新的软件版本吗——即,支持滚动更新吗?
  • 您可以将数据重新分配到已添加进集群的新的节点或磁盘吗?或合并它们以减少节点或磁盘(完全在线,不停机)?与此相关的问题是重新分区数据的能力。您是否能在线完成?在线意味着在操作期间仅读取数据、或同时读取和写入数据。
  • 能在线为数据库更改DDL吗?例如,在不影响读取和写入的前提下,更改列的数据类型?数据库能容易地添加和删除非键列。
  • 能在线创建和删除二级索引吗?
  • 支持完全和增量在线备份吗?

您的应用程序需要上述哪些功能取决于运营和分析工作负载的混合程度,以及高可用性对这些工作负载的重要程度。

安全

运营和分析工作负载的安全实现不同。对运营工作负载而言,通常在应用程序层管理安全性。应用程序与用户交互,并管理数据库的所有访问。另一方面,BI和分析工作负载能使最终用户通过报告和分析工具直接访问数据库。在这种情况下,可能会将授权推送至数据库,查询和存储引擎需要管理安全性。

集成到SIEM系统也适用于分析工作负载,但很多运营工作负载需要更高程度的安全控制和可见性。

可管理性

管理数据库及其工作负载的能力非常重要。从图1-9中可以看出,可管理性需要很多功能,也许仅能实现部分功能

clipboard.png

图1-9 数据库管理任务

由于HTAP工作负载的混合特性,某些管理任务变得越来越具挑战性,特别是工作负载管理。衡量OLTP或运营工作负载时往往需要考虑事务或人机交互的能力。该理念是根据每秒完成的事务来评估服务水平目标。由于此类事务的延迟可能很小,所以跟踪每一条SQL语句的性能或每一事务的表现成本将非常高。因此,您需要以某个时间间隔来统计信息并计算出平均值。而BI和分析适用于报表或查复杂查询,这些查询通常耗时较长,它们采集自身的运行指标值,并基于查询级别统计信息进行监视和管理,以达到良好的性能。

根据优先级和/或资源分配,混合工作负载很难达到SLA的要求。分析工作负载的随机特性使其不能很好地融入运营工作负载,即使在负载峰值期间,运营工作负载也要求亚秒级的响应时间。

如果查询引擎正在与不同的存储引擎进行集成,那么获得所有的运行指标也具挑战性。虽然查询引擎可以跟踪一些指标,例如,存储引擎服务一项请求所花费的时间,但可能无法查看底层存储引擎正在使用的资源。另外,很难在查询引擎和存储引擎之间细分出重要的CPU、内存和I / O指标以及诸如队列长度和内存交换等信息,例如,如果您想获得操作符(用于查询计划的每一步,例如,扫描、连接和聚合等)和被访问的表在查询中所使用资源的详细信息,特别是并发执行和表被分区时,这将是一项非常困难的工作,除非利用插桩和回调函数收集端到端信息。再例如,如何找出遇到数据倾斜或瓶颈的原因?

在不久的将来,不同类型的工作负载可能在单个平台上运行,但这篇报告并没有详尽列举出与企业级运营能力相关的所有挑战。例如,与YARN或Mesos的集成,它们会尽可能考虑如何管理跨集群的不同应用工作负载的资源。希望这些能帮助您理解目前的挑战。


EsgynChina
12 声望11 粉丝

易鲸捷公司项目总监