Hadoop 服务注册表可用于多种方式:
注册表用户既可以是条目(服务记录)的发布者,也可以是通过其服务记录找到的其他服务的使用者。分布式应用程序的不同部分也可以将其用于不同的目的。例如,YARN 应用程序的应用程序主服务器可以发布绑定,以便其工作器容器使用。然后,在容器中运行的代码可以查找绑定,以便与该管理器通信,即使该管理器在集群的不同节点上重新启动。客户端应用程序可以通过公共 API 查找外部服务端点,以便与 AM 交互。
注册表不能用于:-
yarn:persistence = "application_attempt" yarn:id = ${application_attemptId}
这意味着即使创建了新的尝试,该记录也会在应用程序尝试完成后被删除。每个应用程序尝试都必须重新注册端点,而无论如何可能需要找到该服务。
yarn:persistence = "application_attempt" yarn:id = application_attemptId
这意味着即使在应用程序尝试之间,该记录也会持久存在,尽管端点信息已过时。
路径的选择是特定于应用程序的。对于 YARN 应用程序名称保证唯一的服务,我们建议采用以下约定
/users/${username}/applications/${service-class}/${instance-name}
或者,可以在路径中使用应用程序 ID
/users/${username}/applications/${service-class}/${applicationId}
后者使得将 YARN 应用程序列表条目映射到服务记录变得简单。
客户端应用程序可以找到服务
找到服务记录后,客户端可以枚举external
绑定并找到具有所需 API 的条目。
此处,YARN 应用程序中的所有容器都在发布供公开使用的服务端点。
id:password
对,该对赋予它们在没有用户的 kerberos 凭据的情况下更新这些条目的权限。这允许容器在授予 AM 对注册表路径的写访问权限的用户令牌过期后更新它们的条目。id:password
对实例化注册表操作实例。${base-path} + "/" + RegistryPathUtils.encodeYarnID(containerId)
此记录应该具有容器持久性策略和容器 ID
yarn:persistence = "container" yarn:id = containerId
当容器终止时,该条目将自动删除。
此容器部署的服务的导出服务端点应该列在服务记录的 external
端点列表中。
${base-path}
下的条目来枚举 YARN 应用程序导出的所有容器。通常在集群中固定的服务,但需要发布绑定和配置信息的,可以发布在注册表中。示例:Apache Oozie 服务。部署应用程序可能也发布的集群外部服务。示例:Amazon Dynamo 实例。
这些服务可以注册在属于运行该服务的用户的路径下,例如 /users/oozie
或 /users/hbase
。客户端应用程序将使用此路径。虽然这可以验证服务记录的有效性,但它确实依赖于客户端应用程序知道服务部署在哪个用户名上,或使用完整路径进行配置。
另一种方法是将服务部署在 /services
下的静态服务路径下。例如,/services/oozie
可以包含 Oozie 服务的注册。由于此路径的权限限制为预配置的系统帐户,因此在安全集群上此路径上的服务注册的存在确认它是由集群管理工具注册的。
/services
下,并且它是由系统用户帐户之一部署的,则它可以直接注册自身。此处 YARN 容器使用某种心跳机制(定期报告)向其 AM 注册以接收工作,通常通过某种心跳机制。如果 AM 配置为容器比应用程序尝试存活更长时间,则当 AM 失败时,容器将继续运行。这些容器需要绑定到任何重新启动的 AM。它们可能还希望得出结论,如果 AM 没有重新启动,它们最终应该超时并自行终止。此类策略有助于应用程序对网络分区做出反应。
internal
端点列表中发布,其中 api
字段设置为容器使用的特定 API 的 URL。ps
命令中可见。更安全的方法是将共享密钥保存到群集文件系统,然后将路径传递给容器。此类路径的 URI 可能为应用程序的注册内部端点之一。管理端口和绑定只是要发布的其他端点。这些应发布为内部端点,因为它们不供公开使用。
客户端应用程序希望找到实现特定 API 的所有服务,例如 "classpath://org.apache.hbase"
registryOperations.list(path)
以列出该路径下所有直接节点,获取子节点的相对列表。stat()
来枚举子记录状态。ServiceRecordHeader.getLength()
的值,则它可能包含服务记录。resolve()
操作检索内容。如果成功,则它确实包含服务记录,因此客户端可以枚举 external
端点并找到具有所需 API 的端点。RegistryPathStatus
状态条目的 children
字段。如果它 >= 0,则应在该条目的路径上递归执行枚举。此算法描述了注册表树的深度优先搜索。当然,还可以进行各种变化,包括广度优先搜索或在找到单个入口点后立即停止搜索。还可以并行搜索不同的子树,这可能会减少搜索时间,但会增加客户端对注册表基础设施的负载。
实用程序类 RegistryUtils
为常见的注册表操作提供了静态实用程序方法,特别是,RegistryUtils.listServiceRecords(registryOperations, path)
执行指定路径的所有直接子记录条目的列出和收集。
客户端应用程序面临“当端点无效时该怎么办”的问题,特别是当服务未运行时,应该怎么做?
一些传输假设中断是暂时的,并且针对原始绑定的旋转重试是正确的策略。这是 Hadoop IPC 客户端的默认策略。
其他传输快速失败,立即通过异常或其他机制报告失败。这对于客户端是直接可见的,但允许客户端重新扫描注册表并重新绑定到应用程序。
最后,一些应用程序从一开始就设计为动态故障转移:它们发布的绑定信息实际上是一个 zookeeper 路径。Apache HBase 和 Apache Accumulo 就是此类示例。注册表用于初始绑定查找,之后客户端本质上具有故障恢复能力。