Introduction

在数据库和仓库的上下文中进行复制是将实体从一个仓库复制到另一个仓库的过程。这可以是整个数据库的更广泛级别,也可以是表或分区之类的较小级别。复制的目的是拥有一个副本,只要基础实体发生更改,副本就会更改。

在 Hive 中,复制(在Hive 1.2.0中引入)使用懒惰的主副本模型专注于灾难恢复。它使用通知和导出/导入语句来实现用于复制的 API,然后可以由其他工具(例如Falcon)执行复制。

有关用法信息,请参见Hive Replication

Hive 复制的版本 2

本文档介绍了 Hive 复制的初始版本。第二个版本也可用:有关详细信息,请参见HiveReplicationv2Development

复制目的

复制是制作某些对象(例如数据库,表或分区)的副本的过程。复制有两个主要用例:灾难恢复和负载平衡。

Disaster Recovery

  • 允许在灾难(例如服务器无法恢复崩溃)或自然灾害(例如火灾和地震)发生后恢复数据。

  • 优先考虑数据/元数据的安全性而不会造成任何损失。

  • 可用性速度并不那么重要。

  • 热备份通常就足够了。

Load Balancing

  • 允许将用户分散在多个系统上,以 Management 比系统通常无法处理的更大的负载。

  • 优先考虑速度和访问。

  • 多数情况下倾向于只读。

  • 通常需要热备份。

Replication Taxonomy

复制系统经常根据其事务源(“ where”)和同步策略(“ when”)来分类。

Transaction Source

Primary-Copy

  • 从主副本到副本副本的单边副本。

  • 优点: 简单的并发控制(不需要复制就引入了锁)。

  • 缺点: 对于非读取负载平衡很差。

Update-Anywhere

  • 允许双向更新。

  • 优点: 适用于负载平衡。

  • 缺点: 复杂的并发控制。

Synchronization Strategy

Eager

  • 创建单个事件 Sequences 流。

  • 优点: 保证强一致性。

  • 缺点: 由于要求在暂存当前事件的复制之前不得处理任何事件,因此响应时间较长可能会导致性能问题。

Lazy

  • 允许对事件进行一些重新排序以优化资源的使用。

  • 优点: 对用户的快速响应时间。

  • 缺点: 可能有关于目的地和暂时不一致的过时数据。

Design

分类设计选择

Hive 中的复制由于以下原因而使用延迟的主副本复制。

主副本与任何位置的更新

由于 Hive 中的复制专注于灾难恢复,因此主副本复制提供的只读负载平衡就足够了。随时随地复制中的复杂并发控制成本太高。此外,可以将主副本复制隔离为每个对象是单向的,这允许在需要时可以在不同方向复制两个不同对象的方案。对于某些负载平衡要求,这可能就足够了。

渴望 vs 懒惰

急切的复制要求对主数据库上的每个更新都有保证的增量日志。在 Hive 中使用external tables时,这会带来问题。外部表允许在 Hive 外部完全 Management 数据,因此可能无法为 Hive 提供完整而准确的增量日志。对于 ACID 表,确实存在此类日志,并将在将来的开发中使用该日志,但是当前 Hive 中的复制仅适用于传统表。

相反,Hive 使用延迟复制。与渴望复制不同,延迟复制是异步和非阻塞的,这可以更好地利用资源。在 Hive 中优先考虑到这一点,因为要确认不按 Sequences 处理事件(包括诸如DROP之类的破坏性事件)会涉及一些复杂性。

其他设计选择

除了上面列出的分类选择之外,许多其他因素也影响了 Hive 中的复制设计:

  • Hive 对复制的主要需求是灾难恢复。

  • Hive 支持导出/导入的概念。已经存在一些使用 export/import 和DistCp的 Perl/Python 脚本进行手动复制和时间自动复制的实现。

  • Hive 已经能够发送通知以基于事件触发操作,例如由正在加载的分区触发的Oozie作业。

  • 不打算使用 UI,因为还有其他数据 Management 工具(例如Falcon)已经涵盖了数据移动并包括某种形式的 feed 复制。 Hive 应该允许这些工具插入复制系统。 Hive 处理逻辑并为外部工具提供 API 以处理机制(执行,数据 Management,用户交互)。

  • 其他工具可以解决基于时间戳/订阅源的复制,因此 Hive 不需要重新解决此问题。

  • 使用广泛的 DFS 副本和支持数据库的本机复制工具,也可以进行 HDFS 复制和支持 metastore 数据库复制,因此 Hive 不需要重新解决这些问题。另外,尝试通过这些方法解决复制将导致多个事实来源,并导致同步问题,并且不容易允许使用更精细的方法(即,它们将不容易支持仅热表或分区的复制)。

Basic Approach

Hive 已经支持导出和导入命令,该导出和导入命令可用于转储表,将表 DistCp 到另一个群集并从中导入/创建。一种使进 Export 自动化的机制将为开发复制奠定基础。借助 HiveMetaStoreEventHandler 机制,可以开发出这种自动化功能,以在将某些更改提交到元存储时生成通知,然后将这些通知转换为导出动作,DistCp 动作和导入动作。

hcatalog-server-extensions jar 的一部分notification system已经部分存在。最初,它是为了能够触发 JMS 通知而开发的,Oozie 工作流可以使用该通知来启动在完成使用 HCatalog 写入表的工作时键入的关键操作。尽管目前它已存在于 HCatalog 中,但其存在的主要原因是仅在 HCatalog 之前存在范围,可以直接使用,而无需使用HCatalog IF/OF。可以借助一个将上述通知转换为动作的库来扩展它。

Implementation

Hive 的复制实现将通知事件子系统与事件到要执行的实际任务的 Map 结合在一起,以帮助实现复制过程的自动化。 Hive 提供了一个用于复制的 API,其他工具可以调用该 API 来处理复制的执行方面。

Events

仓库发生任何更改时都会触发事件。 Hive 提供了用于读取这些事件的工具的 API。每个事件都有一个关联的事件序列 ID(单调递增)。读取后,这些事件将通过 ReplicationTaskFactory 转换为复制任务。

因此,Hive 中的基本复制机制并不专门与前面描述的导出/导入(EXIM)机制绑定,而是仅用作默认的事件到任务 Map 机制。与 Hive 集成的组织或项目可能会插入其他一些 ReplicationTaskFactory 实现来实现相同的目标,这将允许进行修改,例如使用其他簿记或安全方面,或使用其他机制将数据从一个仓库移至另一个仓库。从理论上讲,即使是跨数据库技术,例如 Hive-> MySQL,也可以使用其他实现来实现某种其他形式的复制。但是,本文档将重点介绍由 EximReplicationTaskFactory 实现的 EXIM 机制的细节。

从事件到任务的 Map 完成后,将执行事件。执行的所有方面,例如 Management 适当的凭据,最佳的群集使用和调度,都不在 Hive 的范围内,因此由复制工具(如 Falcon 中的 HiveDR)执行。

事件 ID,状态 ID 和导出/导入的 Sequences

如上所述,每个事件都标有事件序列 ID。除了事件 ID 外,由于复制是异步进行的,因此在导出发生时(这将比事件本身晚一些),使用主仓库的当前状态 ID 标记导出。这样,复制就可以确定目标对象的状态是比源对象的状态新还是旧,并在导入时据此做出是否接受导入的决定。如果目标的当前对象状态比从源导出的对象的状态新,它将不会复制该更改。面对复制事件在失败后重复发生或重新启动的情况,这具有鲁棒性。

事件处理

根据事件类型(对象(数据库,表,分区)和操作(创建,添加,更改,插入,删除)的组合)对每个事件进行不同的处理。每个事件可以包括源命令,副本和目标命令。下表描述了十种事件类型以及如何通过以下描述对其进行处理。

EventSource CommandNeeds Copy?Destination Command
CreateDatabaseNo-opNoNo-op
DropDatabaseNo-opNoDROP DATABASE CASCADE
AlterDatabase(not implemented)(not implemented)(not implemented)
CreateTableEXPORT … FOR REPLICATIONYesIMPORT
DropTableNo-opNoDROP TABLE … FOR REPLICATION('id')
AlterTableEXPORT … FOR METADATA REPLICATION是(仅限元数据)IMPORT
AddPartition(多个)EXPORT … FOR REPLICATIONYes(多个)IMPORT
DropPartitionNo-opNo(多个)ALTER TABLE … DROP PARTITION(…) FOR REPLICATION('id')
AlterPartitionEXPORT … FOR METADATA REPLICATION是(仅限元数据)IMPORT
InsertEXPORT … FOR REPLICATION是(副本)IMPORT
CreateDatabase

出于安全原因,Hive 当前不允许在存在数据库之前对其进行复制,因为这可能会导致无意间复制私有数据。因此,一切都设置为无操作。但是,将来可能会重新讨论它,因此该实现包括一个 API 点。

DropDatabase

Drop 不需要在源端进行任何操作或进行任何复制。在目标端,它需要一个丢弃数据库级联。尽管这是一个危险的命令,但是当前的要求是,在数据库可以被复制之前已经存在,因为不允许在对象存在之前设置任何复制定义,从而减轻了风险,因此这被认为是预期的操作。

AlterDatabase

由于 Hive 认为数据库是容器对象,因此目前尚未实现。因此,唯一有意义的更改将是 HDFS 位置,无需复制。因此,没有 API 指向。

CreateTable

这要求在源端进行导出,复制数据,并在目标端进行导入。仅当导入的状态 ID 比副本对象的状态 ID 更新时,才会执行此导入。否则,将是无人值守。

DropTable

Drop 不需要在源端进行任何操作或进行任何复制。在目标端,如果 drop 命令中包含的状态 ID 比副本对象的状态 ID 更新,则将删除该表。否则,将是无人值守。

AlterTable

这仅需要导出,复制和导入元数据。仅当其状态 ID 比副本对象的状态 ID 更新时,才会执行导入。否则,将是无人值守。

AddPartition

可以自动添加多个分区,从而将多个导出命令 Binding 到一个事件中并复制数据。仅当导入的状态 ID 比副本对象的状态 ID 更新时,才会执行导入。否则,将是无人值守。

DropPartition

Drop 不需要在源端进行任何操作或进行任何复制。在目标端,与 AddPartition 一样,一个事件可以有多个命令。仅当它们的状态 ID 比副本对象的状态 ID 更新时才执行它们。否则,将是无人值守。

AlterPartition

这仅需要导出,复制和导入元数据。与 AddPartition 和 DropPartition 不同,AlterPartition 一次只能修改一个分区。仅当其状态 ID 比副本对象的状态 ID 更新时,才会执行导入。否则,将是无人值守。

Insert

这需要导出,复制和导入数据(而不是元数据)。当前,它是整个对象的哑副本(而不是仅应用所做的更改),尽管这是将来需要改进和优化的领域。仅当其状态 ID 比副本对象的状态 ID 更新时,才会执行导入。否则,将是无人值守。

Future Features

将来,应在以下领域中进行其他工作:

  • 使复制能够与 ACID 表一起使用,尤其是与负载平衡用例有关。仅特定的热表可能也需要负载平衡,从而可以更外科地使用复制。

  • 通过允许事件无效/折叠来限制不必要的副本。

  • 查看在消息队列(如Kafka)上或 HDFS 磁盘上(而不是在元存储中)存储生成的事件。

  • 支持复制更多的 Hive 对象,例如角色,用户等。

HIVE-7973跟踪在 Hive 中开发复制的进度。

References

[1] Kemme,B.等人,“复制:理论与实践”,B。Charron-Bost 等人,编辑,“数据库复制:教程”。德国柏林:施普林格,2010 年,第 219-252 页。