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也被邀参加,我有幸听了他的演讲并获得亲笔签名书一本,发现他竟然是左手写字,当然这个 ...
随机推荐
- Js里面的数组去重方法
去掉数组里面重复的有很多种,我这里就说一种比较简单的吧. var arr=[23,33,44,33,44,66,44,55,44,4,44,33,23]; for(var i=0;i<arr.l ...
- 微信企业号接收消息(使用SpringMVC)
微信企业号接收消息(使用SpringMVC) 微信企业号接收消息(使用SpringMVC) 将应用设置在回调模式时,企业可以通过回调URL接收员工回复的消息,以及员工关注.点击菜单.上报地理位置等事件 ...
- Postgresql 经纬度
增加一列: add column `location` geometry default p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px &q ...
- Python模块发布
项目根目录添加setup.py模块: from distutils.core import setup setup( name="模块名字", version="1.0. ...
- ASP.NET MVC 创建控制器类过程
MvcHandler.ProcessRequestInit()方法: 1.1获取控制器的名称string requiredString = this.RequestContext.RouteData. ...
- golang http server分析(一)
http:http请求过程实质上是一个tcp连接通信,具体通过socket接口编码实现 在go中是通过listenAndServer()方法对外提供了一个http服务,在该方法中完成了socket的通 ...
- 多线程——i++的坑
在使用socket编程的时候发生数据丢失问题,一直以为是网络原因,后来测试后发现是多线程操作同一数据源又未加入数据锁导致. 直接上代码,下面程序执行的结果可能出现198.199.200.两个线程统一时 ...
- jQuery 事件——关于select选中
场景: eg:在管理一篇博文时,因博文的管理有一列叫:状态的列,该列有诸多状态,如:正常,待审核,删除等... 此时,若使用Select下拉列表进行状态选择,并在选中具体项值后,通过Ajax异步提交, ...
- 【2017-03-24】CSS样式表
CSS样式表:层叠式样式表 一.样式表的分类 1.内联式 写在标记的属性位置,优先级最高,重用性最差. 格式: <div style="width:100px;height:100px ...
- mysql的导入和导出
MYSQL数据库导出 以root登录vps,执行以下命令导出. 1./usr/local/mysql/bin/mysqldump -u root -p123456 zhumaohai > /ho ...