hadoop中hdfs写入流程

hdfs写入数据流程总结:
================================
1、通过配置文件获取DistributedFileSystem实例
2、初始化校验和类型和大小 ===> 类型CRC32C,大小4byte //对每个chunk进行校验,chunk大小512字节
3、创建namenode元数据:
在DFSOutputStream中dfsClient.namenode.create
4、使用computePacketChunkSize方法对packet和chunk进行计算 //计算每个packet中的chunk数量(126)
5、使用DFSPacket初始化包对象
6、writeChecksumChunks写入数据:方法,最终使用System.arrayCopy方法:
先写入4 x 9字节的checksum
再写入512 x 9字节的chunk

7、waitAndQueueCurrentPacket:将数据放入dataQueue中。接着notifyAll,唤醒DataStreamer线程


8、DataStreamer:设置管线,然后打开datanode的传输流,
底层传输使用的是nio的非阻塞技术
protobuf串行化技术

9、数据写入成功的时候:
dataQueue.removeFirst(); //将数据队列中的第一个数据删除
ackQueue.addLast(one); //将此数据移动到确认队列的末尾
dataQueue.notifyAll(); //通知DataStreamer继续传输包

10、将数据实例化到磁盘的过程:
先把checksum和data之间的鸿沟去掉:
移动checksum数据到data数据之前
移动header数据到checksum之前


HDFS 上传流程
过程解析:详解
这里描述的 是一个256M的文件上传过程
① 由客户端 向 NameNode节点节点 发出请求
②NameNode 向Client返回可以可以存数据的 DataNode 这里遵循 机架感应 原则

③客户端 首先 根据返回的信息 先将 文件分块(Hadoop2.X版本 每一个block为 128M 而之前的版本为 64M)
④然后通过那么Node返回的DataNode信息 直接发送给DataNode 并且是 流式写入 同时 会复制到其他两台机器
⑤dataNode 向 Client通信 表示已经传完 数据块 同时向NameNode报告
⑥依照上面(④到⑤)的原理将 所有的数据块都上传结束 向 NameNode 报告 表明 已经传完所有的数据块

这样 整个HDFS上传流程就 走完了



DFSPacket:
========================================
/**
* buf is pointed into like follows:
* (C is checksum data, D is payload data)
*
* [_________CCCCCCCCC________________DDDDDDDDDDDDDDDD___]
* ^ ^ ^ ^
* | checksumPos dataStart dataPos
* checksumStart

*
* Right before sending, we move the checksum data to immediately precede
* the actual data, and then insert the header into the buffer immediately
* preceding the checksum data, so we make sure to keep enough space in
* front of the checksum data to support the largest conceivable header.
*/

DataStreamer:
=========================================
DataStreamer类是对从管线发送数据包到datanode是可响应的,
从namenode获取新的块id和块位置,然后开始流式传输包到datanodes
每个包都有一个序列号相关联,当block中所有的packet被发出且收到所有的包回执
DataStreamer就关闭当前的块

DFSOutputStream:
=======================================================
客户端程序将数据通过这个流写入到内部缓存。
数据被分割成packet,每个包64k

一个packet由chunk组成。每个chunk是512字节,相应的关联一个校验和

当客户端程序填满当前的packet,会填充到dataQueue(数据队列)。
DataStreamer 线程从dataQueue(数据队列)抓取数据,并将其通过管线发送到第一个datanode
接着将数据从dataQueue(数据队列)移动到ackQueue(确认队列)。当收到所有数据节点的确认回执
ResponseProcessor(响应处理器)会将数据从ackQueue(确认队列)中移除

如果出现错误,所有未完成的包将从ackQueue(确认队列)移出
通过清除错误数据节点的管线,生成一个新的管线
DataStreamer开始重新传输数据

Datanode和Namenode的VERSION文件:
namenode:
=================================
#Sun Mar 18 09:36:21 CST 2018
namespaceID=133742883
clusterID=CID-126a68dc-a8c1-4517-8f28-60fb6af6c269
cTime=0
storageType=NAME_NODE
blockpoolID=BP-1464761855-192.168.23.101-1520907981134
layoutVersion=-63

datanode:
==================================
#Sun Mar 18 09:36:47 CST 2018
storageID=DS-6068e606-1d2d-4865-aa62-1cd326ee3e64
clusterID=CID-126a68dc-a8c1-4517-8f28-60fb6af6c269
cTime=0
datanodeUuid=705f0e4e-a50b-4448-84ed-fc6e2f8d2923
storageType=DATA_NODE
layoutVersion=-56


HDFS特性:
适用于存储超大文件
适用于流式数据访问,不具有随机定位文件的功能
支持构建于商业硬件
不适用于低时间延迟的数据访问
不适用于存储海量小文件 //har、压缩、sequenceFile
不适用于多用户写入和任意位置修改文件


MapReduce:
编程模型,适用于分布式处理海量文件

App //入口函数(main)
Mapper //map
Reducer //reduce


在集群运行MR程序:
1、修改代码
2、将代码打包成jar 并发送到Linux操作系统
3、创建源文件(1.txt)
4、使用命令hadoop jar myhadoop.jar com.oldboy.mr.App /1.txt /out

1、输入路径可以写文件名和文件夹名:
文件夹名称会将文件夹下所有文件读取,且忽略子目录文件

2、Map数和文件数量有关:
需要将小文件进行归档或压缩
hadoop archive -archiveName temp.har -p / Temp /


partition:分区,指派某种类型的key发送到某个reduce进行计算
hash分区: (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;

key.hashCode() & Integer.MAX_VALUE //保证数字为正值
% numReduceTasks //取余数,保证范围在0~n-1之间

自定义分区:

public class WCPartitioner extends Partitioner<Text,IntWritable> {
    /**
     * 数字到分区0,字符到分区1
     */
    @Override
    public int getPartition(Text text, IntWritable intWritable, int numPartitions) {
    String key = text.toString();
    try {
        Integer.parseInt(key);
        return 0;
    } catch (Exception e) {
        return 1;
    }
    }
}

combiner:
map端的reduce:
在map端预处理时候的聚合(预聚合)

原文地址:https://www.cnblogs.com/zyde/p/8900234.html