上一篇文章中,主要讲解了token的一些通用知识,以及hadoop中,token的实现和通用数据结构及流程。
本文主要讲述yarn任务提交运行过程中涉及的几个重要token:AMRMToken,NMToken,ContainerToken。
【AMRMToken】
用于保证ApplicationMaster(下面均简称AM)与RM之间的安全通信,即AM向RM注册,以及后续向RM申请资源的rpc请求,都会带上该token。
AMRMToken在客户端向RM提交任务后,由RM创建生成,然后通过rpc请求传递给NM;NM通过将token持久化到本地文件,让AM启动后从对应文件中加载到token,这样AM就可以使用正确的token向RM注册并完成rpc请求交互了。接下来就展开说明下。
1)token的生成
客户端提交任务请求后,RM在内部的处理中,为AM构造对应的container启动上下文时,创建了AMRMToken,相关代码如下所示:
// AMLauncher.java
private void launch() throws IOException, YarnException {
...
// 构造 container 启动上下文
ContainerLaunchContext launchContext =
createAMContainerLaunchContext(applicationContext, masterContainerID);
...
}
private ContainerLaunchContext createAMContainerLaunchContext(
ApplicationSubmissionContext applicationMasterContext,
ContainerId containerID) throws IOException {
...
setupTokens(container, containerID);
...
}
protected void setupTokens(ContainerLaunchContext container, ContainerId, containerID)
throws IOException {
...
// 构造 AMRMToken
Token<AMRMTokenIdentifier> amrmToken = createAndSetAMRMToken();
if (amrmToken != null) {
credentials.addToken(amrmToken.getService(), amrmToken);
}
...
}
protected Token<AMRMTokenIdentifier> createAndSetAMRMToken() {
Token<AMRMTokenIdentifier> amrmToken =
this.rmContext.getAMRMTokenSecretManager()
.createAndGetAMRMToken(application.getAppAttemptId());
((RMAppAttemptImpl)application).setAMRMToken(amrmToken);
return amrmToken;
}
2)AMRMToken的传递
a. RM --> NM
在构造完container启动上下文后,将启动上下文随container启动请求(StartContainerRequest)发送给NM。
b. NM --> AM
NM收到请求后,内部构造Container实例对象,并从请求中取出credential保存在实例对象中,在真正需要启动AM时,将token信息写到本地文件中。
// ContainerLauncher.java
public Integer call() {
// token存储在 nmPrivate 中的路径
Path nmPrivateTokensPath =
dirsHandler.getLocalPathForWrite(
getContainerPrivateDir(appIdStr, containerIdStr) + Path.SEPARATOR +
String.format(TOKEN_FILE_NAME_FMT, containerIdStr));
// Set th token location too.
// 为AM设置环境变量
addToEnvMap(
environment, nmEnvVars,
ApplicationConstants.CONTAINER_TOKEN_FILE_ENV_NAME,
new Path(
containerWorkDir,
FINAL_CONTAINER_TOKENS_FILE).toUri().getPath());
// 将token写入文件中
try (DataOutputStream tokensOutStream =
lfs.create(nmPrivateTokensPath, EnumSet.of(CREATE, OVERWRITE))) {
Credentials creds = container.getCredentials();
creds.writeTokenStorageToStream(tokensOutStream);
}
...
}
//DefaultContainerExecutor.java
public int launchContainer(ContainerStartContex