大厂Yarn面试题集锦及参考答案
客户端提交 MapReduce 作业时,ResourceManager 返回的 “资源路径” 具体是什么?其在作业执行过程中有什么作用?
当客户端向 YARN 的 ResourceManager 提交 MapReduce 作业时,ResourceManager 会返回一个资源路径,这实际上是一个 HDFS 上的临时目录路径。具体来说,该路径的默认格式通常为:
/user/<username>/.staging/<application_id>
,其中:
<username>
是提交作业的用户名;<application_id>
是 ResourceManager 为此作业生成的唯一标识符(例如application_1621234567890_001
)。
资源路径的作用:
- 存储作业依赖文件客户端会将作业运行所需的资源文件上传到此路径,包括: Job JAR 包(MapReduce 程序的打包文件);配置文件(如 mapred-site.xml 或自定义配置文件);输入分片信息(由客户端生成的作业元数据);其他依赖库(如第三方 JAR 文件)。这些文件会被分布式缓存机制自动分发到各个任务执行的节点。
- 支持容错与状态跟踪资源路径中的内容会被 MRAppMaster(MapReduce ApplicationMaster)和 NodeManager 访问,以确保任务执行的一致性。例如,当某个任务失败时,MRAppMaster 可以根据资源路径重新获取依赖文件并重新调度任务。
- 资源本地化(Localization)NodeManager 在启动 Container 前,会从该路径下载所需的文件到本地磁盘,这一过程称为资源本地化。本地化后的文件会被缓存在节点上,避免重复下载,从而提升任务启动效率。
- 作业清理作业完成后(无论成功或失败),MRAppMaster 会自动删除此路径以释放 HDFS 存储空间。如果作业因异常未能正常清理,管理员可通过该路径手动处理残留文件。
资源路径的生命周期:
- 创建阶段:客户端提交作业时,ResourceManager 生成唯一路径;
- 上传阶段:客户端将依赖文件上传至该路径;
- 使用阶段:MRAppMaster 和 NodeManager 读取路径中的文件;
- 清理阶段:作业结束后自动删除路径。
关键设计意义:
- 解耦资源存储与计算:通过 HDFS 集中管理资源文件,避免将依赖捆绑在计算节点本地;
- 支持弹性扩展:无论集群规模如何变化,任务均可通过统一路径获取资源;
- 简化容错逻辑:文件在 HDFS 上具备多副本容错能力,避免因单点故障导致作业无法恢复。
总结
ResourceManager 返回的资源路径是 YARN 作业执行的核心纽带,它确保了作业依赖的可靠存储、高效分发和自动清理,是 YARN 实现资源管理与任务调度解耦的关键设计之一。
为什么 YARN 采用 pull-based 通信模型分配资源?它与 push-based 通信模型有哪些区别?
YARN 选择 pull-based 通信模型(拉取模型)的核心原因在于提升资源调度的灵活性和可扩展性。在这种模型下,ApplicationMaster(AM) 主动向 ResourceManager(RM) 发起资源请求,RM 根据集群整体资源状态返回可用资源。相比之下,push-based 模型由中央调度器主动推送资源给任务,可能导致资源分配僵化和响应延迟。
pull-based 与 push-based 的主要区别:
主动权 |
AM 主动请求资源 |
调度器强制分配资源 |
资源利用率 |
按需分配,减少资源碎片 |
可能因预分配导致资源闲置 |
容错性 |
AM 可灵活重试请求,适应节点故障 |
依赖调度器全局状态,恢复复杂 |
通信开销 |
请求频率由 AM 控制,适合大规模集群 |
高频推送可能引发网络拥塞 |
YARN 选择 pull-based 的关键优势:
- 动态适应性:AM 根据任务实际需求请求资源(例如 Map 任务需低 CPU,Reduce 任务需高内存),避免资源浪费。
- 降低 RM 压力:RM 仅响应资源请求,无需维护所有任务的实时状态,支撑超大规模集群(例如万台节点)。
- 支持多租户:不同 AM 可独立管理资源请求,实现作业级别的隔离和优先级控制。
- 容错简化:当节点故障时,AM 只需重新请求资源,无需依赖 RM 的全量状态重建。
典型场景对比:
- Pull-based:MapReduce 作业的 AM 在 Map 阶段结束后,再请求 Reduce 任务的资源,确保资源按阶段精准分配。
- Push-based:Hadoop 1.x 的 JobTracker 预先为所有任务分配 slot,常因资源僵化导致集群利用率低下。
总结:Pull-based 模型通过解耦资源请求与分配,赋予应用层更大的自主权,同时降低了中心化调度器的复杂度,成为 YARN 支撑多样化计算框架(如 Spark、Flink)的核心设计之一。
NodeManager 与 ResourceManager 是如何进行交互的?NodeManager 会定期向 ResourceManager 汇报哪些信息?
NodeManager(NM)作为 YARN 的节点代理,与 ResourceManager(RM)的交互基于心跳机制,通常每秒发送一次心跳(可配置)。这种设计既保证实时性,又避免高频通信拖垮集群。
NodeManager 汇报的核心信息:
- 节点资源状态:总资源:节点的物理资源总量(CPU 核数、内存、GPU 等)。已用资源:当前正在运行的 Container 占用的资源。可用资源:剩余可分配的资源,用于 RM 决策新任务的调度。
- Container 运行状态:Container 列表:节点上所有 Container 的 ID 及其状态(运行中、已完成、失败等)。异常信息:例如 Container 因 OOM(内存溢出)或超时被终止的日志摘要。
- 健康状态:磁盘健康:HDFS 数据目录的可用空间和读写状态。硬件监控:CPU 温度、网络丢包率等硬件指标(部分通过外部插件采集)。
- 增量事件:新启动的 Container:通知 RM 已成功启动的 Container。释放的资源:当 Container 完成或失败时,NM 上报释放的资源量。
交互流程的深层机制:
- 资源抢占:当 RM 需要为高优先级任务腾出资源时,通过心跳响应通知 NM 终止特定 Container。
- 黑名单机制:若某个 NM 频繁故障,RM 会将其加入黑名单,暂时排除在调度范围外。
- 动态配置更新:RM 可通过心跳向 NM 推送新的资源分配策略或安全策略(例如调整 CPU 隔离参数)。
设计意义:
- 最终一致性:RM 通过心跳汇总集群资源视图,虽非实时强一致,但能支撑高并发调度。
- 负载均衡:RM 根据 NM 上报的可用资源,决定将新任务调度到负载较轻的节点。
- 故障自愈:若 NM 超时未发送心跳,RM 会将其标记为“失联”,并重新调度其上的任务。
在作业提交过程中,切片信息(split)和配置文件(job.xml)分别有什么作用?
切片信息(split) 和 配置文件(job.xml) 是 MapReduce 作业的两大元数据支柱,分别解决“数据怎么处理”和“任务怎么执行”的问题。
切片信息的核心作用:
- 逻辑数据划分:将输入数据(如 HDFS 文件)切割为多个 split,每个 split 对应一个 Map 任务。 示例:1GB 文本文件按 128MB 块存储,可能被切分为 8 个 split,但实际 split 数还会考虑文件格式(如压缩文件不可分割)。
- 数据本地化优化:split 包含数据块的位置信息(如 HDFS 的 DataNode 列表),帮助调度器优先将 Map 任务分配到存有数据的节点。
- 并行度控制:split 的数量直接决定 Map 任务数,影响作业并发度。用户可通过
mapreduce.input.fileinputformat.split.maxsize
参数调整 split 大小。
配置文件(job.xml)的作用:
- 作业级参数传递:包含所有 MapReduce 任务的全局配置,例如: 资源配额:单个 Container 的内存(mapreduce.map.memory.mb)和 CPU(yarn.cpu-vcores)。Shuffle 参数:排序缓冲区大小(mapreduce.task.io.sort.mb)、压缩算法(mapreduce.map.output.compress.codec)。容错配置:任务重试次数(mapreduce.map.maxattempts)、超时阈值(mapreduce.task.timeout)。
- 框架行为控制:指定 InputFormat、OutputFormat、Mapper/Reducer 类等,决定作业的执行逻辑。
两者协同工作示例:
- 客户端根据输入路径生成 split 列表,写入 HDFS 的暂存目录。
- job.xml 被上传到同一目录,MRAppMaster 读取该文件以获取作业配置。
- MRAppMaster 根据 split 数量决定启动多少个 Map 任务,并根据 job.xml 中的资源参数向 RM 申请 Container。
常见误区:
- split 不是物理切割:它仅是逻辑描述,实际数据仍以 HDFS 块形式存储。
- job.xml 优先级:作业代码中显式设置的参数会覆盖 job.xml 的默认值。
在 YARN 中,ApplicationMaster 是如何监控任务执行状态的?
ApplicationMaster(AM)作为作业的“管家”,通过多层级监控机制跟踪任务状态,确保作业按预期执行。
核心监控手段:
- 心跳轮询:AM 定期(如 3 秒)向所有运行其任务的 NodeManager(NM) 发送查询请求,获取 Container 的: 运行状态:是否正常执行、进度百分比(例如 Map 任务处理了 60% 的输入数据)。资源使用:CPU 和内存的实际消耗,用于检测资源超用或泄漏。诊断信息:若任务失败,NM 返回异常堆栈或日志路径。
- 事件驱动机制:NM 在任务状态变化(如完成、失败)时,主动向 AM 发送事件通知,触发 AM 的响应逻辑(如重试失败任务)。
- 计数器(Counters)收集:AM 聚合所有任务的计数器(例如已处理的记录数、错误数据量),用于生成作业统计报告。
- 超时检测:AM 为每个任务设置超时阈值(可配置),若长时间未收到进度更新,则判定任务僵死并强制终止。
容错与恢复策略:
- 任务重试:对失败任务重新调度(最多重试次数由
mapreduce.maxattempts
控制)。 - 推测执行:当某个任务明显慢于同类任务时,AM 启动备份任务(speculative task),取先完成的结果。
- 黑名单管理:若某个 NM 多次导致任务失败,AM 将其加入黑名单,后续任务不再调度到该节点。
监控数据用途:
- 资源动态调整:若发现某些任务资源不足,AM 可向 RM 申请更大规格的 Container。
- 用户反馈:通过 YARN Web UI 或 API 向用户展示任务进度和异常告警。
底层技术依赖:
- RPC 通信:AM 与 NM 间通过 Hadoop RPC 协议交换状态数据。
- 状态机模型:AM 为每个任务维护状态机(如 NEW、SCHEDULED、RUNNING、SUCCEEDED),驱动状态转换。
YARN 是如何保证资源分配的异步性的?
YARN 的异步资源分配模型通过“事件驱动”和“非阻塞队列”实现,使得资源请求与分配过程解耦,避免任务因等待资源而阻塞。
关键实现机制:
- 异步心跳处理:NodeManager(NM)定期发送心跳至 ResourceManager(RM),但 RM 不会立即处理所有请求,而是将其存入队列。调度器(如 CapacityScheduler)按策略从队列中批量处理资源分配,提升吞吐量。
- 回调机制(Callback):ApplicationMaster(AM)向 RM 提交资源请求后,无需阻塞等待响应,而是继续处理其他逻辑(如监控运行中的任务)。当 RM 完成资源分配时,通过异步事件通知 AM,后者再触发 Container 启动流程。
- 资源预留(Reservation):若当前资源不足,RM 可为 AM 预留资源,待资源释放后通过异步通知分配。
- 事件总线(Event Bus):YARN 内部使用事件总线(如 AsyncDispatcher)传递资源分配事件,各组件通过事件监听器异步响应。
异步性的核心优势:
- 高并发处理:RM 可同时处理数千个资源请求,适合大规模集群。
- 资源分配与任务执行解耦:AM 在等待资源期间仍能执行其他操作(如准备任务数据)。
- 避免死锁:传统同步模型可能导致多作业相互等待资源而形成死锁,异步模型通过队列和超时机制规避此问题。
示例场景:
- AM 向 RM 请求 10 个 Container,RM 立即返回已分配的 5 个,剩余 5 个加入待处理队列。
- 当其他作业释放资源后,RM 通过回调通知 AM 获取剩余 Container。
- AM 在整个过程中无需阻塞,可继续管理已分配 Container 中的任务。
底层技术支撑:
- Java 并发库:使用
Future
和ExecutorService
管理异步操作。 - 状态持久化:异步分配过程中,RM 将资源请求状态持久化到 Zookeeper 或 LevelDB,防止宕机后状态丢失。
请描述 MapReduce 作业中 MapTask 和 ReduceTask 的资源申请与启动过程
在 MapReduce 作业中,MapTask 和 ReduceTask 的资源申请与启动过程遵循 YARN 的分层调度模型,但两者的触发时机和资源需求存在显著差异。
MapTask 的申请与启动:
- 资源申请:客户端提交作业后,MRAppMaster(MapReduce ApplicationMaster)启动并向 ResourceManager(RM) 申请资源。MRAppMaster 根据切片(split)数量确定需要启动的 MapTask 总数,并基于 mapreduce.map.memory.mb 和 yarn.scheduler.minimum-allocation-mb 等配置参数计算单个 MapTask 的资源需求(CPU、内存)。资源请求以 Container 为单位,通过 ResourceRequest 对象发送给 RM,通常包含以下信息: 优先级:MapTask 通常优先级高于 ReduceTask。资源规格:例如 4GB 内存 + 2 个 CPU 核。数据本地性要求:优先申请存储输入数据的节点(如同一机架或同一节点)。
- 资源分配:RM 根据调度策略(如 Capacity Scheduler)将满足条件的资源(Container)分配给 MRAppMaster。如果本地资源不足,RM 可能分配跨机架或跨节点的 Container。
- 任务启动:MRAppMaster 通过 NodeManager(NM) 启动 Container,执行 MapTask。NM 从 HDFS 下载任务依赖的 JAR 包、配置文件和输入 split 信息(资源本地化)。MapTask 进程(如 YarnChild)启动后,开始处理分配给它的 split 数据。
ReduceTask 的申请与启动:
- 资源申请:ReduceTask 的资源请求通常在 MapTask 完成一定比例(如 5%)后触发,以避免资源过早占用。MRAppMaster 根据 mapreduce.reduce.memory.mb 和任务数量计算资源需求,向 RM 提交请求。
- 资源分配与启动:RM 分配 Container 后,MRAppMaster 通知 NM 启动 ReduceTask。ReduceTask 启动后,会从 MapTask 节点拉取(Shuffle)中间数据,进行排序(Sort)和聚合(Reduce)。
关键差异:
- 启动时机:MapTask 在作业初始化后立即申请资源;ReduceTask 依赖 MapTask 的进度。
- 数据本地性:MapTask 强依赖输入数据位置;ReduceTask 通常无此限制,但可能优先分配到 Shuffle 数据量大的节点。
- 资源隔离:MapTask 和 ReduceTask 运行在不同的 Container 中,避免资源冲突。
请解释 YARN 中 “资源预留” 机制,并说明其对集群利用率会产生怎样的影响?
资源预留(Resource Reservation) 是 YARN 为解决资源碎片化和高优先级作业抢占问题引入的机制,允许 ResourceManager 为特定 ApplicationMaster(AM)临时保留资源,即使当前资源不足。
资源预留的触发场景:
- 资源不足:当 AM 请求的资源总量超过集群当前可用资源时,RM 可预留部分已释放但未分配的资源。
- 优先级调度:高优先级作业需要确保在未来某个时间点获得资源。
- 资源碎片整理:当集群存在大量小资源块时,RM 可能暂时保留资源以整合成大块。
资源预留的实现流程:
- AM 向 RM 提交带预留标识的资源请求(例如设置
ReservationRequest
的超时时间)。 - RM 检查资源池,若无法立即分配,则标记该请求为“待预留”。
- 当其他任务释放资源时,RM 优先将资源分配给预留请求,而非立即响应其他 AM。
对集群利用率的影响:
高优先级作业 |
确保关键任务获得资源,避免饿死 |
低优先级作业可能因等待预留资源而延迟启动 |
资源碎片化 |
整合碎片资源,提升大任务调度成功率 |
预留期间部分资源可能暂时闲置,导致短期利用率下降 |
超时预留 |
超时后释放资源,避免死锁 |
频繁预留-超时循环可能增加调度器开销 |
优化策略:
- 动态调整预留超时:根据集群负载自动缩短或延长预留时间。
- 预留资源复用:允许其他任务临时使用预留资源(需在 AM 同意下)。
- 碎片预测算法:通过历史数据预测资源释放时机,减少无效预留。
典型用例:
- 实时批处理混合集群:为实时作业预留资源,同时允许批处理作业使用空闲资源。
- 资源密集型作业:如机器学习训练任务需大量 GPU,通过预留确保资源连贯性。
为什么 YARN 的 ResourceManager 不需要维护大量元数据?
YARN 的 ResourceManager(RM) 无需维护大量元数据的核心原因在于其分层架构设计和职责分离机制,将应用状态管理下放给 ApplicationMaster(AM),自身仅聚焦于全局资源调度。
关键设计原则:
- 无状态化调度:RM 仅记录集群总资源和已分配资源,不跟踪单个任务的运行时状态(如进度、日志路径)。任务状态由 AM 维护,RM 通过心跳机制获取 NM 的节点级资源状态(如可用 CPU、内存)。
- 事件驱动通信:RM 通过异步事件(如 NODE_UPDATE、APP_ATTEMPT_ADDED)接收集群状态变更,无需持久化所有事件历史。例如,当 NM 上报 Container 完成时,RM 仅更新资源池的可用量,不记录 Container 的详细执行日志。
- 轻量级恢复机制:RM 故障后重启时,通过持久化存储(如 Zookeeper)恢复关键元数据(如应用列表、队列配置),而非所有运行时状态。AM 和 NM 会重新向 RM 注册并上报状态,重建集群视图。
对比传统架构(如 Hadoop 1.x):
- Hadoop 1.x 的 JobTracker 需要维护所有任务的详细状态(如 MapTask 进度、ReduceTask 分片),导致单点瓶颈和扩展性受限。
- YARN 的 RM 仅需维护: 应用列表(Application ID、队列、用户);节点资源总量和分配情况;调度策略配置(如队列容量、ACL)。
优势:
- 横向扩展能力:RM 的元数据量与集群规模无关,可支撑超大规模集群(如 10,000+ 节点)。
- 容错简化:RM 重启后无需恢复复杂状态,依赖 AM 和 NM 的心跳重建集群视图。
- 降低网络开销:NM 仅上报聚合资源状态,而非每个任务的细粒度信息。
作业完成后,YARN 是如何释放资源并注销 ApplicationMaster 的?
作业完成后,YARN 通过状态机驱动的清理流程释放资源并注销 AM,确保集群资源高效回收。
资源释放流程:
- 作业完成信号:当所有任务(MapTask 和 ReduceTask)成功完成,AM 向 RM 发送 FinishApplicationMasterRequest,标记作业状态为 SUCCEEDED。若作业失败或超时,AM 或 RM 将其状态置为 FAILED 或 KILLED。
- Container 终止:RM 向所有运行该作业 Container 的 NM 发送 ContainerKillEvent,强制释放资源。NM 接收到事件后: 终止 Container 进程;清理本地临时文件(如 Shuffle 数据);向 RM 上报资源释放量。
- AM 注销:RM 将 AM 从注册表中移除,并释放其占用的资源(AM 本身也是一个 Container)。AM 进程自行退出,或由 RM 触发超时终止。
- HDFS 清理:AM 负责删除作业的暂存目录(ResourceManager 返回的资源路径)。若 AM 异常退出,RM 的 ApplicationHistoryServer 会在一定时间后(可配置)清理残留文件。
关键容错机制:
- 超时强制释放:若 AM 未正常发送完成信号(例如进程崩溃),RM 会在
yarn.am.liveness-monitor.expiry-interval-ms
(默认 10 分钟)后强制终止作业。 - 异步清理:资源释放与状态更新通过事件异步处理,避免阻塞 RM 主线程。
资源泄漏防护:
- NM 本地资源回收:即使 RM 未及时发送终止命令,NM 会定期扫描已完成的 Container 并自动清理。
- 审计日志:RM 记录资源分配和释放的详细日志,供管理员排查泄漏问题。
请对比 YARN 与 MapReduce V1 的架构差异,并说明 YARN 具有哪些优势?
YARN 和 MapReduce V1(Hadoop 1.x) 的架构差异本质在于资源管理与任务调度的解耦程度,YARN 通过分层设计解决了传统架构的扩展性和灵活性瓶颈。
架构对比:
核心组件 |
ResourceManager(RM)、NodeManager(NM)、ApplicationMaster(AM) |
JobTracker、TaskTracker |
资源管理 |
全局资源调度,支持多种计算框架(如 Spark、Flink) |
静态 MapSlot 和 ReduceSlot,仅支持 MapReduce |
扩展性 |
支持 10,000+ 节点 |
通常上限为 4,000 节点(JobTracker 单点瓶颈) |
容错性 |
RM 无单点故障(可配置 HA),AM 失败后由 RM 重新调度 |
JobTracker 单点故障导致集群不可用 |
资源利用率 |
动态分配,按需申请 |
固定 Slot 分配,易导致资源闲置 |
YARN 的核心优势:
- 多框架支持:YARN 将资源管理与任务调度分离,允许 Spark、Flink 等框架通过实现自己的 AM 接入集群。MapReduce V1 仅能运行 MapReduce 作业,无法适应多样化计算需求。
- 弹性资源分配:YARN 的 Container 资源规格可动态调整(如 2GB~8GB 内存),而 V1 的 Slot 是固定大小的静态资源单位。
- 横向扩展能力:YARN 的 RM 仅负责资源调度,不跟踪任务状态,轻松支撑万台节点;V1 的 JobTracker 需管理所有任务的详细状态,成为扩展瓶颈。
- 容错与高可用:YARN 支持 RM 的 Active-Standby 高可用模式,AM 失败后可重新调度;V1 的 JobTracker 单点故障会导致整个集群不可用。
- 资源隔离与安全性:YARN 通过 Linux CGroups 或 Docker 实现资源隔离,支持 GPU 和异构资源;V1 仅依赖进程级别的隔离,易导致资源冲突。
典型场景对比:
- 混合作业负载:YARN 可同时运行批处理(MapReduce)和实时作业(Spark Streaming),而 V1 只能串行执行 MapReduce 作业。
- 资源抢占:YARN 允许高优先级作业抢占资源,V1 的 Slot 分配是静态的,无法动态调整。
总结:YARN 通过解耦资源管理与任务调度,实现了更高效的资源利用、更强的扩展性和更广泛的计算框架支持,成为现代大数据生态的基石。
YARN 的 FIFO、Capacity、Fair 三种调度器的核心区别是什么?
YARN 的调度器决定了集群资源如何在多个作业间分配,FIFO、Capacity 和 Fair 是三种主流策略,其核心差异体现在资源分配逻辑、多租户支持和资源隔离能力上。
FIFO 调度器:
- 资源分配方式:按作业提交顺序先进先出分配资源,所有资源优先分配给最早提交的作业,直至其完成。
- 适用场景:单用户测试环境或小规模集群,不适用于多租户生产环境。
- 缺点: 资源饥饿:长作业可能阻塞后续短作业;低利用率:若首个作业资源需求小于集群总量,剩余资源无法被其他作业利用。
Capacity 调度器:
- 核心设计:将集群划分为多个资源队列,每个队列预分配固定容量(例如 30% 给队列 A,70% 给队列 B),队列内采用 FIFO 策略。
- 关键特性: 弹性资源共享:若某队列资源空闲,其他队列可临时借用;多租户隔离:通过队列划分实现部门或项目间的资源隔离;优先级支持:队列内作业可设置优先级。
- 适用场景:需要资源保障和多团队协作的企业级集群。
Fair 调度器:
- 资源分配原则:动态平衡所有作业的资源占用,确保每个作业获得公平份额(如平均分配或按权重分配)。
- 核心机制: 缺额分配:新提交的作业可立即获得资源,从超额占用的作业中回收资源;最小资源保证:可为特定作业或队列设置最低资源配额。
- 适用场景:混合负载环境(如同时运行批处理和交互式查询),需快速响应短作业。
三者的对比:
资源分配 |
顺序分配 |
队列预分配 + 弹性共享 |
动态平衡 + 按需调整 |
隔离性 |
无 |
队列级硬隔离 |
队列级软隔离(可超用) |
适用规模 |
小集群 |
中大规模 |
中大规模 |
典型用例 |
单用户测试 |
多部门企业集群 |
混合负载(如 Spark + MR) |
总结:选择调度器需权衡资源保障需求(Capacity 优先)与灵活性需求(Fair 优先),FIFO 仅适用于极简场景。
容量调度器(Capacity Scheduler)是如何实现多队列资源分配的?它适用于哪些场景?
容量调度器通过分层队列结构和预分配资源配额实现多队列资源分配,其核心在于资源隔离与弹性共享的结合。
实现机制:
- 队列定义:集群资源被划分为多个队列(例如 dev、prod),每个队列配置最小容量(capacity)和最大容量(maxCapacity)。队列可嵌套(如 prod 下再分 etl 和 analytics),形成树状结构。
- 资源分配逻辑:队列内分配:同一队列中的作业按 FIFO 或优先级排序,分配资源直至队列容量耗尽。队列间弹性共享:若某队列未用满其最小容量,其他队列可借用其空闲资源;当原队列需要资源时,借用的资源需在释放后归还。
- 资源限制:用户级限制:单个用户在同一队列中可占用的资源上限(防止资源独占);应用数限制:单个队列同时运行的作业数量上限。
适用场景:
- 多团队协作:例如开发团队(
dev
队列)与生产团队(prod
队列)共享集群,各自拥有资源保障。 - 优先级作业:高优先级队列(如实时计算)可抢占低优先级队列的资源。
- 资源预算控制:通过队列容量限制部门资源使用,避免超支。
配置示例:
<property> <name>yarn.scheduler.capacity.root.queues</name> <value>dev,prod</value> </property> <property> <name>yarn.scheduler.capacity.root.dev.capacity</name> <value>30</value> <!-- dev 队列占 30% 资源 --> </property>
优势与局限:
- 优势:硬性资源保障、易管理、支持多租户;
- 局限:弹性共享可能导致资源归还时的短暂竞争,配置复杂度随队列层级增加而上升。
公平调度器(Fair Scheduler)的 “缺额分配” 机制是什么?如何避免在该机制下出现资源饥饿问题?
缺额分配(Deficit Scheduling) 是公平调度器的核心算法,通过动态计算作业的“资源赤字”决定资源分配优先级。
缺额计算:
- 理想份额:假设集群有 100GB 内存,两个作业 A 和 B,则每个作业的理想份额为 50GB。
- 实际占用:若 A 已占用 70GB,B 占用 20GB,则: A 的缺额 = 70 - 50 = 20(超额占用);B 的缺额 = 50 - 20 = 30(资源不足)。
- 分配优先级:缺额越大(即资源不足越严重)的作业,越优先获得资源。
避免资源饥饿的关键策略:
- 最小资源保证:为队列或作业设置最小资源阈值(如 minResources),确保其至少获得一定资源,即使其他作业需求激增。
- 权重调整:通过权重(weight)调整作业的资源占比。例如,权重为 2 的作业可获得两倍于默认份额的资源。
- 抢占机制:若某作业长期无法获得最小资源,调度器可抢占其他作业的资源(需配置 yarn.scheduler.fair.preemption 为 true)。抢占分为温和抢占(等待任务自然释放)和强制抢占(立即终止 Container)。
- 时间衰减因子:计算缺额时,考虑作业的等待时间。等待越久的作业,缺额会被放大,从而提升其优先级。
示例场景:
- 作业 A(权重 1)和作业 B(权重 3)同时运行,集群总资源 100GB。
- 理想份额:A 应得 25GB,B 应得 75GB。
- 若 A 实际占用 20GB,B 占用 60GB,则: A 的缺额 = 25 - 20 = 5;B 的缺额 = 75 - 60 = 15。
- 调度器优先为 B 分配资源,但若 B 的缺额持续无法满足,可能触发抢占。
设计意义:缺额分配通过动态平衡资源,既保障了公平性,又通过最小资源保证和权重机制避免了饥饿问题。
Apache Hadoop 和 CDH 版本的默认调度器分别是什么?
- Apache Hadoop:从 Hadoop 2.x 开始,默认调度器为 Capacity Scheduler。原因:Capacity Scheduler 更适合企业级需求,支持多队列资源隔离和弹性共享,且与 YARN 的设计目标(多租户、资源保障)更契合。
- CDH(Cloudera Distribution Hadoop):CDH 5.x 及更高版本默认使用 Fair Scheduler。原因:Cloudera 推荐 Fair Scheduler 以更好地支持混合工作负载(如 Impala 交互查询与 MapReduce 批处理共存),其动态资源分配更适合实时性要求高的场景。
配置确认方式:
- 在
yarn-site.xml
中检查yarn.resourcemanager.scheduler.class
参数: Apache Hadoop 默认值:org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler。CDH 默认值:org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler。
注意事项:
- CDH 可能根据版本调整默认调度器,需以官方文档为准;
- 切换调度器需重启 ResourceManager,且配置语法不同(如队列定义文件格式)。
在生产环境中,应该如何选择使用容量调度器与公平调度器?
选择容量调度器(Capacity)或公平调度器(Fair)需综合考虑集群规模、作业类型、资源隔离需求和运维复杂度。
适用容量调度器的场景:
- 资源保障需求:例如生产环境需为关键业务预留固定资源(如 30% 给实时计算),避免被其他作业挤占。
- 多部门协作:通过队列划分隔离不同团队(如 finance、marketing),各部门资源用量可审计。
- 作业优先级明确:高优先级队列可配置抢占策略,确保紧急任务快速完成。
- 稳定性优先:Capacity 的配置更直观,适合对调度策略变更敏感的环境。
适用公平调度器的场景:
- 混合负载:同时运行批处理(如 MapReduce)和交互式查询(如 Hive LLAP),需动态调整资源分配。
- 快速响应短作业:公平调度器的缺额分配机制能让新提交的短作业快速获取资源。
- 资源共享需求:当某些队列资源闲置时,其他队列可超用资源,提升整体利用率。
- 灵活权重调整:通过权重为不同作业分配差异化资源比例(如 AI 训练任务权重设为 3,普通任务为 1)。
决策 Checklist:
资源隔离需求 |
强隔离(队列硬配额) |
弱隔离(允许弹性共享) |
作业类型 |
长周期批处理作业为主 |
混合负载(长短作业并存) |
运维复杂度 |
需预先规划队列结构 |
动态调整,适应变化快 |
资源利用率目标 |
中等(依赖弹性共享) |
高(资源超用) |
最终建议:
- 金融、电信等传统企业:优先选择 Capacity,因资源保障和隔离性至关重要;
- 互联网、AI 公司:倾向 Fair,适应快速变化的业务需求和混合负载;
- 混合云环境:Fair 的动态性更适合弹性扩缩容场景。
容量调度器中 “队列资源借用” 的实现原理是什么?这种机制存在哪些限制?
在容量调度器中,队列资源借用是一种弹性资源分配机制,允许队列在未使用完自身配额时,将空闲资源临时分配给其他队列使用。其核心目标是提升集群利用率,同时保留队列的最小资源保障能力。
实现原理:
- 资源监控: 父队列持续监控子队列的实际资源使用量。若子队列 A 的当前使用量低于其配置的 capacity(最小容量),则其空闲资源可被标记为“可借用”。
- 借用触发条件: 当其他队列(如子队列 B)的资源需求超过自身 capacity 时,调度器会优先检查父队列中是否存在可借用资源。
- 资源分配与回收: 借用的资源以 Container 形式分配给需求方队列,并在原队列(子队列 A)需要资源时触发渐进式回收(例如等待正在运行的 Container 自然结束)。回收策略通过 yarn.scheduler.capacity.<queue-path>.maximum-capacity 参数限制最大借用量,防止过度抢占。
限制与挑战:
- 资源归还延迟:若借用资源的队列长时间占用,原队列可能无法及时回收资源,导致关键任务延迟。
- 层级复杂性:多层队列嵌套时,资源借用的优先级和路径可能变得难以预测。
- 配置敏感性:错误设置
maximum-capacity
可能导致资源超用或碎片化(例如设置超过父队列容量)。 - 无抢占支持:容量调度器的资源借用依赖协作式释放,无法强制终止借用资源的任务。
优化实践:
- 设置合理的 maximum-capacity:通常建议不超过队列
capacity
的 2 倍,避免资源过度倾斜。 - 监控与告警:通过 YARN 的 Metrics API 跟踪各队列资源借用情况,及时调整配置。
为什么 FIFO 调度器不适合多租户集群环境?
FIFO 调度器的设计特性与多租户集群的资源隔离和公平性需求存在根本冲突,主要体现在以下方面:
- 无资源隔离机制:所有作业按提交顺序共享整个集群资源。若某租户提交一个长周期作业(如数小时的数据清洗),后续租户的作业必须等待其完成,导致资源饥饿。
- 缺乏优先级支持:多租户场景通常需要为高优先级作业(如实时告警)分配更多资源,但 FIFO 仅支持线性执行,无法动态调整资源分配。
- 资源利用率低下:若首个作业仅使用部分资源(例如 50% CPU),剩余资源无法被其他租户利用,造成浪费。
- 审计与配额管理困难:无法按租户或部门划分资源使用量,难以实现成本分摊和用量监控。
对比多租户需求:
资源隔离 |
所有作业混用资源,无隔离 |
弹性伸缩 |
资源分配僵化,无法动态调整 |
优先级调度 |
仅支持先进先出,无优先级机制 |
利用率优化 |
空闲资源无法跨租户共享 |
典型案例:
- 租户 A 提交一个占用 80% 资源的作业,租户 B 的小作业需等待数小时才能执行,导致 SLA 违约。
- 租户 C 的交互式查询因资源不足无法及时响应,用户体验下降。
结论:FIFO 仅适用于单用户测试或同质化作业场景,多租户集群需选择 Capacity 或 Fair 调度器。
公平调度器中 “最小资源保证” 和 “权重分配” 分别有什么作用?
公平调度器通过最小资源保证和权重分配机制平衡资源分配的公平性与灵活性,两者共同解决资源竞争中的饥饿问题和差异化需求。
最小资源保证:
- 作用:确保队列或作业至少获得指定量资源,防止因其他作业资源抢占导致完全无法运行。
- 配置示例:
- 场景: 当集群繁忙时,即使其他队列超额占用,research 队列仍能获得至少 10GB 内存和 10 核 CPU。若实际资源不足,调度器会通过抢占机制从其他队列回收资源。
权重分配:
- 作用:调整不同队列或作业的资源占比,反映其优先级或业务重要性。
- 配置示例:
- 场景: 集群总资源 100GB,队列 prod(权重 3)和 test(权重 1)同时运行。理想分配比为 3:1,即 prod 获得 75GB,test 获得 25GB。
协同工作逻辑:
- 资源分配优先级: 首先满足所有队列的最小资源,剩余资源按权重比例分配。
- 动态调整: 若某队列的实际使用量低于其权重比例,调度器会优先为其分配资源。
示例:
- 集群有 50GB 空闲资源,队列 A(min=10GB,weight=2)和队列 B(min=10GB,weight=1)。
- 分配流程: 为 A 和 B 各分配 10GB(满足 min);剩余 30GB 按 2:1 分配 → A 得 20GB,B 得 10GB;最终分配:A=30GB,B=20GB。
设计意义:最小资源保证防止“饿死”,权重分配实现差异化优先级,两者结合兼顾公平与业务需求。
如何配置 YARN 队列以实现不同部门或业务模块之间的资源隔离?
在 YARN 中实现资源隔离通常基于容量调度器,通过定义分层队列、设置资源配额和访问控制来完成。
配置步骤:
- 定义队列结构:在 capacity-scheduler.xml 中声明根队列及其子队列。例如:支持嵌套队列(如 engineering 下分 data_team 和 backend_team)。
- 设置队列容量:为每个队列分配最小容量(capacity)和最大容量(maxCapacity):
- 配置用户限制:限制单个用户或组在队列中的资源使用上限:
- 访问控制列表(ACL):指定哪些用户或组可提交作业到队列:
- 启用资源抢占(可选):当队列资源不足时,允许从其他队列抢占资源:
验证与监控:
- 使用
yarn queue -status <queue-name>
命令检查队列状态。 - 通过 YARN ResourceManager Web UI 查看各队列资源使用情况。
最佳实践:
- 队列命名清晰:如
prod_bi
、dev_ml
,便于管理和故障排查。 - 预留缓冲资源:根队列保留 5-10% 资源作为应急缓冲。
- 定期审计配置:避免队列层级过深或配额设置不合理。
请解释 Capacity Scheduler 中 “队列层级” 与 “资源容量” 之间的关系。
在容量调度器中,队列层级决定了资源的继承关系与分配粒度,而资源容量则定义了各队列在层级中的资源占比,两者共同构成多租户资源管理的骨架。
队列层级结构:
- 树状模型:队列以树形结构组织,根队列代表整个集群资源,子队列继承父队列的资源池。
- 示例:
资源容量计算规则:
- 相对比例:每个队列的
capacity
是相对于父队列的百分比。 例如,prod 的 capacity=60% 表示其占用根队列(整个集群)的 60%。 - 绝对资源量:子队列的绝对资源量为
父队列资源 × 子队列 capacity
。 若集群总资源为 1000GB,prod 获得 600GB,其子队列 etl 和 analytics 各获得 300GB(600GB × 50%)。 - 最大容量限制:
maximum-capacity
定义队列可占用的上限(包括借用资源),防止资源过度倾斜。
关键交互逻辑:
- 资源借用:子队列可借用父队列中其他子队列的空闲资源,但总量不超过
maximum-capacity
。 - 资源回收:当父队列需要资源时,优先回收跨队列借用的资源,再处理同队列内的资源分配。
配置示例:
<!-- 定义 prod 队列占 60%,其子队列 etl 和 analytics 各占 50% --> <property> <name>yarn.scheduler.capacity.root.prod.capacity</name> <value>60</value> </property> <property> <name>yarn.scheduler.capacity.root.prod.queues</name> <value>etl,analytics</value> </property> <property> <name>yarn.scheduler.capacity.root.prod.etl.capacity</name> <value>50</value> </property>
设计影响:
- 灵活性:通过层级结构可精细划分资源(如按部门→团队→项目分级)。
- 复杂性:深层嵌套可能导致资源分配难以直观理解,需配合监控工具管理。
常见误区:
- 绝对容量误解:误将子队列的
capacity
理解为集群总量的百分比(实际是父队列的百分比)。 - 最大容量溢出:若
maximum-capacity
设置过高,可能引发资源耗尽风险。
容量调度器中 “队列资源借用” 的实现原理是什么?这种机制存在哪些限制?
在容量调度器中,队列资源借用是一种弹性资源分配机制,允许队列在未使用完自身配额时,将空闲资源临时分配给其他队列使用。其核心目标是提升集群利用率,同时保留队列的最小资源保障能力。
实现原理:
- 资源监控: 父队列持续监控子队列的实际资源使用量。若子队列 A 的当前使用量低于其配置的 capacity(最小容量),则其空闲资源可被标记为“可借用”。
- 借用触发条件: 当其他队列(如子队列 B)的资源需求超过自身 capacity 时,调度器会优先检查父队列中是否存在可借用资源。
- 资源分配与回收: 借用的资源以 Container 形式分配给需求方队列,并在原队列(子队列 A)需要资源时触发渐进式回收(例如等待正在运行的 Container 自然结束)。回收策略通过 yarn.scheduler.capacity.<queue-path>.maximum-capacity 参数限制最大借用量,防止过度抢占。
限制与挑战:
- 资源归还延迟:若借用资源的队列长时间占用,原队列可能无法及时回收资源,导致关键任务延迟。
- 层级复杂性:多层队列嵌套时,资源借用的优先级和路径可能变得难以预测。
- 配置敏感性:错误设置
maximum-capacity
可能导致资源超用或碎片化(例如设置超过父队列容量)。 - 无抢占支持:容量调度器的资源借用依赖协作式释放,无法强制终止借用资源的任务。
优化实践:
- 设置合理的 maximum-capacity:通常建议不超过队列
capacity
的 2 倍,避免资源过度倾斜。
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
17年+码农经历了很多次面试,多次作为面试官面试别人,多次大数据面试和面试别人,深知哪些面试题是会被经常问到。 在多家企业从0到1开发过离线数仓实时数仓等多个大型项目,详细介绍项目架构等企业内部秘不外传的资料,介绍踩过的坑和开发干货,分享多个拿来即用的大数据ETL工具,让小白用户快速入门并精通,指导如何入职后快速上手。 计划更新内容100篇以上,包括一些企业内部秘不外宣的干货,欢迎订阅!