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也被邀参加,我有幸听了他的演讲并获得亲笔签名书一本,发现他竟然是左手写字,当然这个 ...
随机推荐
- cassandra简单介绍与基本操作
项目中用到了cassandra,用来存储海量数据,且要有高效的查询:本博客就进行简单的介绍和进行一些基本的操作 一.使用场景: 是一款分布式的结构化数据存储方案(NoSql数据库),存储结构比Key- ...
- iOS切圆角的几个方法
这几天在研究到切圆角的方法,也找了下网上的资料 ---------- 切圆角尽量避免离屏渲染. 1.直接用视图中layer中的两个属性来设置圆角,这种方法比较简单,但是及其影响性能不推荐: @pro ...
- Visual Studio 2017正式版安装
Visual Studio号称宇宙第一IDE, 2017年3月7日强大的微软帝国时隔两年多终于发布新一代IDE Visual Studio 2017.支持的功能简直不能太多,详情移步:https:// ...
- velocity中使用枚举
版权声明:本文为博主原创文章,转载请注明出处,欢迎使劲喷 一.为什么要在velocity中使用枚举 1.目前接触到的系统,枚举通常用来在程序中定义数据字典. 举个支付的例子,比如一个字段用来标识一条记 ...
- 【转】Django HTTP请求的处理流程
Django 和其他 Web 框架的 HTTP 处理的流程大致相同,Django 处理一个 Request 的过程是首先通过中间件,然后再通过默认的 URL 方式进行的.我们可以在 Middlewar ...
- git中常见的几个命令
git中常见的几个命令 本地仓库 三个区域 工作目录 暂存区 本地仓库 文件的四个状态 未跟踪 untracked 已暂存 staged 已提交commited 已修改 modified 基本命令 g ...
- spdlog源码阅读 (1): sinks
0. spdlog简单介绍 spdlog 是一个快速的 C++ 日志库,只包含头文件,兼容 C++11.项目地址 特性: 非常快 只包含头文件 无需依赖第三方库 支持跨平台 - Linux / Win ...
- 【树莓派】h2数据库操作相关
之前在树莓派上面操作时候,遇到一些业务方面的bug,和团队中的同事经过多次尝试,但就是难以重现用户现场的问题. 但是问题却实实在在地发生,虽然并不是必然可重现的bug,但是也比较闹心: 发生了问题,也 ...
- [转载]或许您还不知道的八款Android开源游戏引擎
或许您还不知道的八款Android开源游戏引擎 分类: 技术文章 2010-08-04 20:27 17430人阅读 ...
- 前端开发必备组件库【基于原生js、兼容主流浏览器、B/S必备】
[持续更新中...跪求点击右上角星星,好人一生平安!] API详见github,链接如下: https://github.com/pomelott/pomelo-plug-in