HDFS:分布式文件系统
HDFS是GFS的简化版,它同一时刻只允许一个用户对同一文件进行追加写操作(GFS允许并发写)。它适合存储大文件,并提供高吞吐量的顺序读/写访问。
它的早期版本两大问题,例如:单点失效和水平扩展不佳。针对这两个问题,在hadoop2.0提出统一的解决方案,即HA和NameNode联盟。
HDFS的设计目标
- 存储大文件
- 文件一次写(支持追加写)/顺序读
HDFS优点:
- 适合大数据处理(支持GB,TB,PB级别的数据存储,支持百万规模以上的文件数量)
- 适合批处理(支持离线的批量数据处理,支持高吞吐率)
- 高容错性(以数据块存储,可以保存多个副本,容易实现负载均衡)
HDFS缺点:
- 小文件存取(占用namenode大量内存,浪费磁盘空间)
- 不支持并发写入(同一时刻只能有一个进程写入,不支持随机修改)
HDFS整体架构
HDFS采用master/slave架构。一个HDFS集群包含一个单独的NameNode,一个Secondary NameNode和多个DataNode。
NameNode
负责存储整个分布式文件系统的元数据,包括:
- 负责管理文件系统的名字空间操作,比如打开、关闭、重命名文件或目录。
- 负责确定数据块到具体Datanode节点的映射(文件到块的映射,块到DataNode的映射)。
- 监督Data nodes的健康
- 协调数据的存取。
这些数据保存在内存里,同时磁盘里面有两个元数据文件,fsimage和editlog,这两个结合可以构建完整的内存元数据。
Name元数据大小估计
对象类别 | 估算大小(bytes) | 计算方法 | 估计总大小(bytes) |
---|---|---|---|
文件 | 224 | 224+2*文件名长度 | 250 |
目录 | 264 | 264+2*文件名长度 | 290 |
块 | 152 | 152+72*副本数 | 368 |
Secondary NameNode
secondary NameNode并不是NameNode的热被,它负责拉取fsimage和editlog并且把它们合并形成新的fsimage并传回。所以本质上,Secondary NameNode是NameNode的一个检查点。
DataNode
DataNode保存文件数据,并负责数据块实际的读/写操作。HDFS会自动将用户上传的大文件切分为block,每个block默认大小是64M,每个block在HDFS中会备份三份
Client
Client和NameNode交互获得元数据,与DataNode交互进行实际的读写操作。
HDFS写文件操作
HDFS只允许同一时刻只有一个客户端对文件进行操作,同时HDFS支持追加写,不支持随机写
- Client调用DistributedFileSystem对象的create方法,创建一个文件输出流(FSDataOutputStream)对象
- 通过DistributedFileSystem对象与Hadoop集群的NameNode进行一次RPC远程调用,在HDFS的Namespace中创建一个文件条目(Entry),该条目没有任何的Block
- 写文件前,向NameNode申请Block,NameNode返回可写文件的DataNode列表
- 通过FSDataOutputStream对象,向DataNode写入数据,数据首先被写入FSDataOutputStream对象内部的Buffer中,然后数据被分割成一个个Packet(64k)数据包
- 以Packet最小单位,基于Socket连接发送到按特定算法选择的HDFS集群中一组DataNode(正常是3个,可能大于等于1)中的一个节点上,在这组DataNode组成的Pipeline上依次传输Packet
- 这组DataNode组成的Pipeline反方向上,发送ack,最终由Pipeline中第一个DataNode节点将Pipeline ack发送给Client。
- 一个Block已经写入到DataNode节点磁盘,Client调用fsync让NameNode持久化Block的位置信息数据,DataNode也会通知NameNode成功持久化Block(这里存在一个不一致时间)。因为每个Block默认大小是64M,文件大于64M,跳到3。
- 完成向文件写入数据,Client在文件输出流(FSDataOutputStream)对象上调用close方法,关闭流
- 调用DistributedFileSystem对象的complete方法,通知NameNode文件写入成功
static String[] contents = new String[] {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"dddddddddddddddddddddddddddddddd",
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
};
public static void main(String[] args) {
String file = "hdfs://h1:8020/data/test/test.log";
Path path = new Path(file);
Configuration conf = new Configuration();
FileSystem fs = null;
FSDataOutputStream output = null;
try {
fs = path.getFileSystem(conf);
output = fs.create(path); // 创建文件
for(String line : contents) { // 写入数据
output.write(line.getBytes("UTF-8"));
output.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端写数据内部实现原理
打开一个DFSOutputStream流,Client会写数据到流内部的一个缓冲区中,然后数据被分解成多个Packet,每个Packet大小为64k字节,每个Packet又由一组chunk和这组chunk对应的checksum数据组成,默认chunk大小为512字节,每个checksum是对512字节数据计算的校验和数据。
创建Packet
当长度满足一个Chunk大小(512B)时,便会创建一个Packet对象,然后向该Packet对象中写Chunk Checksum校验和数据,以及实际数据块Chunk Data,每次满足一个Chunk大小时,都会向Packet中写上述数据内容,直到达到一个Packet对象大小(64K),就会将该Packet对象放入到dataQueue队列中,等待DataStreamer线程取出并发送到DataNode节点。
发送Packet
DataStreamer线程从dataQueue队列中取出Packet对象,放到ackQueue队列中,然后向DataNode节点发送这个Packet对象所对应的数据。
接收ack
发送一个Packet数据包以后,会有一个用来接收ack的ResponseProcessor线程,如果收到成功的ack,则表示一个Packet发送成功。如果成功,则ResponseProcessor线程会将ackQueue队列中对应的Packet删除。如果发生错误,则重新加入dataQueue。
DataNode写数据内部原理
DataNode接受到数据Packet,首先将数据写道下一个DataNode的PipeLine中,然后再写入本地磁盘的Block中,写完后回复上一个DataNode ack。整个Block写成功后,通知NameNode已经收到Block。实际流程如图所示:
持久化包括block的持久化和block checksum的持久化,
HDFS读文件
HDFS读文件分为两步:从NameNode读取文件Block列表,从DataNode读取Block。下面是一段读文件的代码
package org.shirdrn.hadoop.hdfs;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class HdfsFileReader {
public static void main(String[] args) {
String file = "hdfs://hadoop-cluster-m:8020/data/logs/basis_user_behavior/201405071237_10_10_1_73.log";
Path path = new Path(file);
Configuration conf = new Configuration();
FileSystem fs;
FSDataInputStream in;
BufferedReader reader = null;
try {
fs = FileSystem.get(conf);
in = fs.open(path); // 打开文件path,返回一个FSDataInputStream流对象
reader = new BufferedReader(new InputStreamReader(in));
String line = null;
while((line = reader.readLine()) != null) { // 读取文件行内容
System.out.println("Record: " + line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(reader != null) reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
读取文件流程:
- 客户端调用open打开文件,然后从NameNode获取Block信息(默认预先获取10个),文件长度等信息。
- 获取Block列表后,会对Block列表中的DataNode进行排序,排序规则为以下两点
- Client到Block所在的Datanode的距离
- 如果某个DataNode很久没有心跳,那么就放在列表的最后
- 开始对Block进行读取,通过偏移量获取Block,然后根据Block选择合适的DataNode,从DataNode读取数据。重复3,直到读完数据。
- 如果客户端没有缓存需要的Block,又向NameNode拉取Block。跳2
注:有个博客说一旦写入的数据超过一个块的数据,新的读取者就能看见第一个块。对于之后的块也是这样。总之,它始终是当前正在被写入的块,其他读取者是看不见它的。
一致性模型
根据上面的写入操作,我们知道在写完了一个Block后,客户端会调用fsync向NameNode提交Block完成信息。所以:
- 对于一个完整的Block而言,是强一致性的。
- 对于不足一个Block的数据而言,数据可能因为HDFS宕机而丢失。这种情况用户主动调用fsyc向NameNode持久化
容错
HDFS通过复制副本实现容错,NameNode来控制所有的block的复制决策。一般而言,3副本配置是同一机架不同机器放置2个,不同机架放置1个。
DataNode容错
通过心跳机制检测DataNode,如果一段时间没有收到DataNode的心跳信息,判定机器宕机,设置这台机器不可用。因此Namenode会检测是否有文件block的副本数目小于设置值,如果小于就自动开始复制新的副本并分发到其他Datanode节点。
如果在写入的时候,发现某台DataNode一直不回应,向NameNode重新申请DataNode。
检查文件的块的完整性
客户端读取文件后,会检查和文件关联checksum是否一致,如果不一致,从其它DataNode读取数据
NameNode容错
NameNode磁盘中会有元数据信息的持久化信息,可以根据磁盘数据恢复元数据信息。万一NameNode磁盘也损坏了,Secondary NameNode还有历史信息。
集群均衡
- 数据均衡服务(Rebalancing Server)首先要求 NameNode 生成 DataNode 数据分布分析报告,获取每个DataNode磁盘使用情况
- Rebalancing Server汇总需要移动的数据分布情况,计算具体数据块迁移路线图。数据块迁移路线图,确保网络内最短路径
- 开始数据块迁移任务,Proxy Source Data Node复制一块需要移动数据块
- 将复制的数据块复制到目标DataNode上
- 删除原始数据块
- 目标DataNode向Proxy Source Data Node确认该数据块迁移完成
- Proxy Source Data Node向Rebalancing Server确认本次数据块迁移完成。然后继续执行这个过程,直至集群达到数据均衡标准
第2步中,HDFS会把当前的DataNode节点,根据阈值的设定情况划分到Over、Above、Below、Under四个组中。在移动数据块的时候,Over组、Above组中的块向Below组、Under组移动。
发展与改进
NameNode的HA方案
需要有如下保证
- 共享第三方存储,NameNode强一致性
- 需要隔离措施保证不会出现脑裂
NameNode联盟
单点NameNode联盟成为HDFS的瓶颈,主要表现在:限制了文件的个数;都与NameNode交互性能瓶颈。提出NameNode联盟解决这个问题
HDFS:分布式文件系统的更多相关文章
- HDFS分布式文件系统资源管理器开发总结
HDFS,全称Hadoop分布式文件系统,作为Hadoop生态技术圈底层的关键技术之一,被设计成适合运行在通用硬件上的分布式文件系统.它和现有的分布式文件系统有很多共同点,但同时,它和其他的分布式 ...
- 通过Thrift访问HDFS分布式文件系统的性能瓶颈分析
通过Thrift访问HDFS分布式文件系统的性能瓶颈分析 引言 Hadoop提供的HDFS布式文件存储系统,提供了基于thrift的客户端访问支持,但是因为Thrift自身的访问特点,在高并发的访问情 ...
- Hadoop HDFS分布式文件系统 常用命令汇总
引言:我们维护hadoop系统的时候,必不可少需要对HDFS分布式文件系统做操作,例如拷贝一个文件/目录,查看HDFS文件系统目录下的内容,删除HDFS文件系统中的内容(文件/目录),还有HDFS管理 ...
- Hadoop基础-HDFS分布式文件系统的存储
Hadoop基础-HDFS分布式文件系统的存储 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.HDFS数据块 1>.磁盘中的数据块 每个磁盘都有默认的数据块大小,这个磁盘 ...
- 认识HDFS分布式文件系统
1.设计基础目标 (1) 错误是常态,需要使用数据冗余 (2)流式数据访问.数据批量读而不是随机速写,不支持OLTP,hadoop擅长数据分析而不是事物处理. (3)文件采用一次性写多次读的模型, ...
- 1、HDFS分布式文件系统
1.HDFS分布式文件系统 分布式存储 分布式计算 2.hadoop hadoop含有四个模块,分别是 common. hdfs和yarn. common 公共模块. HDFS hadoop dist ...
- 我理解中的Hadoop HDFS分布式文件系统
一,什么是分布式文件系统,分布式文件系统能干什么 在学习一个文件系统时,首先我先想到的是,学习它能为我们提供什么样的服务,它的价值在哪里,为什么要去学它.以这样的方式去理解它之后在日后的深入学习中才能 ...
- 大数据基础总结---HDFS分布式文件系统
HDFS分布式文件系统 文件系统的基本概述 文件系统定义:文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易. 文件名:在文件系统中,文件名是用于定位存储位置. 元数据(Metad ...
- hdfs(分布式文件系统)优缺点
hdfs(分布式文件系统) 优点 支持超大文件 支持超大文件.超大文件在这里指的是几百M,几百GB,甚至几TB大小的文件.一般来说hadoop的文件系统会存储TB级别或者PB级别的数据.所以在企业的应 ...
- 【史上最全】Hadoop 核心 - HDFS 分布式文件系统详解(上万字建议收藏)
1. HDFS概述 Hadoop 分布式系统框架中,首要的基础功能就是文件系统,在 Hadoop 中使用 FileSystem 这个抽象类来表示我们的文件系统,这个抽象类下面有很多子实现类,究竟使用哪 ...
随机推荐
- D3_book 11.1 pie
<!-- pie example --> <!DOCTYPE html> <meta charset="utf-8"> <style> ...
- JavaSocket简单通信
以下介绍:简单的socket发送消息,服务的Server 相互 客户端Client,进行简单的传递消息: 服务端代码: package test; import java.io.DataInputSt ...
- Linq的基本用用法
Linq 的基本用法: Sort , OrderBy, Skip,Take,Where,Compare,Join,Distinct ,InsertRange 等关键词 Select用法 var sel ...
- gdb用法
mickole@test:~/ctest/05gdb$ gdb simple //开始gdb调试 GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4- ...
- 设计模式之单件模式(Singleton Pattern)
一.单件模式是什么? 单件模式也被称为单例模式,它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象,比如:数据库连接对象.注册表对象.线程池对象等等,这种对象如果同 ...
- char、varchar、nchar、nvarchar特点比较
于程序中的string型字段,SQLServer中有char.varchar.nchar.nvarchar四种类型来对应(暂时不考虑text和ntext),开建立数据库中,对这四种类型往往比较模糊,这 ...
- 深入理解Aspnet Core之Identity(4)
主题 之前简单介绍了Asp.net core 的初步的使用,本篇我打算给大家介绍一下Identity的架构,让大家对Identity有一个总体的理解和认识. 简介 博客原文欢迎访问我的博客网站,地址是 ...
- .net程序中http请求的超时配置
请求时的超时 // // 摘要: // 获取或设置 System.Net.HttpWebRequest.GetResponse() 和 System.Net.HttpWebRequest.GetReq ...
- LinkedBlockingQueue源码解析(2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 3.3.public void put(E e) throws InterruptedException 原 ...
- Django分页设置
1. """ 分页组件使用示例: obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.pa ...