浅谈MPP数据库动态增减节点
随着云计算技术的成熟,出于节省成本,增强系统灵活性和弹性的考虑,企业对于把应用从内部数据中心迁移到云平台上的兴趣日益浓厚。
虽然弹性是云计算的重要属性,但如[注1]所说,迁移到云平台上面的应用系统不会自动继承这种弹性。为了充分利用云计算的弹性特性,应用系统需要在代码层面上具备动态伸缩的能力。酷克数据在基于开源的 MPP 数据库 Greenplum Database 构建弹性的云端数据仓库 HashData 过程中,对此深有体会。在这篇文章中,我们将浅谈一下MPP数据库动态增删节点时需要考虑的问题以及可能的解决方案。
Greenplum 数据库
首先,我们为大家简单介绍一下 Greenplum 数据库以及其背后的技术。
Greenplum 数据库是 Pivotal 公司开源的一款成熟商业数据库。该数据库产品经历 10 年的不断迭代和打磨,在系统性能,可靠性,与第三方产品适配上都处于领先地位。从 2008 年在国内推广以来,生态已经非常的成熟,在运营商、金融、物流、公安、政府、互联网 等行业都有非常庞大的用户群体。
通过使用大规模并行处理(MPP)技术,Greenplum 数据库能够支撑大规模分析型数据仓库和商业智能分析业务。
MPP(也被称作 shared nothing 架构)是指一个系统拥有两个或者两个以上的处理器,相互合作来执行任务。每个处理器都配有独立的内存,操作系统和磁盘。Greenplum 数据库采用高性能的系统架构可以将请求均匀分散到存储 PB 级别的数据仓库上,同时充分利用系统中所有的资源,并行地处理请求。
下图是 Greenplum 数据库架构图:
图中的主节点主要负责:
全局事务管理
全局查询优化
协调计算节点
主节点接收到客户端的查询请求后,通过优化器对查询进行优化。优化器的输出称为“查询计划”,查询分派器将查询计划分配给计算节点,计算节点进行处理,并将计算结果发送回主节点。最后主节点将数据汇聚,并转发给客户端。数据交换网络支持多个进程跨网络的高速网络协议,是 Greenplum 数据库流水线处理模型的重要组成部分。
以 Greenplum 为代表的MPP数据库通过 Hash 取模的方法,将数据打散并存储到不同的计算节点上:
利用这种数据分布策略,配合成熟的查询优化器,Greenplum数据库可以智能地组建流水线执行计划,提升节点间并行处理能力。下面的图为您揭示 Greenplum数据库并行处理的概念:
图中包含两个计算节点,并对执行不同任务的进程进行了分片,每个分片用虚线划分。三个分片分别代表执行查询中流水线的三个子计算任务。这三个任务独立的处理一部分计算任务,同时又互相配合完成整体的查询。处于同一个分片的进程,执行的子计算任务相同,但是处理的数据不同(利用 Hash 特性)。具有相同颜色的圆圈表示在一个进程中执行的数据处理步骤。五种颜色的进程分别表示:
青:读取表 "bar" 部分数据,将数据按照 "foo" 的分布规则重新分发
绿:读取表 "bar" 部分数据,将数据按照 "foo" 的分布规则重新分发
红:读取表 "foo" 部分数据,对数据进行连接计算,并将最终结果发送给主节点
橙:读取表 "foo" 部分数据,对数据进行连接计算,并将最终结果发送给主节点
紫:主节点,发送查询计划,收集查询结果
这样,为了执行查询,一共有五个进程参与了处理,系统通过三个分片,构建了流水线,数据记录像流水一样,从数据文件经过每个计算步骤,最终在主节点汇聚,然后转发给客户端。
Greenplum 数据库数据存储之痛
在前面的章节中,我们已经提到,在 Greenplum 数据库中,数据是通过标准的 Hash 函数计算 Hash 值,根据计算节点数量取模,打散存储到不同的节点。这种数据分布策略简单明了,执行开销低;但在增删节点的时候,数据重分布就成为一个令人头疼的问题。我们用一个简单的例子,为大家解释采用 Hash 取模策略时,数据重新分布对系统的影响:
图中描述了系统从三个节点扩展到四个节点时,系统数据分布的变化。在系统扩展前,节点 node0 负责存储 hash(id) % 3 == 0 的数据,对于 node1, node2 以此类推。节点扩展后,节点 node0 负责存储 hash(id) % 4 == 0 的数据,对剩余节点以此类推。在这个例子中,有 70% 的数据经过网络交换,迁移到了其它的节点。
在使用 Hash 取模的方案中,要改变数据分布,全部数据都需要经过读取,重新对 Hash 值取模,发送到节点进行存储,写入磁盘的过程。整个操作过程会产生大量的 I/O 请求,引起正常的业务处理速度下降,影响客户的正常查询需求。随着用户数据规模增长,数据重分布过程少则需要几小时,多则需要几天。
MPP 数据库敏捷伸缩
对于一个MPP数据库,系统增删节点时,我们需要考虑下面的问题:
数据重分布的时间窗口长短
数据重分布带来的I/O开销对正常的业务操作的影响
数据重分布过程中查询执行优化
前面两个问题,是 Hash 取模方式的劣势,可以通过一致性 Hash 来解决这个问题。第三个问题,需要针对系统节点的变化过程,来进行特定的优化。我们首先为大家介绍一致性 Hash 在 MPP 数据库上的应用。
一致性 Hash
一致性 Hash 依然利用标准的 Hash 函数计算 Hash 值。与取模方式不同,一致性 Hash 通过将 Hash 函数计算结果的 Hash 值划分成不同的数值分区,并将不同分区映射到不同的存储节点来解决取模方式的缺点。我们通过图形来逐步为大家介绍一致性 Hash 的使用方式。
Hash 值范围的环状表示
首先,将标准 Hash 函数的返回值映射到 [0, 2^32 -1] 的整数空间。使其首尾连接后,可以得到下面的圆环:
对象 Hash 值的映射
对于需要存储的对象,通过一个 Hash 算法将其映射到环状地址空间,例如:
hash(object1) = key1
hash(object2) = key2
hash(object3) = key3
hash(object4) = key4
将计算的键值存储到圆环的对应位置,可以得到下图:
节点 Hash 的映射
一致性 Hash 的存储节点可以将节点名称通过 Hash 算法映射到环状地址空间,例如:
hash(node1) = pos1
hash(node2) = pos2
每个节点负责存储的数据就是根据节点的位置决定:
node1 存储从 pos1 开始,到 pos2 位置的数据
node2 存储村 pos2 开始,到 pos1 位置的数据
下图描述增加存储节点后一致性 Hash 状态:
对于一致性 Hash 来说,增加或减少一个节点时,需要移动的数据总量将会从 1 变成 1/N(N 表示系统原节点数量)。
细心的读者不难发现,上面介绍的一致性 Hash 存在一个问题:增加或减少节点时,可能只有一部分节点上的数据需要发生移动。这将会引起系统中节点上的可用资源不平衡,导致用户的正常业务逻辑受到较大的影响。
为每个节点引入虚拟节点可以解决这个问题,例如:
hash(node1-a) = pos1
hash(node2-a) = pos2
hash(node1-b) = pos3
hash(node2-b) = pos4
增加虚拟节点后,数据的分布将更加随机。系统在增加和减少节点时,需要迁移的数据分布将会更均匀。
通过使用一致性 Hash,MPP 数据库在节点变化时,既可以保证迁移数据量较小,又可以保证在迁移时,不会对个别节点造成过大负载的情况。
数据动态分布下等值连接运算优化
即使采用了一致性 Hash 来存储数据能够减少系统数据重新分布的时间,在数据调整过程中,数据的分布仍然存在不一致的情况。我们以系统从三个节点扩展为四个节点为例,通过一个典型 MPP 数据仓库查询来深入讨论这个问题:
SELECT * FROM foo LEFT JOIN bar ON foo.id = bar.id;
对于这个常见的 SQL 语句,如果表 foo 和 bar 是按照原始数据分布(三个节点进行 Hash 分布),那么查询应该按如下处理:
此时虽然系统有四个节点可以处理查询,但是由于数据还没有被重新分布,优化器生成的查询计划选择只在原节点上执行查询。虽然无法利用新增的节点资源处理请求,但是系统可以正确的按照扩容前最优的执行策略处理请求,因此查询性能不会出现明显变化。
类似地,如果 foo 和 bar 是按照新的数据分布,那么查询可以按照如下处理:
此时系统使用全部四个节点进行数据处理,MPP 数据库对于此查询可以充分利用新增节点,提高查询响应时间。
我们再考虑一个复杂的情况:foo 和 bar 两张表,foo 表按照新的状态分布(四个节点),bar 表还处于旧的状态分布(三个节点)。可以认为这是数据重分布过程中的一个中间状态,此时由于两张表的分布不一致,查询性能将会产生下降。但是,MPP 数据库仍然要保证查询结果的正确。这里可以通过将按照旧状态分布的表动态地重新分布为新状态来保证查询的正确性,例如:
从图中不难发现,新的查询计划与之前的两个查询计划的区别是增加了 Redist 的节点。Redist 节点能够重新计算输入数据的 Hash 值并根据查询运行时刻的系统状态调整取模策略,保证计算结果的正确性。通过修改查询优化器,借助 MPP 灵活的结构,系统能够应对系统在动态扩展或收缩时的不必要的性能下降。
总结
构建一个高性能、弹性的大数据分析引擎从来都不是一项容易的工作。在这篇文章中,我们简单讨论了一下MPP数据库动态伸缩时需要考虑的问题以及可能的解决方案,特别是如何高效地进行数据重分布,以及在伸缩过程中对正在运行的查询进行执行优化。
随着HashData数据仓库开发工作的不断推进,我们将在后续的文章中探讨更多的实现细节。
[注1] Enterprise Database Applications and the Cloud: A Difficult Road Ahead.
作者:HashData 微信公众号