ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Apache TEZ:从MapReduce到DAG执行引擎的性能飞跃与实战指南

Apache TEZ:从MapReduce到DAG执行引擎的性能飞跃与实战指南

1. 从MapReduce到TEZ:为什么我们需要一个新的执行引擎?

如果你在数据领域工作过几年,尤其是和Hadoop打过交道,那么“MapReduce”这个词对你来说一定不陌生。它曾经是大数据处理的代名词,将复杂的分布式计算抽象成简单的Map和Reduce两个阶段,让处理海量数据成为可能。然而,在实际的生产环境中,尤其是面对越来越复杂的ETL(数据提取、转换、加载)流程、交互式查询(如Hive)和机器学习任务时,MapReduce的局限性就暴露无遗了。它的每个阶段(Map、Shuffle、Reduce)都需要将中间结果写入磁盘,这种“落盘”操作带来了巨大的I/O开销和延迟。一个复杂的Hive查询可能会被编译成几十个甚至上百个MapReduce作业,作业间的数据交换全靠HDFS(分布式文件系统)的读写,整个流程笨重、缓慢,资源利用率低下。

正是在这样的背景下,Apache TEZ应运而生。它不是要取代MapReduce的计算模型,而是要彻底革新其执行引擎。你可以把TEZ理解为一个“超级优化版”的MapReduce执行框架。它保留了MapReduce“分而治之”的核心思想,但摒弃了僵化的阶段划分和强制落盘的执行方式。TEZ的核心目标是:将复杂的数据处理任务建模为一个有向无环图(DAG),并在运行时实现极致的优化,比如任务链化、动态物理优化和资源复用,从而将性能提升一个数量级。

简单来说,当Hive或Pig这样的工具将你的SQL或脚本翻译成执行计划后,TEZ就是这个计划的“总指挥”和“高效执行者”。它不再死板地一个接一个地启动MapReduce作业,而是将整个计划看作一张图,图中的顶点是计算任务,边是数据流向。TEZ会智能地决定哪些任务可以合并(链化)、数据如何传输最省资源、内存如何复用,从而让数据像在管道中流动一样被处理,而不是在多个“磁盘水池”间来回搬运。

我第一次在生产环境将Hive的执行引擎从MapReduce切换到TEZ时,效果是立竿见影的。一个原本需要跑20分钟的日常报表作业,时间直接缩短到了4分钟以内。这种提升不是简单的百分比,而是倍数级的改变。对于需要快速响应的即席查询和复杂的多表关联作业,TEZ带来的体验提升是革命性的。它特别适合那些已经构建在Hadoop生态之上,但苦于作业执行效率的团队。

2. TEZ架构深度解析:它究竟是如何工作的?

要理解TEZ为何高效,我们必须深入其架构。TEZ的设计哲学是“将逻辑计划与物理执行解耦”,并提供极大的灵活性来优化物理执行过程。

2.1 核心架构组件

TEZ的架构主要由以下几个核心组件构成,它们共同协作,将一个逻辑计算图转化为高效的分布式执行:

  1. DAG(有向无环图):这是TEZ对计算任务的抽象。一个DAG由一个或多个**Vertex(顶点)Edge(边)**组成。每个Vertex代表一类相同的计算任务(例如,一个Map阶段或一个Reduce阶段),而Edge则定义了数据在Vertex之间的流动方式。与MapReduce固定阶段不同,TEZ允许你定义任意复杂的DAG结构。

  2. Vertex:顶点是执行的基本单元。一个Vertex中包含了需要运行的所有相同类型的Task。例如,在一个典型的Hive查询中,你可能会有用于扫描表的“Table Scan” Vertex,用于过滤的“Filter” Vertex,用于聚合的“Group By” Vertex等。

  3. Edge:边定义了数据的传输语义,这是TEZ非常强大的一点。它决定了上游Vertex产生的数据,如何被下游Vertex消费。TEZ内置了几种关键的Edge类型:

    • One-To-One Edge:上游任务产生的第i个分区的数据,直接发送给下游的第i个任务。这通常用于数据重分区(如Hash Partition)后的场景,下游任务数需与上游一致。
    • Broadcast Edge:上游产生的数据(通常是小表)被复制并发送给下游的所有任务。这在Map端关联(Map Join)中非常有用。
    • Scatter-Gather Edge:这是最常用、也最类似MapReduce Shuffle的边。上游任务将其输出数据根据Key进行分区(Scatter),然后下游任务从所有上游任务中收集(Gather)属于自己的那部分数据。TEZ对此过程做了大量优化。
  4. Task:任务是Vertex的具体实例。一个Vertex会被分解为多个并行运行的Task。每个Task运行在YARN容器(Container)中。

  5. Tez Application Master (AM):这是每个TEZ DAG作业的“大脑”。它负责向YARN申请资源,将DAG中的Vertex分解为具体的Task,调度这些Task到容器中运行,并监控整个执行过程。AM本身也运行在一个YARN容器中。

  6. Runtime Execution Engine:这是真正执行任务的“肌肉”。它接收AM的指令,在分配的容器中运行用户定义的处理器(Processor)。TEZ的一个关键特性是Container复用。AM会尝试在同一个容器上按顺序运行多个Task,从而避免反复启动JVM的开销。这对于由大量小任务组成的DAG性能提升至关重要。

2.2 TEZ与MapReduce执行模型的对比

为了更直观地理解TEZ的优化,我们来看一个简单的Hive查询的执行差异。假设我们有一个查询:SELECT dept, COUNT(*) FROM emp GROUP BY dept

  • 在MapReduce上执行

    1. 第一个MapReduce作业:Map阶段读取emp表,输出(dept, 1)。Reduce阶段按dept分组求和。这个作业结束,中间结果写入HDFS。
    2. 如果查询更复杂(比如有过滤、多表关联),可能会产生第二个、第三个MapReduce作业。每个作业之间都需要通过读写HDFS来交换数据,产生了大量不必要的序列化、反序列化和磁盘I/O。
  • 在TEZ上执行

    1. Hive优化器将整个查询生成为一个单一的DAG。
    2. DAG可能包含:一个“Table Scan” Vertex读取数据,一个“Group By” Vertex进行聚合。
    3. 这两个Vertex通过一个“Scatter-Gather” Edge连接。Table Scan Vertex的每个Task处理一部分数据,进行初步的Map端聚合(如果开启),然后根据dept字段的哈希值将数据分区,直接通过网络发送给对应的Group By Vertex的Task。
    4. Group By Vertex的Task接收来自所有上游Task的数据,进行最终的聚合计算,然后直接写出最终结果。
    5. 关键优化点
      • 去磁盘化:中间数据尽可能通过内存或直接网络传输,避免写入HDFS。
      • 任务链化:简单的操作(如过滤、投影)可以被链化到扫描任务中,在一个Task内完成,减少任务数量。
      • 动态优化:TEZ AM可以根据上游Task的运行情况,动态调整下游Task的启动策略和资源分配。

这种从“多作业批处理”到“单DAG流处理”的转变,是性能飞跃的根本原因。

3. 实战:如何部署、配置与使用TEZ

理解了原理,接下来我们进入实战环节。TEZ通常不作为独立的应用直接编程使用,而是作为Hive、Pig等上层工具的底层执行引擎。因此,我们的实战主要围绕Hive on TEZ展开。

3.1 TEZ的部署与安装

TEZ的安装相对简单,因为它本质上是一组库文件和一个框架。

  1. 下载与解压:从Apache官网下载对应Hadoop版本的TEZ发行包(例如apache-tez-0.10.x-bin.tar.gz)。将其解压到服务器上的一个目录,如/opt/tez

  2. 上传至HDFS:为了让所有集群节点都能访问到TEZ的库文件,需要将其上传到HDFS。

    hdfs dfs -mkdir -p /apps/tez hdfs dfs -put /opt/tez/share/tez.tar.gz /apps/tez/

    这里将整个share目录下的依赖打包成tez.tar.gz上传是一种常见做法,YARN会在任务启动时自动将其分发到各个容器。

  3. 配置YARN:需要告诉YARN TEZ库的位置。在$HADOOP_HOME/etc/hadoop/yarn-site.xml中添加配置:

    <property> <name>yarn.application.classpath</name> <value>$HADOOP_CONF_DIR,$HADOOP_COMMON_HOME/*,$HADOOP_COMMON_HOME/lib/*,$HADOOP_HDFS_HOME/*,$HADOOP_HDFS_HOME/lib/*,$HADOOP_MAPRED_HOME/*,$HADOOP_MAPRED_HOME/lib/*,/apps/tez/*,/apps/tez/lib/*</value> </property> <property> <name>yarn.timeline-service.enabled</name> <value>true</value> </property> <!-- 以下两项对于TEZ恢复和诊断很有帮助 --> <property> <name>yarn.timeline-service.hostname</name> <value>timeline-server-hostname</value> </property> <property> <name>yarn.timeline-service.leveldb-timeline-store.path</name> <value>/tmp/yarn/timeline</value> </property>

    注意yarn.application.classpath的配置至关重要且容易出错。必须确保路径中包含TEZ库的HDFS路径(/apps/tez/*)。路径分隔符在Linux上是冒号:,在Windows上是分号;,但在XML配置中直接写逗号,,YARN会自己处理。

  4. 配置Hive使用TEZ:在Hive的配置目录(如$HIVE_HOME/conf)下的hive-site.xml中,设置执行引擎为TEZ。

    <property> <name>hive.execution.engine</name> <value>tez</value> </property> <property> <name>hive.tez.container.size</name> <value>2048</value> <!-- 设置Tez Task容器内存大小,单位MB --> </property> <property> <name>hive.tez.java.opts</name> <value>-Xmx1638m</value> <!-- 设置JVM堆内存,通常为容器大小的0.8倍 --> </property>
  5. 启动Hive并验证:完成配置后,重启Hive服务(如果使用HiveServer2)。在Hive CLI或Beeline中,可以执行以下命令验证:

    SET hive.execution.engine;

    输出应为tez。你也可以运行一个简单的查询,并在YARN的ResourceManager Web UI上观察作业类型,应该显示为 “TEZ” 而不是 “MAPREDUCE”。

3.2 关键性能调优参数

TEZ的强大性能很大程度上依赖于合理的配置。以下是一些最核心、最有效的调优参数,你可以在Hive会话中通过SET命令临时设置,或写入hive-site.xml永久生效。

参数默认值推荐调整与说明
hive.tez.container.size-1 (自动计算)这是最重要的参数之一。指定每个Tez Task容器申请的内存(MB)。建议设置为YARN单个容器最大允许内存(yarn.scheduler.maximum-allocation-mb)的整数倍,且小于其最大值。例如,如果集群容器最大为8GB,可以设置为4GB或8GB。太小会导致频繁GC,太大会浪费资源。
hive.tez.java.opts-1 (自动计算)容器内JVM堆内存大小。通常设置为hive.tez.container.size的0.7到0.8倍,为堆外内存(如Direct Buffer、JVM自身开销)留出空间。例如,容器大小为4096MB,此参数可设为-Xmx3276m
tez.grouping.split-count-1 (自动计算)控制每个Map Task处理的最大输入分片数。对于小文件众多的场景,调大此值可以减少Task数量,避免调度开销。例如设为2,表示一个Task最多处理2个输入分片。
tez.grouping.max-size1073741824 (1GB)每个Map Task处理的数据最大字节数。如果单个HDFS块很大(如256MB),可以适当调大此值(如2GB)来减少Task数。
tez.grouping.min-size16777216 (16MB)每个Map Task处理的数据最小字节数。对于小文件,调小此值可能增加并行度,但会增多Task。需要权衡。
hive.auto.convert.jointrue务必保持开启。允许Hive将Common Join自动转换为Map Join,当小表符合条件时,能极大提升关联性能。
hive.auto.convert.join.noconditionaltask.size10000000 (10MB)控制自动Map Join的小表大小阈值。可以根据集群内存情况调整,例如提高到20MB或25MB。
tez.am.resource.memory.mb1024Application Master容器内存。对于复杂的DAG(顶点和边很多),建议增大到2048或4096,避免AM因内存不足失败。
tez.runtime.io.sort.mb100Task内部排序时使用的内存大小。如果任务需要排序的数据量大,可以适当增加(如200),但不要超过hive.tez.java.opts中堆内存的50%。
tez.runtime.unordered.output.buffer.size-mb100用于非排序输出(如Map端直接输出)的缓冲区大小。对于Map端聚合作业,增大此值可以提高性能。

实操心得:调优没有银弹。最好的方法是从默认配置开始,通过观察作业执行日志和YARN UI,找到瓶颈后再进行针对性调整。通常的顺序是:先确保内存参数(container.size,java.opts)设置合理,再根据数据特征调整分组参数(split-count,max-size),最后微调运行时参数(io.sort.mb)。

4. 高级特性与生产环境问题排查

当TEZ在集群中稳定运行后,你会接触到它的一些高级特性,也会遇到一些典型问题。掌握这些,能让你更好地驾驭TEZ。

4.1 TEZ UI与DAG可视化

TEZ提供了一个非常强大的Web UI,用于可视化DAG的执行过程,这是诊断性能问题的利器。

  1. 启用与访问:TEZ UI通常由Tez Application Master启动。在YARN ResourceManager的Web UI上,找到你的TEZ作业,点击“ApplicationMaster”链接,即可跳转到TEZ UI。
  2. 核心视图
    • DAG View:以图形化方式展示整个DAG,包括顶点、边和数据流向。你可以清晰地看到每个Vertex的状态(成功、运行中、失败)、任务数量。
    • Vertex View:点击某个顶点,可以查看该顶点下所有Task的详细信息,包括每个Task的运行节点、开始结束时间、输入输出数据量。
    • Counters:这是性能分析的关键。TEZ收集了海量的计数器,如File Input/OutputCPU timeGC timeShuffle相关的数据量等。通过对比不同阶段的计数器,可以判断是数据倾斜、GC问题还是I/O瓶颈。
    • Logs:可以直接在UI上查看AM和各个Task的日志,无需登录服务器。

使用技巧:当作业跑得慢时,我首先会打开TEZ UI。看DAG图,是不是顶点太多、太复杂?看每个Vertex的运行时间,是哪个Vertex成了瓶颈?然后看该Vertex的Counters,如果Shuffle相关的数据量异常大,很可能遇到了数据倾斜。

4.2 数据倾斜的识别与处理

数据倾斜是分布式计算中的常见“杀手”,TEZ作业也不例外。表现为少数几个Task运行时间极长,拖慢整个作业。

识别方法

  • 在TEZ UI的Vertex View中,观察Task的完成时间分布。如果大部分Task在1分钟内完成,但有几个跑了10分钟,基本可以断定是倾斜。
  • 查看该Vertex的Counters,比较不同Task的INPUT_RECORDSOUTPUT_RECORDS,数量级差异巨大即是倾斜。

处理策略

  1. SQL层面优化

    • 过滤空值:关联键或分组键中存在大量NULL值时,它们会被分发到同一个Reducer。在关联或分组前,先用WHERE key IS NOT NULL过滤掉。
    • 打散大Key:对于已知的少数几个大Key(如特定的用户ID、城市代码),可以在SQL中将其“加盐”打散。例如:
      -- 原始倾斜的Group By SELECT user_id, COUNT(*) FROM logs GROUP BY user_id; -- 加盐打散,先局部聚合,再全局聚合 SELECT user_id, SUM(cnt) FROM ( SELECT user_id, COUNT(*) as cnt FROM logs GROUP BY user_id, CEIL(RAND() * 10) -- 添加一个随机盐值(0-9) ) t GROUP BY user_id;
    • 启用倾斜关联优化:在Hive中设置hive.optimize.skewjoin=truehive.skewjoin.key,Hive会尝试将倾斜的Key识别出来,并用不同的执行策略处理。
  2. TEZ参数调整

    • 对于Group By造成的倾斜,可以尝试显著增加Reducer的数量(通过set mapred.reduce.tasks=N;),有时能缓解问题,但治标不治本。

4.3 常见错误与排查指南

以下表格整理了我遇到的一些典型TEZ错误及其解决方法:

错误现象或日志关键词可能原因排查与解决步骤
Container killed by YARN for exceeding memory limits容器内存超限。可能是hive.tez.java.opts设置过大,或任务本身内存消耗大(如处理大对象)。1. 检查YARN UI,确认容器被杀时的物理内存和虚拟内存使用量。
2. 适当调大yarn.nodemanager.vmem-pmem-ratio(虚拟内存与物理内存比例,默认2.1)。
3. 更根本的是优化任务:检查是否有笛卡尔积、不合理的数据膨胀;或适当增加hive.tez.container.sizehive.tez.java.opts
ApplicationMaster host not specified或 AM启动失败TEZ库路径配置错误,YARN无法找到TEZ的JAR包。1. 仔细检查yarn-site.xml中的yarn.application.classpath,确保包含TEZ在HDFS上的路径(如/apps/tez/*)。
2. 确认HDFS上的tez.tar.gz文件存在且权限正确。
作业长时间卡在ACCEPTED状态集群资源不足,作业在排队。1. 检查YARN队列资源使用情况。
2. 检查是否有其他大作业占用了资源。
3. 调整作业优先级或减少作业申请的容器资源量。
Vertex failed, vertexName=Map 1某个顶点失败具体任务执行失败。需要查看失败Task的日志。1. 在TEZ UI上点击失败的Vertex,找到失败的Task,查看其stderrsyslog
2. 常见原因:数据格式异常、UDF代码报错、磁盘空间不足、节点硬件故障等。根据日志具体分析。
作业性能突然下降可能与集群状态、数据分布变化有关。1. 对比历史成功作业的DAG图和Counters。
2. 检查HDFS数据块分布是否均匀,是否有大量小文件产生。
3. 检查集群节点是否有负载过高或网络波动。

排查心法:遇到TEZ作业问题,遵循“从外到内,从宏观到微观”的原则。先看YARN RM UI,作业状态是什么?资源申请是否成功?再看TEZ UI,DAG执行到哪一步卡住了?是哪个Vertex出了问题?最后深入该Vertex失败Task的日志,找到根本原因。善用日志和可视化工具,是解决分布式问题的关键。

5. 超越Hive:TEZ在其他生态中的应用与未来

虽然Hive是TEZ最广为人知的应用场景,但它的价值并不局限于此。TEZ作为一个通用的DAG执行框架,其设计目标就是服务于整个Hadoop生态。

Pig on TEZ:Apache Pig同样支持将数据流脚本编译成TEZ DAG执行,获得了与Hive类似的性能提升。对于习惯Pig Latin语法的用户,这是一个无缝的升级选项。

自定义TEZ应用:TEZ提供了完整的Java API,允许开发者直接编写基于DAG的分布式应用程序。这为那些需要比MapReduce更灵活、比Spark更贴近Hadoop底层生态(如需要直接与HDFS、HBase交互)的复杂数据处理流水线提供了可能。你可以定义自己的Processor来处理数据,定义Edge来控制数据流向,构建出高度定制化的执行图。不过,这需要较高的开发门槛,通常只有在对性能有极致要求或有特殊流程需求的场景下才会使用。

与Spark的对比与选型:这是很多团队会问的问题。Apache Spark是另一个强大的内存计算框架,也使用DAG调度。如何选择?

  • TEZ:更像是“Hadoop原生生态的执行加速器”。它的优势在于与Hive、Pig等现有工具无缝集成,迁移成本极低,能直接利用Hadoop集群现有的投资和运维体系。它的资源管理和调度深度依赖YARN,与Hadoop栈结合更紧密。适合已经重度依赖Hive进行数据仓库建设,希望以最小代价提升作业性能的团队。
  • Spark:是一个“更独立、更通用的数据计算栈”。它不仅提供执行引擎(Spark Core),还提供了更丰富的上层库(Spark SQL, MLlib, Structured Streaming),形成了一个更完整的生态。特别是在机器学习、流处理和交互式分析场景,Spark的API更现代、生态更活跃。适合启动新项目、对多种计算范式(批、流、ML)有统一需求的团队。

未来展望:随着云原生和存算分离架构的兴起,计算引擎的竞争更加激烈。TEZ作为Hadoop生态内的重要优化引擎,其未来在于继续深化与上层SQL引擎(如Hive LLAP)的集成,提供更极致的交互查询体验。同时,在云上对象存储(如S3、OSS)成为主流存储的背景下,如何优化数据读取和Shuffle性能,也是TEZ需要持续演进的方向。

从我个人的实践经验来看,TEZ绝非一个过时的技术。对于任何一个正在使用或维护基于Hadoop传统数据仓库(尤其是Hive)的企业,将执行引擎从MapReduce迁移到TEZ,几乎是性价比最高的性能优化手段,没有之一。它不需要重写业务逻辑,不需要迁移数据,通常只需要调整配置和重启服务,就能带来显著的收益。理解它的原理,掌握它的调优和排错方法,是每个大数据平台工程师的必备技能。当你看到那些曾经需要喝杯咖啡才能跑完的作业,现在几十秒就返回结果时,你会觉得这一切的学习和折腾都是值得的。

返回列表