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 这个抽象类来表示我们的文件系统,这个抽象类下面有很多子实现类,究竟使用哪 ...
随机推荐
- Need You Now --Lady Antebellum
战地女神(Lady Antebellum)由女主唱 Hillary Scott.男主唱 Charles Kelley .吉他/键盘手 Dave Haywood,2006夏天在美国乡村音乐重镇纳什维尔组 ...
- Activity-fragment-ListView展示
在上一篇博客,Android-fragment简介-fragment的简单使用,介绍了简单的使用: 这篇博客主要讲解,在fragment做处理事情(Activity的事情) Activity pack ...
- Thread in depth 3:Synchronization
Synchronization means multi threads access the same resource (data, variable ,etc) should not cause ...
- visual studio code 中隐藏从 ts 文件生成的 js 文件和 map 文件
typescript 文件编译产生的 js 和 map 文件不需要手工编辑,打开[文件][首选项][工作区设置],放入以下代码: // 将设置放入此文件中以覆盖默认值和用户设置. { "fi ...
- SQL SERVER 2008 附加数据库出现只读问题。
问题描述 在附加数据库时出现的图片: 解决办法 步骤一,修改文件夹的 1.打开该数据库文件存放的目录或数据库文件的属性窗口,选择"属性"菜单->选择"安全&qu ...
- 使用MEF与Castle实现AOP
MEF是微软的一个ioc框架,使用非常方便,我们只需要在需要导出的类上标记[Export],在需要使用的地方[import]就可以使用了.现在我们扩展MEF,在其装配生成实例时,使用Castle Dy ...
- NetCore入门篇:(三)Net Core项目Nuget及Bower包管理
一.创建项目 1.如何创建项目,参照上一篇文章 二.程序包介绍 1.Net Core的程序包分前后端两种,后端用nuget,前端用bower. 2.与Net 不同,Net Core引用nuget包时, ...
- 978. Longest Turbulent Subarray
A subarray A[i], A[i+1], ..., A[j] of A is said to be turbulent if and only if: For i <= k < j ...
- Django 项目 实现重定向并进行反向解析
一.项目路由配置urls.py中 from django.conf.urls import include, url from django.contrib import admin # 匹配应用 u ...
- spring boot 使用application.properties 进行外部配置
application.properties大家都不陌生,我们在开发的时候,经常使用它来配置一些可以手动修改而且不用编译的变量,这样的作用在于,打成war包或者jar用于生产环境时,我们可以手动修改环 ...