HDFS Append时packet的格式以及DataNode对block/checksum文件的处理

HDFS的Block一般比较大,默认64MB/128MB,客户端给DataNode发数据实际上是以Packet的形式发送的,Packet一般只有64KB左右。Packet内部由分为一个个chunk,每个chunk一般情况(后面会说非一般情况)下512Bytes,并且Packet内部对于每个chunk会带上这个chunk的checksum,对于CRC来说,checksum本身占用4Bytes。一个Packet的结构如下:

其中header中包含了一些元信息,比如这个packet是不是所属block的最后一个packet,数据长度多少,编码多少,packet的数据部分的第一个字节在block中的offset,DataNode接到这个Packet是否必须sync磁盘。

下面主要关注当客户端使用如下模式写数据时,数据是怎样被封装成一个个packet的:

FSDataOutputStream out = fs.append(new Path(file));
out.write(b, off, len);
out.hflush()

首先,假设需要进行append的file一开始不存在,没有任何数据。

实际上,out是HdfsDataOutputStream类型,out.write(b,off,len)最终调用了HdfsDataOutputStream包含的DFSOutputStream类型对象,转而调用的是DFSOutputStream的父类FSOutputSummer的write(b,off,len),FSOutputSummer从名字可以看出,对数据进行了checksum.

FSOutputSummer的write(b,off,len)实质上就一行:

for (int n=0;n<len;n+=write1(b, off+n, len-n)) {}

实际上就是循环的调用write1方法将数据写入,write1方法会去检查是否写入的数据满了一个chunk(正常情况下512Bytes),如果满了,则为这个chunk计算一个checksum,4个字节,然后将这个chunk和对应的checksum写入当前Packet中(DFSOutputStream的writeChunk方法),格式就是上面那个图中的格式。当Packet满了,也就是说塞入的chunk的个数到达了预先计算的值,就将这个packet放入dataQueue,后台会有一个DataStreamer线程专门从这个dataQueue中取一个个的packet发送出去。

到这里,都比较清晰,需要注意的是,如果append的file中本身已经存在了一些数据,比如512+512+100Bytes,那么在调用out.write(b,off,len)向file中追加新的数据时,构造的第一个packet中只有一个chunk,并且这个chunk的大小是512-100=412Bytes,这个packet之后的packet的chunk是标准512Bytes。

if (appendChunk && bytesCurBlock%bytesPerChecksum == 0) {
appendChunk = false;
// 下次计算checksum时的chunk大小是512Bytes,不再是412Bytes
resetChecksumChunk(bytesPerChecksum);
}

以上代码来自DFSOutputStream的writeChunk方法,其中appendChunk在fs.append时会被置为true,并且bytesCurBlock会初始化为append之前文件的大小,当构造完特殊包后,bytesCurBlock增加了412Bytes,将上次的paritial chunk补齐了。

DataStreamer从dataQueue中取packet发送出去的过程不关注,下面看DataNode针对append如何处理block文件和block的checksum文件。

DataNode上接受Block的逻辑封装在BlockReceiver中,其中,receiveBlock方法中有一段代码

while (receivePacket() >= 0) { /* Receive until the last packet */ }

每调一次receivePacket,DataNode就接收一个packet,将packet的data和checksum都拿出来,进行一次校验,看数据在发送过程中是否损坏,然后看block在当前DataNode上的副本在磁盘上的长度是否是chunk的整数倍,如果不是,则将block checksum文件(blk_1100893627_27540491.meta)的输出流seek到最后一个checksum,并且将最后一个checksum读出来,如下代码:

 if (onDiskLen % bytesPerChecksum != 0) {
// prepare to overwrite last checksum
adjustCrcFilePosition();
} // If this is a partial chunk, then read in pre-existing checksum
if (firstByteInBlock % bytesPerChecksum != 0) {
LOG.info("Packet starts at " + firstByteInBlock +
" for " + block +
" which is not a multiple of bytesPerChecksum " +
bytesPerChecksum);
long offsetInChecksum = BlockMetadataHeader.getHeaderSize() +
onDiskLen / bytesPerChecksum * checksumSize;
computePartialChunkCrc(onDiskLen, offsetInChecksum, bytesPerChecksum);
}

然后将数据写入block文件(blk_1100893627),将checksum写入block checksum文件(blk_1100893627_27540491.meta)

block file和block checksum file格式如下:



参考资料

Hadoop 2.5.0

HDFS Append时packet的格式以及DataNode对block/checksum文件的处理的更多相关文章

  1. iOS block 声明时和定义时的不同格式

    今天写程序时,在实现一个block时总提示格式错误,对比api的block参数格式,没发现错误.后来查阅了资料,发现这两个格式是不同的! 具体格式见下方 NSString * (^testBlock) ...

  2. spyder在编辑过程中被自己弄乱了,想要恢复成安装时默认的格式或者重置页面格式的解决办法

    打开spyder,tools-->Reset Spyder to factory defaults,按照如上操作即可恢复成安装时的默认格式.

  3. WPF绑定文本时使用指定格式文本

    原文:WPF绑定文本时使用指定格式文本 Text="{Binding PlayletModel.characters,StringFormat=Cast : {0}}" Strin ...

  4. 在js内生成PDF文件并下载的功能实现(不调用后端),以及生成pdf时换行的格式不被渲染,word-break:break-all

    在js内生成PDF文件并下载的功能实现(不调用后端),以及生成pdf时换行的格式不被渲染,word-break:break-all 前天来了个新需求, 有一个授权书的文件要点击下载, 需要在前端生成, ...

  5. HDFS源码分析心跳汇报之DataNode注册

    HDFS源码分析心跳汇报之DataNode注册,近期推出!

  6. ASM时的OFM特性对影的建数据文件名称的影响及为SYSTEM表空间的数据文件使用别名

    客户遇到个DG的问题,存储使用的ASM管理,有多个磁盘盘. 在主库创建数据文件,备库自己主动创建的数据文件都在同一磁盘组,而且在主库创建数据文件是指定的是类似**.DBF的名字,到备库也变成了使用AS ...

  7. 安装Ruby、Sass在WebStrom添加Watcher实现编辑scss文件时自动生成.map和压缩后的.css文件

    前言 这段时间一直在看Bootstrap,V3官方直接提供了Less版本的源码,就先将Less学完了,很简单的语法,学习写Demo都是在Webstorm里写的,配置了Watcher自动编译(详见< ...

  8. oracle expdp导入时 提示“ORA-39002: 操作无效 ORA-39070: 无法打开日志文件 ”

    1.导出数据库的时候报错 expdp zz/zz@orcl directory=exp_dp dumpfile=zz_20170520.dump logfile=zz_20170520.log   2 ...

  9. SqlServer 2014还原数据库时提示:无法在已有的""上还原文件,请重新发出RESTORE语句,用WITH REPLACE来覆盖原先存在的文件

    场景 SQL Server 2014在还原数据库时提示: 无法在已有的""上还原文件,请重新发出RESTORE语句,用WITH REPLACE来覆盖原先存在的文件... 实现 在还 ...

随机推荐

  1. EventBus 3.0使用

    在没用eventBus之前一直用Android广播方式通知消息更新UI 广播写法 首先发送广播通知 Intent intent = new Intent(); intent.setAction(&qu ...

  2. 使用dynamic类型改进反射

    首先还是声明一下,使用场景: 1.如果编译时函数名称确定,对象类型运行时确定,那么运用dynamic是一个好主意.2.如果编译时函数名称确定,对象类型在编译时也确定,那就既不需要反射也不需要dynam ...

  3. 如何启动ResourceManager和NodeManager

    登录到bigtop1上,vagrant ssh bigtop1 将/usr/lib/hadoop/libexec/init-hdfs.sh文件内容替换为: #!/bin/bash -ex # # Li ...

  4. 关于Unity程序在IOS和Android上显示内嵌网页的方式

    近期因为有须要在Unity程序执行在ios或android手机上显示内嵌网页.所以遍从网上搜集了一下相关的资料.整理例如以下: UnityWebCore 从搜索中先看到了这个.下载下来了以后发现这个的 ...

  5. yii2高级应用

    public function searchWithRelated() {         $criteria = new CDbCriteria; $criteria->together = ...

  6. 纯CSS3实现3D特效的iPhone 6动画

    iPhone 6发布不久,屌丝怎能买得起,不过作为程序员,今天看到一个用纯CSS3绘制的iPhone 6,由于CSS3特性的运用,带有点3D的动画特效,大家可以先来看看在线演示效果. 在线演示    ...

  7. LLVM

    http://blog.csdn.net/snsn1984/article/details/41077763

  8. Oracle数据库入门——高水位线详解

    一.什么是水线(High Water Mark)? 所有的oracle段(segments,在此,为了理解方便,建议把segment作为表的一个同义词) 都有一个在段内容纳数据的上限,我们把这个上限称 ...

  9. 制作便携版 FireFox 火狐浏览器

    Firefox是一款可高度自定义的开源浏览器: 你可以访问 火狐DIY 定制自己的Firefox安装包, 此外,你还可以自己动手定制一款可以放在U盘随身携带的便携版Firefox火狐浏览器. 制作便携 ...

  10. js类(继承)(二)

    1. 定义js类 js并不是一种面向对向的语言, 没有提供对类的支持, 因此我们不能像在传统的语言里那样 用class来定义类, 但我们可以利用js的闭包封装机制来实现js类, 我们来封装一个简的Sh ...