Block Token 原理分析
介绍
文件权限检查由NameNode执行,而不是DataNode执行。 默认情况下,任何客户端都可以访问只有其块ID的任何块。 为了解决这个问题,Hadoop引入了块访问令牌的概念。 块访问令牌由NameNode生成,并在DataNode端进行合法性验证。块访问令牌作为Hadoop数据传输协议的一部分或通过HTTP查询参数来呈现。一个典型的应用场景如下:一个客户端向NameNode发送文件读请求,NameNode验证该用户具有文件读权限后,将文件对应的所有数据块的ID、位置以及数据块访问令牌发送给客户端;当客户端需要读取某个数据块时,将数据块ID和数据块访问令牌发送给对应的DataNode。由于NameNode已经通过心跳将密钥发送给各个DataNode,因此DataNode可以对数据块进行安全验证,而只有通过安全验证的访问请求才可以获取数据块。
Block Token产生和验证的过程如下:
(1)Namenode经过对客户的身份验证和访问权限验证之后,返回块位置以及块访问令牌。
(2)客户端给Datanode发送块ID以及块访问令牌请求数据。
(3)Datanode经过验证块访问令牌之后返回给客户端请求的数据。
源码分析
用户使用Block Token访问数据的流程图如下:
Block Token的产生
由代码追踪可知Block Token是调用BlockPoolTokenSecretManager类产生的,但实际产生Block Token的操作是由BlockTokenSecretManager类执行的,该类与BlockPoolTokenSecretManager类的关系如下:
BlockPoolTokenSecretManager包含BlockTokenSecretManager,并且每一个blockPool对应一个BlockTokenSecretManager
实际用map存储对应关系:
private final Map<String, BlockTokenSecretManager> map =
new HashMap<String, BlockTokenSecretManager>();
所以先调用BlockPoolTokenSecretManager类的方法获取BlockPoolId找到对应的BlockTokenSecretManager。
/**
* See {@link BlockTokenSecretManager#generateToken(ExtendedBlock, EnumSet)}
*/
public Token<BlockTokenIdentifier> generateToken(ExtendedBlock b,
EnumSet<AccessMode> of) throws IOException {
return get(b.getBlockPoolId()).generateToken(b, of);
}
进入实际产生BlockToken的方法:
/** Generate an block token for current user */
public Token<BlockTokenIdentifier> generateToken(ExtendedBlock block,
EnumSet<AccessMode> modes) throws IOException {
UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
String userID = (ugi == null ? null : ugi.getShortUserName());
LOG.info("sqy test!"+"ugi="+ugi+",userID="+userID);
return generateToken(userID, block, modes);
} /** Generate a block token for a specified user */
public Token<BlockTokenIdentifier> generateToken(String userId,
ExtendedBlock block, EnumSet<AccessMode> modes) throws IOException {
BlockTokenIdentifier id = new BlockTokenIdentifier(userId, block
.getBlockPoolId(), block.getBlockId(), modes);
return new Token<BlockTokenIdentifier>(id, this);
}
经过Kerberos和权限检查之后,Namenode就需要返回给用户块信息了。下面只讲主要的实现方法,调用BlockManager#createLocatedBlock(),该方法主要做了两件事:创建LocatedBlock和产生BlockToken。
(1)进入BlockManager类
private LocatedBlock createLocatedBlock(final BlockInfoContiguous blk, final long pos,
final BlockTokenSecretManager.AccessMode mode) throws IOException {
//获取BlockID、BlockPoolID、userID、位置pos
final LocatedBlock lb = createLocatedBlock(blk, pos);
if (mode != null) {
//设置块令牌
setBlockToken(lb, mode);
}
return lb;
}
由于我们这里主要讲块访问令牌的建立使用过程,创建LocatedBlock获取块信息这部分就不展开讲了。mode=AccessMode.READ,进入到setBlockToken方法中。
public void setBlockToken(final LocatedBlock b,
final BlockTokenSecretManager.AccessMode mode) throws IOException {
// 如果开启BlockToken认证功能,这里是在hdfs-site.xml文件中配置的。
if (isBlockTokenEnabled()) {
// Use cached UGI if serving RPC calls.
b.setBlockToken(blockTokenSecretManager.generateToken(
NameNode.getRemoteUser().getShortUserName(),
b.getBlock(), EnumSet.of(mode)));
}
}
(2)进入BlockTokenSecretManager类
在BlockManager类中调用generateToken方法创建令牌之前,会先创建BlockTokenSecretManager类的实例对象blockTokenSecretManager,设置块访问密钥更新间隔时间、块访问令牌的生命周期、加密算法以及生成了密钥。
/** Generate a block token for a specified user */
public Token<BlockTokenIdentifier> generateToken(String userId,
ExtendedBlock block, EnumSet<AccessMode> modes) throws IOException {
//生成TokenID
BlockTokenIdentifier id = new BlockTokenIdentifier(userId, block
.getBlockPoolId(), block.getBlockId(), modes);
//返回块访问令牌
return new Token<BlockTokenIdentifier>(id, this);
}
产生返回的块令牌信息的实现:
/**
* Construct a token given a token identifier and a secret manager for the
* type of the token identifier.
* @param id the token identifier
* @param mgr the secret manager
*/
public Token(T id, SecretManager<T> mgr) {
password = mgr.createPassword(id); // 设置令牌过期时间和keyId
identifier = id.getBytes();
kind = id.getKind();
service = new Text();
}
Block Token的验证
由之前的理论知识可知,namenode返回给用户块访问令牌,用户根据块信息和块访问令牌去datanode请求文件信息。因此块访问令牌的验证是在datanode发生的,根据代码追踪可知是在DataXceiver类,该类执行了各种block操作处理方法,而在readBlock、writeBlock中就包含了Block Token的验证操作。下面以readBlock方法为例来就行说明。
(1)进入DataXceiver类
public void readBlock(final ExtendedBlock block,
final Token<BlockTokenIdentifier> blockToken,
final String clientName,
final long blockOffset,
final long length,
final boolean sendChecksum,
final CachingStrategy cachingStrategy) throws IOException {
previousOpClientName = clientName;
long read = 0;
updateCurrentThreadName("Sending block " + block);
OutputStream baseStream = getOutputStream();
DataOutputStream out = getBufferedOutputStream();
//进行Token READ访问模式的验证
checkAccess(out, true, block, blockToken,
Op.READ_BLOCK, BlockTokenSecretManager.AccessMode.READ);
......
进入到checkAccess方法中。
private void checkAccess(OutputStream out, final boolean reply,
final ExtendedBlock blk,
final Token<BlockTokenIdentifier> t,
final Op op,
final BlockTokenSecretManager.AccessMode mode) throws IOException {
checkAndWaitForBP(blk);
//判断是否启用BlockToken验证
if (datanode.isBlockTokenEnabled) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking block access token for block '" + blk.getBlockId()
+ "' with mode '" + mode + "'");
}
try {
//进行BlockToken验证
datanode.blockPoolTokenSecretManager.checkAccess(t, null, blk, mode);
} catch(InvalidToken e) {
.....
(2)进入BlockPoolTokenSecretManager类
public Token<BlockTokenIdentifier> generateToken(ExtendedBlock b,
EnumSet<AccessMode> of) throws IOException {
return get(b.getBlockPoolId()).generateToken(b, of);
}
(3)进入BlockTokenSecretManager类
public void checkAccess(Token<BlockTokenIdentifier> token, String userId,
ExtendedBlock block, AccessMode mode) throws InvalidToken {
BlockTokenIdentifier id = new BlockTokenIdentifier();
try {
//从输入流读取参数到tokenID,对其反序列化
id.readFields(new DataInputStream(new ByteArrayInputStream(token
.getIdentifier())));
} catch (IOException e) {
throw new InvalidToken(
"Unable to de-serialize block token identifier for user=" + userId
+ ", block=" + block + ", access mode=" + mode);
}
//验证块令牌中的相关信息(userID、blockID、BlockPoolID、ExpiryDate、mode)
checkAccess(id, userId, block, mode);
.....
结论
以上就是Block Token产生、验证的整个过程。不过是否开启Block Token验证是需要在hdfs-site.xml文件中配置的,默认是false。
dfs.block.access.token.enable
Block Token 原理分析的更多相关文章
- [转]Handler MessageQueue Looper消息循环原理分析
Handler MessageQueue Looper消息循环原理分析 Handler概述 Handler在Android开发中非常重要,最常见的使用场景就是在子线程需要更新UI,用Handler ...
- WebViewJavascriptBridge 原理分析
WebViewJavascriptBridge 原理分析 网上好多都是在介绍 WebViewJavascriptBridge如何使用,这篇文章就来说说 WebViewJavascriptBridge ...
- Java NIO使用及原理分析 (四)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- tomcat原理分析与简单实现
tomcat原理分析与简单实现 https://blog.csdn.net/u014795347/article/details/52328221 2016年08月26日 14:48:18 卫卫羊习习 ...
- Java NIO使用及原理分析 (四)(转)
在上一篇文章中介绍了关于缓冲区的一些细节内容,现在终于可以进入NIO中最有意思的部分非阻塞I/O.通常在进行同步I/O操作时,如果读取数据,代码会阻塞直至有 可供读取的数据.同样,写入调用将会阻塞直至 ...
- OAuth认证协议原理分析及同步消息到Twitter和Facebook使用方法
OAuth有什么用?为什么要使用OAuth? twitter或豆瓣用户一定会发现,有时候,在别的网站,点登录后转到 twitter登录,之后转回原网站,你会发现你已经登录此网站了,这种网站就是这个效果 ...
- Redis数据持久化机制AOF原理分析一---转
http://blog.csdn.net/acceptedxukai/article/details/18136903 http://blog.csdn.net/acceptedxukai/artic ...
- 原理剖析-Netty之服务端启动工作原理分析(下)
一.大致介绍 1.由于篇幅过长难以发布,所以本章节接着上一节来的,上一章节为[原理剖析(第 010 篇)Netty之服务端启动工作原理分析(上)]: 2.那么本章节就继续分析Netty的服务端启动,分 ...
- Hadoop数据管理介绍及原理分析
Hadoop数据管理介绍及原理分析 最近2014大数据会议正如火如荼的进行着,Hadoop之父Doug Cutting也被邀参加,我有幸听了他的演讲并获得亲笔签名书一本,发现他竟然是左手写字,当然这个 ...
随机推荐
- [OpenGL] mac上运行NateRobin的OpenGL教程找不到 data file 解决方案
之前买的OpenGL编程指南第七版一直没看,最近开始看了,然后按照教程推荐的去指定网址下载NateRobin的OpenGL教程,但发现网址已经提示Error:404了, 然后谷歌搜索到可用的下载网址为 ...
- H5 音频
HTML 5 音频 HTML5 视频/DOM HTML5 拖放 HTML5 提供了播放音频的标准. Web 上的音频 直到现在,仍然不存在一项旨在网页上播放音频的标准. 今天,大多数音频是通过插件(比 ...
- Java基础--定时任务Timer(转载)
Java基础--定时任务Timer 一.Timer介绍 java.util.Timer java.util.TimerTask Timer是一个定时器类,通过该类可以为指定的定时任务进行配置.Time ...
- STL部分的实现
C++的STL很强大,里面实现很多功能 就平时经常会用到的vector之类的,自己实现一下, 有哪块错误的希望大神给予指点 vector类模板 template<typename T>cl ...
- sass 与 less 的区别与学习
一直使用的都是sass,公司提出新需求要用less,看了一下less的官方文档,感觉记不住.在这我想用与sass的比较学习,加深印象.也希望可以帮助到一些人. 一.安装sass与less sass基于 ...
- ng-class 用法
很长时间不写页面很多angualrjs的指令用法忘了,搜搜网上的千篇一律“不全”: 下面我把ngclass的用法列出来!(注:网上只有2种,我补充一种三维运算) 1: ng-class=" ...
- MIT 计算机科学及编程导论 Python 笔记 1
计算机科学及编程导论在 MIT 的课程编号是 6.00.1,是计算机科学及工程学院的经典课程.之前,课程一直使用 Scheme 作为教学语言,不过由于 Python 简单.易学等原因,近年来已经改用 ...
- 初学canvas,遇到width和height显示问题和用excanvas.js兼容IE问题
/*-----------------------ITEYE 祈祷幸福博客原创,转载请注明.-------------------*/ 第一次认真写技术博客文~~~若有不严谨的地方,望指正. 今天是第 ...
- while循环学习之统计流量
/application/apache/logs/bbs-access_log日志文件中任意一行的格式如下,以空格为间隔第十列(2632)为此次请求内容的字节数大小 192.168.220.1 - - ...
- Python全栈开发第13天
#多用户登录 import getpass #引用getpass import os #引用os import configparser #引用配置文件操作的库 count = 0 count_oth ...