ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Hadoop YARN资源管理核心机制与生产环境调优实践

Hadoop YARN资源管理核心机制与生产环境调优实践 1. 先搞清楚YARN在Hadoop生态里到底扮演什么角色做大数据这行Hadoop这个词几乎是绕不开的入场券。而Hadoop之所以能成为大数据领域的基石靠的绝不只是HDFS那套分布式文件系统更关键的是它背后那套能把集群资源管得明明白白的调度框架——YARN。很多人学Hadoop装完HDFS就以为完事了等到跑Spark作业、跑MapReduce任务时发现资源老是抢来抢去任务排队排到怀疑人生才回过头来补YARN的知识。这篇文章我就把YARN资源管理这件事从头到尾捋一遍从架构原理到配置实操再到常见坑的排查思路尽量做到让你看完能直接上手。YARN的全称是Yet Another Resource Negotiator翻译过来就是又一个资源协调器。它的核心职责就一句话把集群里的CPU、内存这些资源统一管起来然后按照你设定的策略分配给各个任务。你可以把它理解成一个大型停车场的中央调度系统——停车场有多少车位、哪些车位被占了、哪辆车该停哪、停车场满了之后新来的车怎么排队全部由它说了算。没有它HDFS再能存数据计算任务也只能各抢各的、乱成一锅粥。这篇文章适合谁看刚搭完Hadoop伪分布式、准备跑第一个MapReduce或Spark作业的新手正在准备大数据岗位面试的求职者以及已经在集群环境里跑任务但经常被资源问题折磨的运维和开发。我尽量用实际操作中遇到的真实场景来讲不堆理论因为资源管理这东西光看文档是真的学不会的。2. YARN的结构设计与调度机制拆解2.1 组件分工RM、NM、AM、Container各管什么先把YARN的四大核心组件弄清楚后面看配置和报错日志才不至于两眼一抹黑。第一个是ResourceManager简称RM是整个集群的大脑。它全局只有一个Active状态负责接收各个应用的资源申请请求然后根据集群当前的资源使用情况做出分配决策。RM内部还维护了每个NodeManager上报上来的资源信息相当于一张实时的集群资源总表。第二个是NodeManager简称NM是集群中每个节点上的管家。每台机器上跑一个NM负责启动和管理本机上的Container监控本机的CPU、内存使用情况并定时向RM汇报心跳。如果某个Container把内存吃爆了NM有权直接把它干掉并向RM报告。第三个是ApplicationMaster简称AM是每个应用自己的项目经理。注意每个应用一个Spark作业、一个MapReduce作业都会启动一个专属的AM它负责向RM申请具体的Container资源并协调这些Container来完成任务。可以这样理解RM管全局AM管单场战斗。第四个是Container这是YARN分配资源的最小单位。一个Container其实就是一台机器上被隔离出来的一小块CPU和内存资源可以理解成停车场里一个具体的车位。任务的实际计算逻辑就是在Container里跑的容器内可以跑MapReduce的Map或Reduce任务也可以跑Spark的Executor。这里有个很多新手容易混淆的点Container不等于Docker容器。YARN的Container指的是资源隔离的抽象概念虽然现在很多发行版也会用Linux CGroup做底层隔离但它在诞生之初只是JVM层面的资源边界。面试时被问到这一点能讲清楚的同学不多但这就是加分项。2.2 一次任务从提交到结束的完整旅程搞清楚组件之后我把一次Spark任务在YARN上的完整执行流程走一遍这对理解YARN和排查问题都特别有帮助。假设你已经把Spark作业打包好执行了spark-submit命令。第一步客户端把作业的Jar包和依赖上传到HDFS上然后向RM发起一个提交应用的请求。RM收到请求后会先确认有没有队列资源、用户权限对不对然后在一个NodeManager节点上启动一个Container并在里面拉起应用的ApplicationMaster。第二步AM启动之后它需要先向RM注册自己然后根据作业的资源配置参数比如要多少个Executor、每个Executor要多少内存和CPU向RM发起资源申请。RM收到申请后会根据调度器和当前集群资源情况把可用的Container列表返回给AM。AM拿到这些Container后通过NM在对应的节点上启动任务进程也就是真正的计算逻辑开始执行。第三步任务执行过程中AM要持续跟踪每个任务的进度如果某个任务失败AM负责重新申请Container并重试。所有任务完成后AM向RM注销自己释放所有资源整个流程结束。这个流程里有一个值得注意的点AM本身就是运行在一个Container里的所以AM自己也要消耗资源。很多人在配置Spark参数时只算了Executor的资源忽略了AM的资源导致在资源紧张的集群上出现提交任务就失败的现象日志报错往往是AM container is running beyond memory limits之类的。这个问题后面我会单独讲。2.3 三种调度器怎么选FIFO、Capacity、FairYARN的调度器决定了当多个任务同时申请资源时先给谁、给多少。默认情况下Hadoop自带的调度器有三种实际工作中选错调度器导致的排队长问题特别常见。FIFO Scheduler是最简单的先进先出队列谁先提交谁先执行。它的优点是实现简单缺点也很致命——如果第一个大作业占满了资源后面所有的小作业都得排队等集群利用率极低。所以现在几乎没有生产环境会用纯FIFO。Capacity Scheduler是Hadoop默认的调度器它把集群资源按百分比划分成多个队列每个队列可以设置资源上限队列内部的作业再按FIFO或优先级调度。这种设计的好处是多租户之间资源互不挤占数据团队提交的作业再大也不会把算法团队的队列资源全抢走。生产环境如果不确定选什么直接默认Capacity Scheduler基本不会错。Fair Scheduler的目标是让所有正在运行的作业尽可能公平地分享资源。它采用最小共享量动态调整的机制当只有一个作业运行时它可以用整个集群的资源当第二个作业提交后第一个作业的资源会被逐渐收回让两个作业各占一半左右。这种调度器适合即席查询比较多的场景比如多个业务方共用一个集群大家都不希望自己的小查询被大任务卡死。选调度器的核心判断依据是你的集群是对内专用还是对外共享。如果是单一部门跑批处理Capacity Scheduler足够如果是多团队共用一个集群、又有较多交互式查询Fair Scheduler的体验会更好。这块建议在搭建集群之前就想清楚因为配置文件改起来容易但运行中的集群切换调度器需要重启RM代价不小。3. 从伪分布式到集群YARN的安装配置实战3.1 伪分布式环境下YARN的最小配置如果你想在一台机器上快速体验YARN的完整流程伪分布式模式是最快的路径。网上关于Hadoop伪分布式的教程一抓一大把但很多教程只带你装完HDFS就不管了YARN部分的配置容易被忽略。这里我给出一个能跑通的最小配置集。在Hadoop的etc/hadoop/目录下核心配置文件是yarn-site.xml。伪分布式模式下你只需要把以下的几个关键属性配好configuration property nameyarn.nodemanager.aux-services/name valuemapreduce_shuffle/value /property property nameyarn.nodemanager.aux-services.mapreduce_shuffle.class/name valueorg.apache.hadoop.mapred.ShuffleHandler/value /property /configuration这段配置的作用是把NodeManager的辅助服务打开MapReduce作业在Shuffle阶段需要依赖这个服务来传输数据。如果忘了配MapReduce作业会卡在Shuffle阶段报错但Spark作业可能不受影响所以很多人在跑Spark时没发现问题一跑MapReduce就翻车就是这个原因。配置完之后执行start-yarn.sh脚本启动YARN然后用jps命令检查如果能看到ResourceManager和NodeManager两个进程就说明启动成功了。浏览器打开RM的Web UI默认端口8088能在首页看到集群的活跃节点数、已用资源和可用资源总量。这一步能看到资源数字跳起来基本上YARN就活了。补充一个伪分布式下很常见的细节如果你是用普通用户启动YARN会遇到端口绑定权限问题Linux下1024以下端口需要root权限这时候要么换一个高端口要么临时用sudo但不建议直接用root跑集群后面出问题排查更麻烦。3.2 集群模式下资源规划的关键参数伪分布式只是学习用真正的工作环境肯定是要上集群的。集群部署YARN时最核心的两个资源配置参数是yarn.nodemanager.resource.memory-mb和yarn.nodemanager.resource.cpu-vcores。前者表示每个NodeManager节点最多能给YARN使用的物理内存总量后者表示该节点最多能分配给YARN的虚拟核数。这里有个很多新手都会踩的坑memory-mb这个值不要往大了乱填。给YARN的内存多了留给操作系统、HDFS DataNode、NodeManager自身的内存就不够了很容易出现机器内存被吃满、系统开始疯狂Swap的情况。我的习惯是如果一台机器是64GB内存那么给YARN的memory-mb一般设置为48GB到56GB之间剩下的留给系统和其他进程。具体还要看节点上还跑不跑DataNode、HBase RegionServer这些进程如果都挤在一起就要再保守一点。CPU的配置相对简单但是要留意YARN的vcore和物理核数不是简单的一比一对应。YARN默认允许超卖也就是虚拟核数可以大于物理核数一般比例建议在1.5到2倍之间。举个例子一台16核的机器可以配置成yarn.nodemanager.resource.cpu-vcores24这样能提升CPU利用率但前提是任务的执行模型不是死循环CPU密集型的否则反而会拖慢整体速度。集群模式下ResourceManager的高可用是必须要考虑的。生产环境至少部署两个RM节点用ZooKeeper做自动故障转移。配置好后Active RM挂了Standby RM会自动顶上客户端无感知。很多中小型公司图省事只部署一个RM结果RM进程一挂整个集群不可用这个钱真的不建议省。3.3 用Python通过REST API管理YARN任务很多人可能不知道YARN除了Web UI和命令行之外还提供了一套完整的REST API所有页面上的操作底层都是调的这套接口。这意味着我们完全可以用Python脚本去管理YARN任务比如查询正在跑的任务列表、查看任务日志、甚至杀掉异常任务。YARN的ResourceManager默认暴露了多个REST API接口最常用的是# 查询所有应用列表 curl http://rm_host:8088/ws/v1/cluster/apps # 查询单个应用详情 curl http://rm_host:8088/ws/v1/cluster/apps/{application_id} # 查询集群指标 curl http://rm_host:8088/ws/v1/cluster/metrics直接curl就能拿到JSON格式的数据然后可以在Python里做二次封装。我写过一个简单的Python脚本定时扫描集群上运行时长超过阈值的任务自动发送告警邮件还可以通过API调用PUT接口把卡死的任务杀掉整个过程不到100行代码。Python的标准库urllib就够用不需要额外装requests。不过要提醒一句通过REST API杀任务属于高权限操作生产环境一定要做好认证和授权。Hadoop从2.9版本开始默认开启YARN的Timeline Service部分API的调用方式有所变化遇到401或者404先确认一下Hadoop版本对应的API文档。另外千万注意REST API和Web UI的端口虽然默认都是8088但在高可用架构下需要先找到当前Active RM的地址否则请求落到Standby RM上会直接被拒绝。4. YARN资源调优的实战经验4.1 内存三层模型容器、堆、物理内存的关系我在实际工作中发现很多人配置YARN内存参数时非常随意导致作业一直报OOM内存溢出错误。原因在于YARN的内存管理实际上是有三个层次的概念混淆这三层是很多问题的根源。第一层是Container级别也就是YARN向NodeManager申请的内存。你在spark-submit里指定的executor-memory只是Container内存的一部分。第二层是JVM堆内存这是给应用进程实际使用的堆空间Spark的spark.executor.memory配置的就是堆内存的大小。第三层是物理内存包括JVM堆外内存、元空间、线程栈等Container实际占用的物理内存往往比配置的堆内存大不少。YARN默认会要求Container的物理内存不超过你申请的内存上限如果超过NodeManager会直接杀掉这个Container。这就解释了一个非常经典的现象你明明给Spark Executor配了4GB内存跑着跑着日志却报Container killed by the ApplicationMaster或者Running beyond physical memory limits。原因就是Executor除了堆内存外还用了大量堆外内存超出你申请的总量。解决思路很简单把Container的内存申请得比JVM堆内存大一些。在Spark里有个参数spark.yarn.executor.memoryOverhead默认是executor-memory的10%如果你的作业涉及大量Shuffle或者使用了堆外缓存把这个比例调高到15%到20%会稳妥很多。如果是MapReduce作业对应的参数是mapreduce.reduce.memory.mb和mapreduce.reduce.java.opts注意后者要设置成比前者小一些。4.2 核数和并行度的关系不是核心越多越快YARN里的vcore配置对很多刚接触的人来说是个纯粹的玄学问题。我见过有人把每个Executor的核心数从1调到4本意是想加快处理速度结果任务反而变慢了。原因很简单YARN上的并行度不仅仅取决于核数还取决于每个任务实际能不能把核用起来。在Spark on YARN中一个Executor能同时跑多少个Task取决于spark.executor.cores这个参数。理论上一个Executor有4个核就能同时运行4个Task。但如果你的数据源是HDFS每个Task本质上是一个数据分区的处理而数据分区的数量是在读取数据时就决定了的。假设一个作业只有20个分区你就算开了100个核实际同时执行的也只有20个Task剩下的核都在空转白白占着资源不放。调优的思路应该是先根据数据量确定Task的期望数量一般控制在每个Task处理128MB到256MB数据量然后反推需要的Executor数量和每个Executor的核数。举个例子一个作业要处理1TB数据HDFS块大小是128MB数据分区大概是8000个。如果每个Executor配4个核、每核跑1个Task那么大约需要2000个Executor才能同时把分区跑完显然不合理所以要结合集群规模调整分区数而不是一股脑地加核。YARN调度层面还有一个容易忽略的点Container的核数配置决定了它被分配到的CPU权重。假如一个节点的物理核只有16个你给一个Executor配了8个vcore那么这个Executor占用的就是一个大块资源其他小任务只能在剩下的核上跑。如果一个集群里既有大作业又有小作业建议把Executor的核数控制在2到4之间这样调度器的资源切分会更灵活。4.3 队列配置与资源隔离的实际案例说完单个作业的参数再来说说集群层面的资源隔离。生产环境里YARN的队列规划直接决定了多个团队能不能和平共处。我参与过一个集群的治理项目当时的场景是数据开发团队每天凌晨跑T1的批量任务算法团队白天做模型训练产品团队随时可能有即席查询。一开始大家都挤在同一个默认队列里结果就是白天的即席查询被凌晨遗留的批量任务堵住体验极差。后来我们把Capacity Scheduler的队列调整为三层结构一个batch队列跑定时批量任务容量占比60%一个interactive队列跑即席查询容量占比20%但设置了最高可抢占到40%资源一个training队列跑模型训练容量占比20%同时限制了同一个用户最多提交的任务数防止某个人误操作提交了一堆并行训练任务把集群拖垮。Capacity Scheduler的队列配置在capacity-scheduler.xml里核心的配置项包括队列的capacity容量百分比、maximum-capacity最大可占用的资源上限、maximum-am-resource-percent队列中用于启动AM的资源比例。这里有一个细节值得特别注意yarn.scheduler.capacity.maximum-am-resource-percent这个参数默认是0.1也就是说默认只有10%的资源能用于启动ApplicationMaster。如果你提交的任务特别多AM占用的资源超过了这个比例新任务就会一直处于ACCEPTED状态看起来像卡死了一样日志上却没有任何报错。实际经验总结下来队列调优不是一次性工作。你需要持续观察每个队列的资源使用曲线、平均等待时间和任务失败率然后动态调整容量配比。Hadoop的配置是做不了热更新的改完capacity-scheduler.xml之后要执行yarn rmadmin -refreshQueues才能生效这条命令建议收藏它是线上队列调整的主要手段。5. 高频问题排查与避坑清单5.1 集群资源充足但任务一直ACCEPTED这是我在技术支持中遇到频率最高的问题。RM Web UI上集群明明有不少可用的CPU和内存但是新提交的任务就是一直卡在ACCEPTED状态既不运行也不报错。很多人第一次遇到时都会怀疑集群出故障了其实排查思路很简单。优先检查AM资源比例。前面提到的yarn.scheduler.capacity.maximum-am-resource-percent参数如果设置得太小就会出现这种资源充足但任务无法启动的情况。因为RM要启动AM而AM本身也要占用Container资源如果AM资源配额被占满了新任务就只能排队。检查方法是在RM Web UI的Scheduler页面里查看每个队列的AM Used资源和AM Max资源如果Used已经顶到Max了就是这个问题。还有一种可能性是队列ACL限制。YARN的每个队列可以通过yarn.scheduler.capacity.root.队列名.acl_submit_applications参数限定允许提交任务的用户和用户组。如果你切换了一个用户去提交任务而这个用户不在ACL白名单里任务也会一直卡在PENDING状态。这种问题日志里会出现User xxx cannot submit applications to queue root.xxx之类的提示细心一点应该能看到。最后要检查的是提交任务的客户端本身。如果你用的是spark-submit注意--queue参数指定的队列名是不是真的存在。我们踩过最经典的坑是开发环境队列名是root.dev生产环境是root.prod脚本里忘了改结果任务一直在某个不存在的队列里排队看起来就像卡住了一样。5.2 Container运行中被强杀的排查思路另一个高频问题就是Container被NodeManager强杀。表现是作业跑了十几分钟甚至几小时后突然报一堆Container killed然后AM尝试重试几次后整个作业直接失败。引起这个问题的原因五花八门我按排查优先级列一下。第一个要查的是物理内存超限。日志里如果出现Container [pidxxx, containerIDxxx] is running beyond physical memory limits. Current usage: 5.2GB of 4GB physical memory used说明Container的实际内存使用超过了申请值。解决方法就是调大spark.yarn.executor.memoryOverhead或者直接在spark-submit时把executor-memory加大。这是最经典的内存问题十个Container被强杀里至少有六个是它。第二个要查的是本地磁盘空间不足。NodeManager在运行Container时会在本机本地目录写Shuffle数据、Spark临时数据。如果集群的磁盘没做监控某个节点写满了NodeManager会杀掉该节点上的Container。报错信息里一般会出现local dir或者Disk out of space字样。这时候除了清理磁盘还要去检查yarn.nodemanager.local-dirs的配置是否合理最好把目录分散挂载到多块磁盘上避免单盘打满。第三个可能的原因就比较隐蔽了CGroup隔离导致的进程被杀。在新版Hadoop中如果开启了CGroup的CPU隔离但容器的CPU份额设置不对某些高CPU消耗的Container会被内核的OOM Killer干掉而YARN日志里未必能看到明显的报错只能通过查看系统日志或者dmesg来发现。这种情况多见于物理内存足够、但CPU限制过死的场景遇到时建议适当调大vcore的配置。5.3 压箱底排查技巧速查表我把这些年排查YARN问题时总结出来的常用命令和检查点整理成了一张速查表方便你遇到问题时快速定位方向。问题现象常见原因快速验证命令任务一直ACCEPTEDAM资源比例不足查看RM Web UI的Scheduler页面对比AM Used和AM MaxContainer被强杀物理内存超限grep physical memory limits 作业日志任务提交被拒绝队列ACL权限不足检查yarn logs中是否有cannot submit字样Shuffle阶段卡住忘了配aux-services查看NM日志中的ShuffleHandler是否启动RM频繁主备切换网络抖动或GC停顿检查两个RM节点的系统负载和GC日志节点上任务全部失败本地磁盘写满df -h查看yarn.nodemanager.local-dirs挂载点还有一个排查神器是yarn logs命令。当你跑完一个失败的应用执行yarn logs -applicationId application_xxx_xxx可以拉取整个应用所有Container的标准输出和错误日志。这个命令在处理任务失败但搞不清哪个环节出错的场景时特别有用省去了逐台机器翻日志的痛苦。需要提醒的是这个命令需要开启日志聚合yarn.log-aggregation-enable否则日志只存在各个节点上用命令是拉不下来的。最后再说一个面试官特别爱问的坑YARN和Spark版本兼容性。Spark 2.x对应Hadoop 2.x没问题但Spark 3.x配合老版本Hadoop 2.6以下的集群可能会有RPC协议不兼容导致任务无法提交。如果你在生产环境遇到了莫名其妙的客户端连接问题先看看Jar包里的hadoop-client版本和集群实际版本是不是同一个大版本版本引起的坑往往查得人头疼。6. 聊聊这几年的使用心得YARN这个东西乍一看只是Hadoop里一个资源调度的模块但用久了你会发现它几乎是整个大数据生态的基座。从最早的MapReduce到后来的Spark、Flink、Tez只要跑在Hadoop集群上底层调度全靠YARN撑腰。学会了YARN你其实就掌握了一套通用的分布式资源管理方法论后面再去接触Kubernetes这些容器调度系统很多概念是相通的——ResourceManager对应K8s的SchedulerNodeManager对应KubeletContainer对应Pod只是抽象层次不同而已。我个人在踩过无数次坑之后的体会是YARN相关的难题八成都出在配置参数之间互相影响这件事上。内存配小了会被杀配大了会浪费核数配少了并行度不够配多了又会加剧等待队列容量设得不合理一个人能堵死整个组。所以遇到问题不要急着一个参数一个参数地试错而是先搞清楚整体架构再从上到下排查效果会好很多。最后分享一个小技巧Hadoop的yarn-site.xml里有个隐藏参数yarn.resourcemanager.system-metrics-publisher.enabled默认是false。生产环境建议把它打开这样RM会把各队列的详细资源使用指标发布到监控系统里配合Grafana做可视化之后你能提前发现很多资源倾斜的苗头远好过等任务卡死了再回头查日志。这个改动不需要重启集群改完配置刷新一下RM的配置就能生效值得一试。
返回列表