4.1 YARN 架构与组件 4.1 YARN 架构与组件详解 Apache Hadoop YARN (Yet Another Resource Negotiator) 是 Hadoop 2.0 及更高版本中的核心组件,它是一个强大的集群资源管理框架。YARN 的出现是为了解决 Hadoop 1.0 中 MapReduce 框架的局限性,例如资源利用率低、扩展性差以及仅支持 MapReduce 编程模型等问题。YARN 通过将资源管理和作业调度/监控功能分离,为 Hadoop 带来了更强大的资源管理能力和更灵活的应用程序支持。 本章节将深入探讨 YARN 的架构与核心组件,帮助您全面理解 YARN 的工作原理和关键概念。 4.1.
Apache Hadoop YARN (Yet Another Resource Negotiator) 是 Hadoop 2.0 及更高版本中的核心组件,它是一个强大的集群资源管理框架。YARN 的出现是为了解决 Hadoop 1.0 中 MapReduce 框架的局限性,例如资源利用率低、扩展性差以及仅支持 MapReduce 编程模型等问题。YARN 通过将资源管理和作业调度/监控功能分离,为 Hadoop 带来了更强大的资源管理能力和更灵活的应用程序支持。
本章节将深入探讨 YARN 的架构与核心组件,帮助您全面理解 YARN 的工作原理和关键概念。
YARN 采用典型的 Master-Slave 架构,主要由以下核心组件构成:
ResourceManager (RM):整个集群的资源管理器,是 YARN 的 Master 节点。
NodeManager (NM):集群中每个节点的资源和任务管理器,是 YARN 的 Slave 节点。
ApplicationMaster (AM):每个应用程序的管理者,负责应用程序的生命周期管理和资源协调。
Container:YARN 中资源分配的基本单位,用于运行应用程序的任务。
Client:用户提交应用程序的客户端。
为了更直观地理解 YARN 的架构,我们可以使用 Mermaid 的 graph TD 图表来表示:
图 4.1-1 YARN 架构图
上图清晰地展示了 YARN 架构的主要组件及其相互关系。接下来,我们将逐一深入剖析每个组件的功能和作用。
ResourceManager 是 YARN 集群的中央控制节点,负责集群资源的统一管理和调度。它主要由以下两个核心组件构成:
Scheduler (调度器):Scheduler 负责资源的调度和分配。它根据应用程序的资源需求,将集群资源(以 Container 的形式)分配给合适的应用程序。YARN 的调度器是可插拔的,允许用户根据不同的需求选择不同的调度策略,例如 FIFO 调度器、容量调度器和公平调度器等。
ApplicationsManager (应用程序管理器):ApplicationsManager 负责管理集群中运行的所有应用程序。它接受客户端提交的应用程序,启动应用程序的 ApplicationMaster,监控 ApplicationMaster 的运行状态,并在 ApplicationMaster 失败时重新启动它。
ResourceManager 的主要职责包括:
资源管理:管理集群中所有节点的资源信息,包括 CPU、内存、磁盘、网络带宽等。
资源调度:根据调度策略,将集群资源分配给应用程序。
应用程序管理:管理应用程序的生命周期,包括应用程序的提交、启动、运行、监控和完成。
安全管理:负责集群的安全认证和授权。
集群监控:监控集群的健康状态和资源利用率。
ResourceManager 的工作流程简述:
接收客户端请求:ResourceManager 接收来自客户端的应用程序提交请求。
应用程序注册:ApplicationsManager 接收到应用程序提交请求后,会对应用程序进行注册,并为应用程序分配一个 Application ID。
ApplicationMaster 启动:ApplicationsManager 向 Scheduler 请求启动 ApplicationMaster 的 Container 资源。Scheduler 根据调度策略,在合适的 NodeManager 上分配 Container,并指示 NodeManager 启动 ApplicationMaster。
资源分配:ApplicationMaster 启动后,会向 ResourceManager 的 Scheduler 注册,并根据应用程序的需求请求资源。Scheduler 根据调度策略,为 ApplicationMaster 分配 Container 资源。
应用程序运行:ApplicationMaster 获取到 Container 资源后,会指示 NodeManager 在 Container 中启动应用程序的任务。
监控与管理:ResourceManager 监控集群的资源使用情况和应用程序的运行状态,并进行必要的管理操作,例如资源回收、故障恢复等。
代码实践 - 访问 ResourceManager UI:
ResourceManager 提供了一个 Web UI 界面,用户可以通过浏览器访问 ResourceManager UI 来查看集群的资源使用情况、应用程序的运行状态、节点信息等。ResourceManager UI 的访问地址通常为 http://<ResourceManager 主机名或 IP 地址>:<ResourceManager UI 端口号>,默认端口号为 8088。
例如,如果 ResourceManager 运行在主机名为 rm-host 的机器上,并且端口号为默认的 8088,则可以通过浏览器访问 http://rm-host:8088 来访问 ResourceManager UI。
在 ResourceManager UI 上,您可以查看以下信息:
Cluster Metrics (集群指标):显示集群的整体资源使用情况,例如总内存、已用内存、可用内存、总 CPU 核数、已用 CPU 核数等。
Nodes (节点):显示集群中所有 NodeManager 节点的信息,包括节点状态、资源使用情况、运行的 Container 数量等。
Applications (应用程序):显示集群中正在运行和已完成的应用程序列表,包括应用程序 ID、应用程序名称、应用程序类型、应用程序状态、资源使用情况等。
Schedulers (调度器):显示当前使用的调度器类型和调度器配置信息。
通过 ResourceManager UI,用户可以实时监控集群的运行状态,并进行必要的管理操作。
NodeManager 运行在 YARN 集群的每个节点上,负责管理本节点的资源和 Container。它是 YARN 的 Slave 节点,直接受 ResourceManager 的管理和调度。
NodeManager 的主要职责包括:
Container 管理:接收 ResourceManager 和 ApplicationMaster 的指令,启动、监控和停止 Container。
资源管理:管理本节点的资源,包括 CPU、内存、磁盘等。
资源汇报:定期向 ResourceManager 汇报本节点的资源使用情况和 Container 运行状态。
本地化服务:提供本地化服务,例如数据本地化和应用程序代码本地化。
节点健康检查:定期进行节点健康检查,并将检查结果汇报给 ResourceManager。
NodeManager 的工作流程简述:
节点注册:NodeManager 启动后,会向 ResourceManager 注册,并将本节点的资源信息汇报给 ResourceManager。
接收 Container 启动指令:NodeManager 接收来自 ResourceManager 或 ApplicationMaster 的 Container 启动指令。
Container 启动:NodeManager 根据指令,在本节点上创建并启动 Container,为 Container 分配指定的资源。
Container 监控:NodeManager 监控 Container 的运行状态,包括 CPU 使用率、内存使用率、网络流量等。
Container 状态汇报:NodeManager 定期向 ResourceManager 和 ApplicationMaster 汇报 Container 的运行状态和资源使用情况。
Container 停止:NodeManager 接收到 ResourceManager 或 ApplicationMaster 的指令后,会停止指定的 Container,并回收 Container 占用的资源。
代码实践 - 查看 NodeManager 日志:
NodeManager 的日志记录了 NodeManager 的运行状态、Container 的启动和停止信息、资源管理信息等。查看 NodeManager 日志对于排查节点故障和 Container 运行问题非常重要。
NodeManager 的日志文件通常位于 NodeManager 的日志目录下,具体路径取决于 Hadoop 的配置。常见的日志文件包括:
hadoop-yarn-nodemanager-<主机名>.log: NodeManager 的主日志文件,记录 NodeManager 的运行状态和错误信息。
container-log: 目录,包含各个 Container 的日志文件。每个 Container 的日志文件通常以 container_<Application ID>_<尝试 ID>_<Container ID> 命名。
可以通过以下命令查看 NodeManager 的主日志文件:
tail -f <NodeManager 日志目录>/hadoop-yarn-nodemanager-<主机名>.log
例如:
tail -f /var/log/hadoop-yarn/hadoop-yarn-nodemanager-node1.log
通过查看 NodeManager 日志,可以了解 NodeManager 的运行状态,以及 Container 的启动和停止过程中的错误信息。
ApplicationMaster 是每个应用程序的管理者,负责应用程序的生命周期管理和资源协调。当用户提交一个应用程序到 YARN 集群时,YARN 会为该应用程序启动一个 ApplicationMaster 实例。
ApplicationMaster 的主要职责包括:
应用程序注册:向 ResourceManager 注册应用程序信息。
资源协商:与 ResourceManager 的 Scheduler 协商资源需求,为应用程序的任务请求 Container 资源。
任务调度:将应用程序的任务调度到分配的 Container 上执行。
任务监控:监控应用程序的任务执行状态,包括任务进度、任务日志等。
容错处理:处理应用程序任务执行失败的情况,例如任务重试、Container 重新分配等。
应用程序完成:在应用程序完成运行时,向 ResourceManager 注销应用程序。
ApplicationMaster 的工作流程简述:
启动:ApplicationMaster 由 ResourceManager 的 ApplicationsManager 启动在一个 Container 中。
注册:ApplicationMaster 启动后,会向 ResourceManager 注册应用程序信息,并获取 ResourceManager 分配的 Application ID。
资源请求:ApplicationMaster 根据应用程序的需求,向 ResourceManager 的 Scheduler 请求 Container 资源。
任务调度:Scheduler 为 ApplicationMaster 分配 Container 资源后,ApplicationMaster 会将应用程序的任务调度到这些 Container 上执行。
监控与管理:ApplicationMaster 监控任务的执行状态,并进行必要的管理操作,例如任务重试、Container 重新分配等。
完成与注销:当应用程序的所有任务都执行完成后,ApplicationMaster 会向 ResourceManager 注销应用程序,并释放占用的资源。
代码实践 - 模拟 ApplicationMaster 资源请求 (概念代码):
以下是一个简化的 Python 代码片段,用于概念性地演示 ApplicationMaster 如何向 ResourceManager 请求 Container 资源。请注意,这只是一个简化的示例,实际的 ApplicationMaster 实现会更加复杂。
class ApplicationMasterClient: def __init__(self, resource_manager_address): self.resource_manager_address = resource_manager_address # ... 初始化与 ResourceManager 的连接 ... def register_application(self, application_name): # ... 向 ResourceManager 注册应用程序 ... print(f"Application '{application_name}' registered with ResourceManager.") def request_containers(self, num_containers, container_resource_spec): # ... 向 ResourceManager 请求指定数量和资源的 Container ... print(f"Requesting {num_containers} containers with resource spec: {container_resource_spec}") # 假设 ResourceManager 返回分配的 Container 列表 allocated_containers = ["container_1", "container_2", ...] # 模拟返回的 Container ID return allocated_containers def run_tasks_in_containers(self, containers): for container_id in containers: # ... 在 Container 中启动任务 ... print(f"Running task in container: {container_id}") def unregister_application(self): # ... 向 ResourceManager 注销应用程序 ... print("Application unregistered from ResourceManager.") # 示例用法 if __name__ == "__main__": rm_address = "rm-host:8032" # ResourceManager 地址 am_client = ApplicationMasterClient(rm_address) am_client.register_application("MyApplication") container_spec = {"memory": "1GB", "vcores": 1} requested_containers = am_client.request_containers(5, container_spec) am_client.run_tasks_in_containers(requested_containers) am_client.unregister_application()
这段代码演示了 ApplicationMaster 客户端如何注册应用程序、请求 Container 资源、并在 Container 中运行任务,最后注销应用程序。 实际的 ApplicationMaster 的实现会使用更复杂的协议和机制与 ResourceManager 进行通信,例如使用 RPC (远程过程调用) 进行通信。
Container 是 YARN 中资源分配的基本单位,它代表了集群中一定量的资源(例如 CPU、内存、磁盘等)。应用程序的任务需要在 Container 中运行。
Container 的特点:
资源隔离:Container 提供了一定程度的资源隔离,可以限制应用程序任务对资源的访问和使用,避免不同应用程序之间的资源干扰。
动态资源分配:Container 的资源是动态分配的,可以根据应用程序的需求进行伸缩。
生命周期管理:Container 的生命周期由 NodeManager 管理,包括 Container 的创建、启动、监控和停止。
Container 的生命周期简述:
Container 请求:ApplicationMaster 向 ResourceManager 的 Scheduler 请求 Container 资源。
Container 分配:Scheduler 根据调度策略,在合适的 NodeManager 上分配 Container 资源。
Container 启动:NodeManager 接收到 Container 启动指令后,在本节点上创建并启动 Container,并为 Container 分配指定的资源。
Container 运行:应用程序的任务在 Container 中运行。
Container 监控:NodeManager 监控 Container 的运行状态和资源使用情况。
Container 完成/停止:当应用程序的任务完成或发生错误时,ApplicationMaster 或 ResourceManager 会指示 NodeManager 停止 Container,并回收 Container 占用的资源.
代码实践 - Container 资源配置 (概念代码):
在实际的 YARN 应用开发中,您需要在应用程序的配置文件中指定 Container 的资源需求。不同的应用程序框架和提交工具可能有不同的配置方式。以下是一个概念性的示例,展示如何配置 Container 的资源需求:
例如,在使用 Hadoop MapReduce 框架时,可以在 mapred-site.xml 或作业提交参数中配置 Container 的资源需求:
<property> <name>mapreduce.map.memory.mb</name> <value>1024</value> <description>每个 Map Task Container 请求的内存大小 (MB)</description> </property> <property> <name>mapreduce.map.cpu.vcores</name> <value>1</value> <description>每个 Map Task Container 请求的 CPU 核数</description> </property> <property> <name>mapreduce.reduce.memory.mb</name> <value>2048</value> <description>每个 Reduce Task Container 请求的内存大小 (MB)</description> </property> <property> <name>mapreduce.reduce.cpu.vcores</name> <value>2</value> <description>每个 Reduce Task Container 请求的 CPU 核数</description> </property>
这些配置项指定了 Map Task 和 Reduce Task 的 Container 分别需要的内存和 CPU 资源。YARN 在为应用程序分配 Container 时,会根据这些配置项进行资源分配。
在编程提交 YARN 应用程序时,通常会使用 API 来设置 Container 的资源需求,例如使用 Hadoop YARN Client API:
// 创建 Container 资源请求 Resource capability = Records.newRecord(Resource.class); capability.setMemorySize(1024); // 内存 1GB capability.setVirtualCores(1); // 1 个虚拟 CPU 核 // 设置 Container 的资源需求到 ApplicationSubmissionContext ApplicationSubmissionContext appContext = ...; appContext.setResource(capability);
这段 Java 代码片段演示了如何使用 Hadoop YARN Client API 创建 Resource 对象来描述 Container 的资源需求,并将其设置到 ApplicationSubmissionContext 中,在提交应用程序时,YARN 会根据这些资源需求来分配 Container。
Client 是用户与 YARN 集群交互的接口,用户通过 Client 提交应用程序、查询应用程序状态、取消应用程序等。
Client 的主要职责包括:
应用程序提交:将应用程序的描述信息、应用程序代码和配置文件等提交给 ResourceManager。
应用程序状态查询:查询应用程序的运行状态、进度、日志等信息。
应用程序取消:取消正在运行的应用程序。
与 ApplicationMaster 交互 (可选):某些 Client 可以直接与 ApplicationMaster 进行交互,例如获取更详细的应用程序运行信息或执行特定的操作。
代码实践 - 使用 Hadoop YARN Client 提交应用程序 (概念代码):
以下是一个简化的 Python 代码片段,概念性地演示如何使用 Hadoop YARN Client 提交一个应用程序到 YARN 集群。实际的 YARN Client API 使用会更加复杂,并且需要使用相应的编程语言 (例如 Java)。
class YarnClient: def __init__(self, resource_manager_address): self.resource_manager_address = resource_manager_address # ... 初始化与 ResourceManager 的连接 ... def submit_application(self, application_jar_path, application_config_path, application_name): # ... 读取应用程序配置 ... app_config = self._load_config(application_config_path) # ... 创建 ApplicationSubmissionContext 对象 ... app_context = self._create_application_context(application_name, app_config) # ... 将应用程序提交到 ResourceManager ... self._submit_to_resource_manager(app_context, application_jar_path) print(f"Application '{application_name}' submitted successfully.") def get_application_status(self, application_id): # ... 向 ResourceManager 查询应用程序状态 ... status = self._query_resource_manager_status(application_id) print(f"Application '{application_id}' status: {status}") def kill_application(self, application_id): # ... 向 ResourceManager 发送取消应用程序请求 ... self._send_kill_request(application_id) print(f"Application '{application_id}' killed.") # ... (私有方法,用于加载配置、创建上下文、与 ResourceManager 通信等) ... def _load_config(self, config_path): # 模拟加载配置 return {"container_memory": "1GB", "container_vcores": 1} def _create_application_context(self, app_name, app_config): # 模拟创建 ApplicationSubmissionContext return {"application_name": app_name, "config": app_config} def _submit_to_resource_manager(self, app_context, jar_path): # 模拟提交到 ResourceManager print(f"Submitting application context: {app_context}, JAR path: {jar_path}") def _query_resource_manager_status(self, app_id): # 模拟查询状态 return "RUNNING" def _send_kill_request(self, app_id): # 模拟发送 kill 请求 print(f"Sending kill request for application: {app_id}") # 示例用法 if __name__ == "__main__": rm_address = "rm-host:8032" # ResourceManager 地址 yarn_client = YarnClient(rm_address) app_jar = "myapp.jar" # 应用程序 JAR 包路径 app_config = "app_config.xml" # 应用程序配置文件路径 app_name = "MyYARNApplication" # 应用程序名称 yarn_client.submit_application(app_jar, app_config, app_name) app_id = "application_12345_0001" # 假设的 Application ID yarn_client.get_application_status(app_id) # yarn_client.kill_application(app_id) # 取消应用程序
这段代码演示了 YARN Client 客户端如何提交应用程序、查询应用程序状态和取消应用程序。 实际的 YARN Client API 会提供更丰富的功能和更复杂的交互流程,通常需要使用 Java 或其他支持 Hadoop YARN Client API 的语言进行开发。 例如,可以使用 hadoop jar 命令从命令行提交 MapReduce 作业, 这就是一种 Client 的形式。
为了更好地理解 YARN 的工作原理,我们可以通过一个典型的应用程序提交和运行流程来描述 YARN 组件之间的交互:
步骤 1: 应用程序提交
步骤 2: 应用程序启动准备
ResourceManager 接收请求: ResourceManager 的 ApplicationsManager 组件接收到应用程序提交请求。
应用程序注册: ApplicationsManager 为应用程序创建一个 Application ID,并将应用程序信息存储起来。
ApplicationMaster 启动请求: ApplicationsManager 向 Scheduler 请求启动 ApplicationMaster 的 Container 资源。
Scheduler 资源分配: Scheduler 根据调度策略,选择合适的 NodeManager,并为 ApplicationMaster 分配一个 Container。
NodeManager 启动 Container: 被选中的 NodeManager 接收到 ResourceManager 的指令,启动 ApplicationMaster 的 Container。
ApplicationMaster 启动: ApplicationMaster 在 Container 中启动,并向 ResourceManager 注册。
步骤 3: 应用程序资源协商与任务执行
ApplicationMaster 资源请求: ApplicationMaster 根据应用程序的需求,向 ResourceManager 的 Scheduler 请求 Container 资源。
Scheduler 资源分配: Scheduler 根据调度策略,为 ApplicationMaster 分配 Container 资源。
NodeManager 启动 Container: NodeManager 接收到 ResourceManager 的指令,启动应用程序任务的 Container。
应用程序任务执行: ApplicationMaster 将应用程序的任务调度到分配的 Container 上执行。
Container 状态汇报: NodeManager 定期向 ApplicationMaster 和 ResourceManager 汇报 Container 的运行状态和资源使用情况。
ApplicationMaster 监控: ApplicationMaster 监控应用程序的任务执行状态。
步骤 4: 应用程序完成与清理
应用程序完成: 应用程序的所有任务执行完成。
ApplicationMaster 注销: ApplicationMaster 向 ResourceManager 注销应用程序,并释放占用的 Container 资源。
ResourceManager 资源回收: ResourceManager 回收应用程序占用的 Container 资源。
我们可以使用 Mermaid 的 sequenceDiagram 图表来更清晰地描述这个流程:
图 4.1-2 YARN 应用程序提交与运行流程图
通过上述流程图和步骤描述,我们可以清晰地理解 YARN 各个组件在应用程序提交和运行过程中的交互和协作关系。
YARN 架构的出现为 Hadoop 带来了诸多优势:
资源利用率提升: YARN 实现了集群资源的统一管理和动态分配,可以更有效地利用集群资源,提高资源利用率。
扩展性增强: YARN 的架构设计使其更容易扩展,可以支持更大规模的集群和更多的并发应用程序。
多框架支持: YARN 不仅支持 MapReduce 框架,还可以支持多种不同的计算框架,例如 Spark、Flink、Storm 等,实现了 Hadoop 平台的多样化应用。
更好的隔离性: YARN 的 Container 机制提供了一定程度的资源隔离,可以避免不同应用程序之间的资源干扰,提高应用程序的稳定性和可靠性。
更灵活的资源调度策略: YARN 的调度器是可插拔的,可以根据不同的应用场景和需求选择合适的调度策略,提高了资源调度的灵活性和效率。
本章节深入介绍了 Hadoop YARN 的架构和核心组件,包括 ResourceManager、NodeManager、ApplicationMaster、Container 和 Client。我们详细解析了每个组件的功能、职责、工作流程以及相互之间的交互关系。通过 Mermaid 图表和代码实践示例,我们更直观地理解了 YARN 的架构和工作原理。
YARN 的出现是 Hadoop 发展史上的一个重要里程碑,它为 Hadoop 平台带来了更强大的资源管理能力和更广泛的应用场景。理解 YARN 的架构和组件是深入学习和应用 Hadoop 技术的基础。
在后续章节中,我们将继续探讨 YARN 的高级特性和应用实践,例如 YARN 的调度器策略、资源队列管理、安全机制等。