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 的内存组成:

需要注意的是,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 大小 = 8GBhive.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 的内存大小。

对于 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 并不总是会导致执行时间减少,原因有二:
- 为 LLAP I/O 分配的缓存仅对 Map Vertex 有用,与 Reduce Vertex 无关。因此,对于读取少量输入数据且大部分执行时间花在 Reduce Vertex 上的查询,缓存利用不足。对于此类查询,将缓存重新用于运行 Reduce Task 是一个更好的选择。
- 根据底层硬件,从本地磁盘读取输入数据并通过内部网络传输(例如从 NVMe SSD 读取并通过 InfiniBand 传输)可能不会比直接从 LLAP I/O 缓存读取慢得多。
因此,只有当网络和磁盘访问相对较慢时(这通常是在 Kubernetes 上运行 HivePlus 的情况),LLAP I/O 的内存开销才值得权衡。从本质上讲,计算和存储的分离使我们能够充分利用 LLAP I/O。