跳到主要内容

LLAP I/O

配置 LLAP I/O

HivePlus 使用与 Hive-LLAP 完全相同的配置键配置 LLAP I/O。

  • hive.llap.io.enabled 指定是否启用 LLAP I/O。如果设置为 true,Hive 会将用于 LLAP I/O 的 MR3 DaemonTask 附加到 all-in-one 方案下的唯一 ContainerGroup 和 per-map-reduce 方案下的 Map ContainerGroup。
  • hive.llap.io.memory.size 指定用于缓存数据的大小。
  • hive.llap.io.threadpool.size 指定用于在 LLAP I/O 中提供请求的线程数。
  • hive.llap.client.consistent.splits 应设置为 true 以使用 InputSplit 的一致性哈希(以便相同的 InputSplit 始终映射到相同的 ContainerWorker)。

但是,与 Hive-LLAP 不同,Java VM 开销的 headroom 大小(以 MB 为单位)可以使用配置键 hive.mr3.llap.headroom.mb(这是 HivePlus 中的新配置)明确指定。下图显示了 all-in-one 方案下具有 LLAP I/O 的 ContainerWorker 的内存组成:

llap.memory

需要注意的是,Java VM 的堆大小(用于 -Xmx 选项)是通过使用配置键 hive.mr3.container.max.java.heap.fraction 指定的因子乘以所有 TaskAttempt 的内存大小(例如,在 all-in-one 方案下使用配置键 hive.mr3.all-in-one.containergroup.memory.mb 指定)得到的。

以下是配置 LLAP I/O 时 hive.llap.io.enabled 设置为 true 的几个示例。

  • hive.mr3.all-in-one.containergroup.memory.mb=40960
    hive.mr3.container.max.java.heap.fraction=1.0f
    hive.mr3.llap.headroom.mb=8192
    hive.llap.io.memory.size=32Gb
    TaskAttempt 的内存 = 40960MB = 40GB
    ContainerWorker 大小 = 40GB + 8GB + 32GB = 80GB
    堆大小 = 40960MB * 1.0 = 40GB
    Java VM 开销的内存 = Headroom 大小 = 8GB
  • hive.mr3.all-in-one.containergroup.memory.mb=40960
    hive.mr3.container.max.java.heap.fraction=0.8f
    hive.mr3.llap.headroom.mb=0
    hive.llap.io.memory.size=40Gb
    TaskAttempt 的内存 = 40960MB = 40GB
    ContainerWorker 大小 = 40GB + 0GB + 40GB = 80GB
    堆大小 = 40960MB * 0.8 = 32GB
    Java VM 开销的内存 = TaskAttempt 的内存 - 堆大小 = 8GB

由于 HivePlus 中的 LLAP I/O 不依赖 ZooKeeper,因此应在 hive-site.xml 中适当设置以下配置键,以使不会尝试与 ZooKeeper 通信。

  • hive.llap.hs2.coordinator.enabled 应设置为 false。
  • hive.llap.daemon.service.hosts 应设置为空列表。

使用内存映射文件进行缓存

如果在 hive-site.xml 中将配置键 hive.llap.io.allocator.mmap 设置为 true,LLAP I/O 会使用内存映射文件(而不是内存)来缓存通过 HiveInputFormat 读取的数据。内存映射文件在配置键 hive.llap.io.allocator.mmap.path 指定的目录下创建(但对用户不可见)。

由于 LLAP I/O 不消耗内存来缓存数据,具有 LLAP I/O 的 ContainerWorker 的内存组成略有不同(在 all-in-one 方案下)。本质上,配置键 hive.llap.io.memory.size 仅指定用于缓存数据的内存映射文件的总大小,不影响 ContainerWorker 的内存大小。

llap.memory.mapped

对于 Kubernetes 上的 HivePlus,如果在 hive-site.xml 中将配置键 hive.llap.io.allocator.mmap 设置为 true,用户应使用配置键 hive.llap.io.allocator.mmap.path 来指定 ContainerWorker Pod 内的有效目录,以创建内存映射文件。使用 ContainerWorker Pod 内的现有目录(例如 /tmp)在理论上是可以的,但为了性能,用户应在工作节点上找到快速设备(例如 NVMe 磁盘),将其上的目录作为 hostPath 卷挂载到 ContainerWorker Pod 中,并专门使用该 hostPath 卷进行 LLAP I/O。

例如,假设用户希望使用工作节点上的本地目录 /nvme/llap 进行 LLAP I/O。用户应设置以下配置键:

  • mr3-site.xml 中的 mr3.k8s.pod.worker.additional.hostpaths 应设置为 /nvme/llap。然后 MR3 使用本地目录 /nvme/llap 在每个 ContainerWorker Pod 中挂载 hostPath 卷。
  • hive-site.xml 中的 hive.llap.io.allocator.mmap.path 也应设置为 /nvme/llap。这是因为 hostPath 卷挂载在相同的目录 /nvme/llap 上。现在 LLAP I/O 有效地使用工作节点上的本地目录 /nvme/llap 来创建内存映射文件。

Kubernetes 上的 LLAP I/O

虽然 Kubernetes 上的 HivePlus 可以以与在 Hadoop 或独立模式下完全相同的方式利用 LLAP I/O,但它的 LLAP I/O 使用值得关注,因为计算和存储的分离使得启用 LLAP I/O 变得非常可取。需要注意的是,如果数据源与计算节点位于同一位置,使用 LLAP I/O 并不总是会导致执行时间减少,原因有二:

  1. 为 LLAP I/O 分配的缓存仅对 Map Vertex 有用,与 Reduce Vertex 无关。因此,对于读取少量输入数据且大部分执行时间花在 Reduce Vertex 上的查询,缓存利用不足。对于此类查询,将缓存重新用于运行 Reduce Task 是一个更好的选择。
  2. 根据底层硬件,从本地磁盘读取输入数据并通过内部网络传输(例如从 NVMe SSD 读取并通过 InfiniBand 传输)可能不会比直接从 LLAP I/O 缓存读取慢得多。

因此,只有当网络和磁盘访问相对较慢时(这通常是在 Kubernetes 上运行 HivePlus 的情况),LLAP I/O 的内存开销才值得权衡。从本质上讲,计算和存储的分离使我们能够充分利用 LLAP I/O。