与 Hive-LLAP 对比
结合在单个 ContainerWorker 内并发执行多个 TaskAttempts 的能力,LLAP I/O 的支持使 HivePlus 在功能上与 Hive-LLAP 等效。因此,HivePlus 可以作为典型用例中 Hive-LLAP 的替代品。然而,尽管它们功能等价,HivePlus 和 Hive-LLAP 在架构上有着根本的不同。
HivePlus
在 HivePlus 的情况下,单个 MR3 DAGAppMaster 可以并发执行多个 DAG,从而消除了像 Hive-LLAP 中那样每个 DAG 需要一个 DAGAppMaster 的需求(如果 HiveServer2 运行在共享会话模式)。更重要的是,DAGAppMaster 对所有 ContainerWorker 具有完全控制权,从而消除了由于缺乏对其内部状态的了解而导致的潜在性能开销。例如,DAGAppMaster 永远不会发送超过 ContainerWorker 容纳能力的 TaskAttempts,这意味着 ContainerWorker 内执行 TaskAttempts 的逻辑非常简单。
Hive-LLAP
相比之下,Hive-LLAP 通过一组 Tez DAGAppMaster(有效地由 HiveServer2 拥有)和另一组 LLAP 守护进程之间的交互来执行多个 DAG。由于 DAGAppMaster 和 LLAP 守护进程是独立的进程(例如,杀死 DAGAppMaster 不会影响 LLAP 守护进程,反之亦然),两组之间的交互比 HivePlus 复杂得多。事实上,所有单独的 DAGAppMaster 本身都是独立的进程,并竞争 LLAP 守护进程提供的服务,从而在架构上增加了另一层复杂性。

HivePlus 的优势
架构上的差异导致两个系统具有不同的特性。下面我们强调 HivePlus 简洁设计相对于 Hive-LLAP 提供的优势。
1. 更易于部署
由于不需要 ZooKeeper,HivePlus 比 Hive-LLAP 容易得多来部署,无论是在 Kubernetes 上还是在 Hadoop 上。在典型的 Hadoop 集群中,如果 Metastore 的数据库服务器已经在运行,用户应该能够快速安装和运行 HivePlus。在 Kubernetes 上,HivePlus 只是一个普通的应用程序,其所有依赖都打包在 Docker 镜像中。
2. 更高的稳定性和更快的执行
HivePlus 设计的简洁性产生了显著的性能差异,特别是在高并发环境中。
简洁性也有助于我们修复在 Hive-LLAP(以及 Hive on Tez)中不容易修复的 bug。例如,Hive-LLAP 有一个与 HiveConf 和 UDFClassLoader 对象相关的内存泄漏问题(HIVE-14430)。HivePlus 没有这种内存泄漏,以下图表证明了这一点,该图表显示了在 60 小时内提交总共 250,000 个调用 UDF 的查询(每个查询使用自己的 Beeline 连接)时 HiveServer2 中的堆大小和已加载类的数量。最后,HiveServer2 仅保留 13 个 HiveConf 对象。

3. 弹性分配集群资源
对于 Hive-LLAP,管理员用户应根据运行集群的计划提前决定 LLAP 守护进程的数量及其资源使用情况。启动后,LLAP 守护进程不会释放其资源,这会带来两个不良后果:
- 当 LLAP 守护进程空闲时,其资源无法重新分配给同一集群中的繁忙应用程序。
- 当 LLAP 守护进程繁忙时,无法利用集群中的空闲资源。
这些问题与 Hive-LLAP 特别相关,因为 LLAP 守护进程通常消耗非常大的容器,往往是 Yarn 可以分配的最大容器。相比之下,HivePlus 不存在此类问题,因为 ContainerWorker 直接从 Yarn 分配:
- 为了更频繁地释放空闲的 ContainerWorker,用户只需要调整
mr3-site.xml中配置键mr3.container.idle.timeout.ms的值。或者用户可以手动杀死空闲的 ContainerWorker。 - 当存在空闲资源时,HivePlus 会自动代表其 ContainerWorker 请求更多资源。
通过这种方式,HivePlus 与现有应用程序合作,同时尝试最大化自己的资源使用。
HivePlus 提供的另一个重要优势是取消了"每个节点恰好一个容器/守护进程"的限制。在 Hive-LLAP 的情况下,集群中的每个节点只能托管一个 LLAP 守护进程。相比之下,HivePlus 对在每个节点上运行的 ContainerWorker 数量没有限制。例如,一个节点可以托管一个像 Hive-LLAP 那样的单个巨大 ContainerWorker,或者许多小的 ContainerWorker 以更细的粒度。实际上,ContainerWorker 的大小也可以不同(如果混合了多个 ContainerGroup),异构节点可以托管不同数量的 ContainerWorker。
这种分配 ContainerWorker 的灵活性使 HivePlus 能够在运行 LLAP 守护进程不切实际的环境中无缝运行。例如,内存少于 24GB 的节点(例如公共云中的小型实例)完全适合运行 HivePlus。这是因为从 MR3 的角度来看,在单个节点上运行许多小的 ContainerWorker 与在各自专用节点上运行每个小的 ContainerWorker 没有什么不同。

4. 更好地支持并发
在 Hive-LLAP 中,并发度受到 Yarn 一次可以创建的 Tez DAGAppMaster 最大数量的限制。这是因为每个运行的查询都需要一个专用的 Tez DAGAppMaster 来管理其 TaskAttempts。在实践中,管理员用户可以通过将 hive-site.xml 中的配置键 hive.server2.tez.sessions.per.default.queue 设置为合适的值来对并发查询数量施加硬限制。
在 HivePlus 中,如果 HiveServer2 运行在共享会话模式下,并发度仅受管理所有并发查询的单个 MR3 DAGAppMaster 分配的内存量限制。管理员用户还可以设置 mr3-site.xml 中的配置键 mr3.am.max.num.concurrent.dags 来指定最大并发查询数。需要注意的是,HiveServer2 也可以运行在独立会话模式下,在这种情况下,并发度像在 Hive-LLAP 中一样受到最大 MR3 DAGAppMaster 数量的限制。
与 Hive-LLAP 相比,使用单个 DAGAppMaster 为 HivePlus 带来了一个优势:在存在许多并发查询的情况下,它为单个 MR3 DAGAppMaster 消耗的内存比 Hive-LLAP 为多个 Tez DAGAppMaster 消耗的内存少得多。此外,我们观察到为许多并发查询共享一个 DAGAppMaster 实际上没有性能惩罚。这是因为 DAGAppMaster 上的计算负载与并发查询的数量不成比例,而与活动 TaskAttempts 的总数成正相关,而活动 TaskAttempts 的数量不能超过由总集群资源决定的限制。
5. 支持 hive.server2.enable.doAs=true
原则上,HivePlus 始终允许用户通过将配置键 hive.server2.enable.doAs 设置为 true 来启用 doAs,因为它只是运行在 MR3 之上的普通应用程序。然而,在安全集群中使用 LLAP I/O 时,启用 doAs 可能会成为问题,因为 LLAP I/O 模块会缓存具有不同访问权限的许多用户的数据。这也是 Hive-LLAP 不允许将 hive.server2.enable.doAs 设置为 true 的原因。
另一方面,只要禁用 LLAP I/O,HivePlus 就可以安全地启用 doAs。因此,在以下环境中:1)LLAP I/O 是可选的;2)应该启用 doAs,HivePlus 是比唯一可用替代方案(即 Hive on Tez)更好的选择。在这样的环境中,HivePlus 克服了 Hive-LLAP 的一个已知限制。
6. 其他
- 通过利用 MR3 中的 LocalProcess 模式,HiveServer2 可以在 Hadoop 集群外部启动 DAGAppMaster,例如在与 HiveServer2 本身相同的机器上运行。此功能对于测试和调试也很有用,因为 DAGAppMaster 的日志文件很容易访问。
- HiveCLI 可以使用 LLAP I/O。但需要注意的是,HiveCLI 的不同实例不共享 LLAP I/O 的缓存,因为每个实例维护自己的 ContainerWorker 集合。
- 在 Hadoop 上,Hive-LLAP 通常创建许多 Tez DAGAppMasters。相比之下,以共享会话模式运行的 HivePlus 维护一个 DAGAppMaster。