Apache HAWQ 作为一款先进的SQL-On-Hadoop开源分布式数据库产品,其代码基础源自著名的分布式数据库Greenplum Database (GPDB)。在设计之初,高可扩展性(Scalability)即成为HAWQ的一个重要的设计目标。因此HAWQ在架构与实现上均与GPDB有着明显的不同。这些不同点反应了HAWQ对高可扩展性的追求。本文将介绍这些不同点与其背后的设计哲学。

HAWQ架构简介

HAWQ是一款基于massively parallel processing (MPP)架构的分布式数据库。HAWQ由一个master节点,一个可选的standby节点和多个计算节点(segment)组成。其中master节点负责接收用户的查询请求,生成查询计划。然后master节点会指挥多个计算节点执行查询计划,最后将查询结果返回给用户。

无状态的计算节点

从HAWQ的架构可以大概看出,作为计算节点,HAWQ的可扩展性与segment的设计实现密不可分。为了提高HAWQ的可扩展性,HAWQ的计算节点被设计成无状态的节点。GPDB的计算节点存储了大量的状态信息,其中包括用户的配置选项和事务的状态等等。维护多个节点间状态的一致性成为影响可扩展性的重要原因。HAWQ的所有状态信息统统保存在master节点,在执行查询计划的时候,状态信息随着查询计划一并分发到计算节点。无状态计算节点的设计使得计算节点不必要再费力的维护状态信息的一致性。而master的唯一性使得维护状态信息的复杂度不随计算节点的增加而增加。

元数据的存储与访问

基于无状态计算节点的设计理念,HAWQ的元数据集中存储在master节点。这成为HAWQ与GPDB的一个重要的设计区别。元数据集中存储的好处是便于管理与一致性的控制。再加上HAWQ的用户数据存储在分布式文件系统HDFS上,HAWQ因此不在需要为计算节点设计镜像(mirror)节点,从而简化了系统设计并且提高了HAWQ的可扩展性。

计算节点在执行查询计划的时候是需要访问元数据的,HAWQ通过元数据分发(metadata dispatching) 来解决这个问题。对于一个查询请求,master在生成查询计划之后,需要遍历整个查询计划来收集执行这个查询计划所需要的元数据。Master将这些元数据收集起来,保存在查询计划里。我们称这样的查询计划为自描述的查询计划。计算节点接收到自描述的查询计划后即可以完成全部计算工作,不需要请求额外的元数据。

一个数据库在刚刚完成初始化的时候就已经存在大量的元数据了,这些元数据包括了数据库支持的各种数据类型,系统表信息,内建函数等等。这些初始的系统元数据并不会被修改,因此HAWQ在每个计算节点上保留这些只读元数据的备份,从而减少自描述查询计划的大小,提高元数据分发的性能。

一些DDL语句会修改元数据,计算节点在每个语句结束的时候收集所有被修改的元数据,将修改的元数据返回给master节点,master负责对元数据的更新操作。

事务的实现

我们之前讲到,无状态的计算节点并不保存事务状态,我们在这一节介绍HAWQ的事务系统的实现。

GPDB与大多数分布式系统相同,采用分布式事务的设计,采用两阶段提交等算法实现分布式事务。HAWQ在设计之初,我们为了提高系统的可扩展性,并没有采用两阶段提交等分布式事务算法。而是采用了一种分布式系统中比较少见的集中式事务控制机制。HAWQ通过两个层次来实现事务系统。

  • 元数据的事务保证:HAWQ的元数据保存在master上,存储在本地文件系统中。HAWQ采用多版本并发控制(MVCC)算法实现元数据的并发隔离。通过日志(WAL)实现元数据的持久化。

  • 数据文件的事务保证:由于HDFS只支持文件的追加操作,因此对数据文件的版本控制可以通过记录数据文件的逻辑长度实现。并发的数据追加可以通过并发写入多个不同的文件来实现。数据文件的长度记录在元数据中,因此数据文件的版本控制是通过元数据实现的。对数据文件的追加不记日志。计算节点对数据文件的追加操作都是即时提交并持久化保存在HDFS上的。

总结

HAWQ的设计理念在于,尽量简化计算节点的复杂度,通过集中式的方式存储和维护复杂的系统状态,从而简化系统整体的复杂度。通过降低系统的复杂度来提高系统的可扩展性。做到简单就是美的效果。

一个分布式系统的可扩展性受到系统设计的方方面面的影响。本文没有也不期待将这些方面一一枚举。本文通过比较HAWQ与GPDB架构的不同,向大家介绍一下HAWQ在设计之初的思考。