技术分享:如何基于对象存储打造一个高性能、完全托管的PB级MPP数据仓库

337 阅读13分钟
原文链接: mp.weixin.qq.com

对象存储服务(OSS)是原生云架构中的重要组成部分,提供了更高的可用性,数据持久性和水平扩展能力。在本文中,我们展示了原生云数据仓库如何通过精心设计的存储和缓存层,利用 Alluxio 消除对象存储的性能损失,同时享受其可伸缩性和成本效应。

正文

本文将介绍北京一家初创企业 HashData 构建基于云原生的 MPP 平台的过程。该企业利用对象存储作为数据持久层,Alluxio 作为云中的数据编排层,最终构建了一个原生云高性能 MPP 共享的体系架构。

HashData 是由一群来自 Pivotal、Teradata、IBM、Yahoo! 等开源数据资深人士于 2016 年创立的。它的旗舰产品 HashData WareHouse(HDW),是为云环境构建的数据仓库服务,具有完全兼容的 Greenplum 分析接口。HDW 独特的多集群共享数据库体系架构,在性能、并发性、灵活性和易用性方面取得了很大突破。和许多传统 MPP 系统采用的非共享体系架构(计算与存储紧耦合)不同,HDW 采用了具有解耦和独立对象存储的共享体系架构。这种体系架构的主要挑战在于性能。与传统的块存储相比,对象存储通常性能较低。

在本文中,我们将进一步分析 HDW 如何利用 Alluxio 作为数据编排层,以消除对象存储带来的性能损失,同时受益于对象存储的可伸缩性和成本效应。

1

为什么使用对象存储服务

如今,对象存储服务(OSS)在原生云架构中一直很重要。正如这篇博客所提出的,它提供了更高的可用性、弹性和耐久性,而且成本更低。越来越多的产品和服务支持 OSS 作为他们的持久文件系统。

节省成本

根据我们的观察,对于许多拥有 100TB+ 数据的用户来说,他们的成本主要来自存储成本,而不是计算成本。一个主要原因是计算完全随需应变,而存储容量在删除数据之前无法回收。因此,当客户考虑各种数据分析选项时,存储成本是一个重要因素。下表为中国全栈 ICT 服务及解决方案(包括公共云服务)供应商 QingCloud 在 PEK3 区域的块存储和对象存储的价格对比。OSS 的成本大约是单副本块存储的 1/4,多副本块存储的 1/5。

弹性也会影响存储成本。虽然块存储支持在线扩展,但是弹性计算机(即将扩展的块存储卷连接到它)在扩展期间会导致 HDW 集群短暂停机。因此,客户通常会保留额外的块存储容量,以避免在短时间内再次扩展,从而导致成本更高。总之,基于 OSS 的数据仓库解决方案的存储成本大约是使用传统块存储成本的 1/10。

系统灵活性

让我们来看一个典型的数据分析场景,尤其是在物联网和电信行业:随着时间的推移,越来越多的数据生成并被导入到数据仓库系统中。通常,由于应用程序需求或管理策略的原因,这些数据需要保存 18 或 36 个月。此外,所有数据必须随时可查询,例如在线分析;另一方面,大多数单个查询(如果不是全部的话)只涉及整个数据存储的一小部分(例如,最近一周或最近一个月,或 2016 年 9 月至 2016 年 10 月之间生成的数据)。

换句话说,计算资源的需求是稳定的,而存储资源的需求则在不断增长。在传统的非共享架构下,为了解决这个问题,我们需要对集群进行扩展(例如增加更多的 worker 节点),因为挂载到弹性计算机上的块存储的容量有上限。

在这种扩展场景中,新增的计算资源完全是浪费,更不用说集群扩展是一个容易出错且耗时的过程。与传统 MPP 解决方案的刚性相反,HDW 的数据存储容量几乎是无限的。存储层扩展对于计算层是完全透明的。实际上,从 HDW 用户的角度来看,没有存储扩展概念。用户可以继续将数据导入到 HDW 集群中,并处理目标数据来支持他们的业务决策。

内置表

如上所述,HDW 继承了 Greenplum 数据库丰富的数据分析功能。其中一个惊人的功能是通过外部表访问对象存储中的原生数据。虽然外部表有一定的特点,但是与外部表相比,HDW 基于 OSS 的内置表还进一步具有以下优势:

  • 内置表支持更新 / 删除和索引操作。最重要的是,内置表完全支持 ACID 事务。这些特征外部表都不支持。

  • 内置表可以实现更好的数据压缩。目前,外部表支持三种常见的数据格式:TXT、CSV 和 ORC。根据我们的观察,为了简单起见,与 ORC 相比,客户通常更喜欢带有 ZIP 压缩算法的 TXT/CSV。使用内置表,我们可以使用更复杂的编码策略(例如字典编码和变长编码)和压缩算法(例如 zstd)。

  • 内置表具有更好的查询性能。内置表的数据布局样式(无论是存储在内存中还是在磁盘上),都为 HDW 的执行引擎进行了高度优化。

2

使用 Alluxio 加速 OSS 访问

尽管对象存储为大数据系统提供了很多好处,但是与块存储相比,它具有更低的 I/O 性能。

一方面,虽然随着对象存储技术的不断发展,目前大多数对象存储服务只能够为每个 HTTP 连接提供 100MB/s 左右的 GET 吞吐量和 40MB/s 的 PUT 吞吐量。当启用多线程 GET、多线程上传和数据压缩时,总体 I/O 吞吐量可以匹配数据库执行器的处理吞吐量。

另一方面,OSS 本身不是瓶颈的时候,在一个公有云环境中,HDW 集群所在软件定义网络(SDN)的总带宽通常存在一个上限,这会在 HDW 集群访问对象存储中的数据时限制 I/O 性能。其次,客户需要为每个 OSS HTTP 请求付费。

第三,HDW 支持各种索引算法,包括 B 树、位图和 GiST。客户可以利用这些索引算法,通过扫描索引来加速查询,并在数万亿元组上实现亚秒级查询时间。另一个查询场景是查询低维度表。对于这些情况,OSS 的吞吐量虽然不是性能瓶颈,但是其访问延迟确是一个很大的瓶颈问题。

为了解决上述问题,我们选择了 Alluxio 作为智能缓存层来加速 I/O 性能。Alluxio,原名 Tachyon,是世界上第一个用于云计算分析和人工智能的数据编排技术。它连接了计算框架和存储系统,使存储层的数据更接近计算框架,允许应用程序通过公共接口连接到多个存储系统,使得数据更易于访问。Alluxio 的内存第一的分层架构使得它能够比现有解决方案快几个数量级的速度访问数据。

结合使用 HDW 和 Alluxio,缓存数据被平均分区到每个 worker 节点上。每个 HDW 片段都将数据缓存到它的本地 Alluxio worker 中。Alluxio 主节点与 HDW 主节点被部署在一起。所有用户都是通过 Alluxio 接口操作数据。HDW 的高层存储架构如下图所示。

Alluxio 在大数据生态系统中扮演者重要的角色。它与许多开源大数据系统共享类似的技术栈,包括基于 Java 或 JVM 的轻量级事务模型,这使得 Alluxio 与它们完美匹配。然而,仍然有许多分布式系统采用完全不同的构建理念。在接下来的部分中,我们将分享在利用 Alluxio 构建原生云 MPP 数据库时学到的经验。

C/C++ 原生客户端

Alluxio 提供几种编程语言绑定,包括 Java、Go 和 Python,还通过 HTTP 代理支持所有其它语言的 REST 接口。虽然开源项目 liballuxio 通过使用 JNI 调用原生 Java 客户端能够提供 C/C++ Alluxio 接口,但是目前还没有官方的 C/C++ 原生客户端。

为了提高系统性能、稳定性、灵活性和易维护性,我们决定为 Alluxio 实现一个原生 C/C++ 客户端,而不是直接使用 liballuxio。在 HashData 中,我们构建了一个 C/C++ 客户端 liballuxio2,它通过 RPC 调用来和 Alluxio 服务器交互。在 Alluxio 不同组件之间的交互过程是基于 thrift/protobuf/netty。liballuxio2 作为一个原生客户端,采用了 thrift/protobuf 提供的 Alluixo 统一数据交换格式。目前, liballuxio2 支持 Alluxio-1.5.0 版本。

统一对象存储 SDK

Alluxio 作为底层文件系统(UFS)支持各种对象存储服务,包括 S3、Azure Blob Store、GCS 等,并提供了一个框架,用户可以通过该框架轻松地扩展它来支持新的对象存储。但是,我们采用了不同的方法,理由如下:

不同的对象存储服务支持不同的访问优化策略,以获得更高的读写性能,包括多线程上传和流水线下载。构建一个 C/C++ 原生 OSS 库是利用这些优化机会的更好方法。

作为一家初创企业,HashData 希望支持本地公共云提供商提供的各种对象存储服务,而不仅仅是上述的跨国巨头。统一的 C/C++ OSS 客户端库可以大大减少研发工作,使得开发人员不必担心异构对象存储服务的复杂性。

Alluxio 客户端可以使用委托 / 非委托模式来控制 UFS 操作的处理位置。在非委托模式下,Alluxio C/C++ 原生客户端负责 OSS 读写操作。Alluxio 服务器只需要维护元数据和基于缓存 I/O 流的块。

我们已经构建了一个统一 C/C++ 原生库来支持本地和全球顶级云平台的对象存储服务,并且将它集成到 liballuxio2 库中。用户仍然可以选择委托模式来保留 Alluxio 服务器执行的 OSS 操作。

分层存储

Alluxio 支持分层存储,以便管理除内存以外的其它存储类型。目前,Alluxio 支持三种存储类型 / 层,包括 MEM(内存)、SDD(固态驱动器)和 HDD(硬盘驱动器)。在开始时,我们保持默认的分层设置,例如数据首先缓存到 MEM 层,并在上层填满后迁移到 SSD/HDD。

但是,当我们开始使用大量数据进行压力测试时,如果 MEM 层中的所有文件都是打开的,那么缓存的数据就不能被删除。对于典型的 HDW 工作负载,MEM 层的容量(为了节省成本,我们通常不会为 EC 机器分配太多内存)不足以缓存目标数据。因此,我们将默认的写入层更改为 SSD。

更关键的是,在数据超出本地磁盘容量的情况下,HDW 数据库内核会告诉 C/C++ 原生 Alluxio 客户端 liballuxio2 不要缓存哪些运行查询的数据。许多复杂的 Alluxio 读 / 写 / 缓存策略都是由 HDW 数据库内核动态决定的。

事务提交

作为关系数据库管理系统(RDBMS),HDW 完全支持 ACID 分布式事务。与许多基于 HDFS 的大数据分析系统(原子写是利用 HDFS 原子重命名特性实现的)不同的是,HDW 对事务的支持是建立在数据库内核里的。只有当所有打开供写的文件都成功地持久化在对象存储上时,事务才成功提交;否则事务将中止,并清除所有开放可写的文件(包括数据)。为了保证数据持久性,所有的 Alluxio 写操作都直接写到对象存储中,而不需要缓存。

3

基准测试

我们使用 TPC 基准(TPC-H)测试来评估我们的解决方案。TPC-H 是一个决策支持基准测试集,由一组面向业务的即时查询和并发数据修改组成。查询和填充数据库的数据具有广泛的行业相关性。这个基准测试的目的不是显示 HDW 对 TPC-H 查询的运行速度有多快,而是显示 Alluxio 提升 I/O 性能的有效性。

因此,在接下来的基准测试中,我们将 HDW 的执行引擎设置为与开源 Greenplum 引擎完全相同,而不是私有的。此外,这项评估大约是在一年前进行的,使用的是基于 Alluxio 的 HDW 的第一个稳定版本,它具有与 Greenplum-5.0 版本相同的数据库内核版本。

配置

数据集大小:100GB

集群:1 个主节点,8 个子(计算)节点

主节点:QingCloud 超高性能实体,2 个 CPU,4GB 内存

子节点:QingCloud 超高性能实体,4 个 CPU,8GB 内存

Alluxio:1.5.0 版本,每个工作节点内存为 2GB

场景

Greenplum 5.0:我们选择这个版本的开源 Greenplum 作为基准。

HashData:HDW 读取的目标数据是从远程对象存储缓存到 Alluxio 层的。

结果

根据我们的观察,OSS 的 I/O 吞吐量至少比本地磁盘低 3 倍。然而,从这个测试结果来看,只有大约 30% 的性能下降。这是因为 TPC-H 是一个 OLAP 查询基准,它包含比 I/O 密集型任务更多的 CPU 密集型任务。通常,冷读只发生在第一次接触数据时。使用 Alluxio 缓存系统,冷读操作的数量大大减少。如图 3 所示,使用 Alluxio 缓存读取的 HDW 性能与传统的非共享 MPP 相同,同时支持使用对象存储的所有优点。

4

结论

在本文中,我们展示了通过精心设计的存储和缓存层,原生云数据仓库可以利用 Alluxio 消除对象存储的性能损失,同时享受其可伸缩性和成本效应。

(来源:Alluxio)

更多精彩内容,点击文末 “阅读原文” 。

- FIN -