大数据入门第六天——HDFS详解
一、概述
1.HDFS中的角色
Block数据:
HDFS中的文件在物理上是分块存储(block),块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在hadoop2.x版本中是128M,之前的版本中是64M
基本存储单位,一般大小为64M(配置大的块主要是因为:1)减少搜寻时间,一般硬盘传输速率比寻道时间要快,大的块可以减少寻道时间;2)减少管理块的数据开销,每个块都需要在NameNode上有对应的记录;3)对数据块进行读写,减少建立网络的连接成本)
一个大文件会被拆分成一个个的块,然后存储于不同的机器。如果一个文件少于Block大小,那么实际占用的空间为其文件的大小
基本的读写S#x5355;位,类似于磁盘的页,每次都是读写一个块
- 每个块都会被复制到多台机器,默认复制3份
NameNode:
负责管理整个文件系统的元数据
Secondary NameNode:
定时与NameNode进行同步(定期合并文件系统镜像和编辑日&#x#x5FD7;,然后把合并后的传给NameNode,替换其镜像,并清空编辑日志,类似于CheckPoint机制),但NameNode失效后仍需要手工将其设置成主机——namenode的冷备份
关于这点,可以参考:http://blog.csdn.net/scgaliguodong123_/article/details/46335427
DataNode:
负责管理用户的文件数据块
文件会按照固定的大小(blocksize)切成若干块(由上传的客户端进行切块处理,这样不大于128M切块大小的实际是多少就是多少)后分布式存储在若干台datanode上
Datanode会定期向Namenode汇报自身所保存的文件block信息,而namenode则会负责保持文件的副本数量
详细角色信息,参考:https://www.w3cschool.cn/hadoop/xvmi1hd6.html
漫画式的讲解,参考:https://www.cnblogs.com/raphael5200/p/5497218.html
二、读写数据流程
简要的说明参考上文漫画式讲解处
专业深入讲解,参考:https://www.cnblogs.com/codeOfLife/p/5375120.html
1.写数据流程
、根namenode通信请求上传文件,namenode检查目标文件是否已存在,父目录是否存在
、namenode返回是否可以上传
、client请求第一个 block该传输到哪些datanode服务器上
、namenode返回3个datanode服务器ABC
、client请求3台dn中的一台A上传数据(本质上是一个RPC调用,建立pipeline),A收到请求会继续调用B,然后B调用C,将真个pipeline建立完成,逐级返回客户端
、client开始往A上传第一个block(先从磁盘读取数据放到一个本地内存缓存),以packet为单位,A收到一个packet就会传给B,B传给C;A每传一个packet会放入一个应答队列等待应答
、当一个block传输完成之后,client再次请求namenode上传第二个block的服务器。
图解请参考上文
注意:HDFS只允许修改文件名/文件追加等,无法直接修改原来的文件!
2.读数据流程
、跟namenode通信查询元数据,找到文件块所在的datanode服务器
、挑选一台datanode(就近原则,然后随机)服务器,请求建立socket流
、datanode开始发送数据(从磁盘里面读取数据放入流,以packet为单位来做校验)
、客户端以packet为单位接收,现在本地缓存,然后写入目标文件
三、HDFS元数据管理与解析
1.元数据管理原理
元数据分类:
- 第一类是文件和目录自身的属性信息,例如文件名、目录名、父目录信息、文件大小、创建时间、修改时间等。
- 第二类记录文件内容存储相关信息,例如文件块情况、副本个数、每个副本所在的Data Node 信息等。
- 第三类用来记录HDFS中所有Data Node信息,用于Data Node管理。
存储机制:
A、内存中有一份完整的元数据(内存meta data)
B、磁盘有一个“准完整”的元数据镜像(fsimage)文件(在namenode的工作目录中),整个运行过程中,fsimage是不会改变的!editslog的更新会同步到内存
C、用于衔接内存metadata和持久化元数据镜像fsimage之间的操作日志(edits文件)注:当客户端对hdfs中的文件进行新增或者修改操作,操作记录首先被记入edits日志文件中,当客户端操作成功后,相应的元数据会更新到内存meta.data中
更多参考:http://blog.csdn.net/xiaming564/article/details/23165253
http://blog.csdn.net/chenkfkevin/article/details/61196409
这里就能很清楚的知道secondary namenode的工作原理了!
关于元数据的存取流程与分析,参考网友的白话讲解:http://blog.csdn.net/lepton126/article/details/53183037
2.修改工作目录
之前我们配置过hadoop.tmp.dir来设置临时目录,这里可以通过以下参数设置HDFS工作目录
配置文件:hdfs-site.xml
参数名:dfs.namenode.name.dir
格式:file://${hadoop.tmp.dir}/dfs/name
说明:Determines where on the local filesystem the DFS name node should store the name table(fsimage).
If this is a comma-delimited list of directories then the name table is replicated in all of the directories, for redundancy.
示例:
<property>
<name>dfs.namenode.name.dir</name>
<value>/home/hadoop/name1,/home/hadoop/name2</value>
</property>
//当然,dfs.datanode.data.dir也是可以配置的,这样重新格式化后就可以重新使用工作目录了!点击查看对比
注:如果还在使用dfs.name.dir/dfs.data.dir,请查看官网配置的deprecated properties
3.元数据各目录解析
详细解析,参考:https://www.iteblog.com/archives/967.html
http://blog.csdn.net/opensure/article/details/51452058
四、HDFS的Java-API操作
完整API参考官网:http://hadoop.apache.org/docs/current/api/
1.基本的增删改查API:
package com.hdfs.demo; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.Before;
import org.junit.Test; import java.net.URI; /**
* HDFS客户端demo
*
* @author zcc ON 2018/1/28
**/
public class HdfsClientDemo {
FileSystem fs = null;
@Before
public void init() throws Exception{
// 如配置完环境变量,下行可省略
// System.setProperty("hadoop.home.dir", "F:\\work\\hadoop-2.6.4");
Configuration conf = new Configuration();
// 配置文件系统(注意hosts的配置)
// conf.set("fs.defaultFS","hdfs://mini1:9000");
// 拿到一个操作的客户端实例对象(此处使用3个参数则上一行省略)
fs = FileSystem.get(new URI("hdfs://mini1:9000"),conf,"hadoop");
}
@Test
public void testUpload() throws Exception{
// 就对应get的别名
fs.copyFromLocalFile(new Path("F:/c.log"),new Path("/c.log.copy"));
// 关闭
fs.close();
}
@Test
public void testDelete() throws Exception{
// 第一个是Path,第二个为是否递归删除
boolean b = fs.delete(new Path("/c.log.copy"), true);
System.out.println("删除状态:" + b);
fs.close();
}
@Test
public void testList() throws Exception{
/*
一般而言,大数据方面使用迭代器场景居多,因为Iterator它本身并不存数据(可以查看源码)
它只是提供了几个简单的方法帮你去取数据,而使用ArrayList则是直接把数据拿过来了,大数据
量下不适合
*/
RemoteIterator<LocatedFileStatus> iterator = fs.listFiles(new Path("/"), true);
while (iterator.hasNext()) {
LocatedFileStatus next = iterator.next();
System.out.println("Path:" + next.getPath());
System.out.println("BlockSize" + next.getBlockSize());
System.out.println("Name:" + next.getPath().getName());
} // Path:hdfs://mini1:9000/1.txt
// BlockSize134217728
// Name:1.txt
fs.close();
} /**
* 既可以遍历文件,又可以遍历文件夹
* @throws Exception
*/
@Test
public void testList2() throws Exception{
FileStatus[] files = fs.listStatus(new Path("/"));
for (FileStatus file : files) {
System.out.println(file.getPath().getName());
if (file.isFile()) {
System.out.println("it is a file");
}
}
}
}
这里引入Java中迭代器的机制浅谈,供参考:https://www.cnblogs.com/hasse/p/5024193.html
更多实例,参考:http://blog.csdn.net/litianxiang_kaola/article/details/70983904
2.流操作API
相对那些封装好的方法而言的更底层一些的操作方式上层那些mapreduce spark等运算框架,去hdfs中获取数据的时候,就是调的这种底层的api
package com.hdfs.stream; import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.Before;
import org.junit.Test; import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI; /**
* HDFS的流API操作
*
* @author zcc ON 2018/1/30
**/
public class HdfsStreamAccess {
FileSystem fs = null;
@Before
public void init() throws Exception{
Configuration conf = new Configuration();
fs = FileSystem.get(new URI("hdfs://mini1:9000"),conf,"hadoop");
} /**
* 通过流的操作,就可以为上层MR程序提供服务,例如跑任务只需要跑60M,这样就不用通过
* 之前的直接得到一整个文件的复杂处理
* 而建立文件夹等直接通过简单API即可!
* @throws Exception
*/
@Test
public void testUpload() throws Exception{
// 输出到HDFS
FSDataOutputStream outputStream = fs.create(new Path("/angle"), true);
// 本地输入流
FileInputStream inputStream = new FileInputStream("F:\\c.log");
// 通过IOUtils进行拷贝(使用更加通用的IOUtils)
IOUtils.copy(inputStream, outputStream);
}
@Test
public void testDownload() throws Exception{
FSDataInputStream inputStream = fs.open(new Path("/angle"));
FileOutputStream outputStream = new FileOutputStream("F:\\c-download.log");
IOUtils.copy(inputStream, outputStream);
} /**
* 指定随机长度读取
*/
@Test
public void testRandomAccess() throws Exception{
FSDataInputStream inputStream = fs.open(new Path("/angle"));
inputStream.seek(12);
FileOutputStream outputStream = new FileOutputStream("F:\\c-random.log");
// 从12字节读到末尾(也可以通过while结合自定义的count等来控制读文件的大小)
// 后续会避免读取读到单词一半这样的问题
// IOUtils.copy(inputStream, outputStream);
IOUtils.copyLarge(inputStream, outputStream, 12, 100);
} /**
* 以下模拟实现:获取一个文件的所有block位置信息,然后读取指定block中的内容
* @throws IllegalArgumentException
* @throws IOException
*/
@Test
public void testCat() throws IllegalArgumentException, IOException { FSDataInputStream in = fs.open(new Path("/weblog/input/access.log.10"));
//拿到文件信息
FileStatus[] listStatus = fs.listStatus(new Path("/weblog/input/access.log.10"));
//获取这个文件的所有block的信息
BlockLocation[] fileBlockLocations = fs.getFileBlockLocations(listStatus[0], 0L, listStatus[0].getLen());
//第一个block的长度
long length = fileBlockLocations[0].getLength();
//第一个block的起始偏移量
long offset = fileBlockLocations[0].getOffset(); System.out.println(length);
System.out.println(offset); //获取第一个block写入输出流
// IOUtils.copyBytes(in, System.out, (int)length);
byte[] b = new byte[4096]; FileOutputStream os = new FileOutputStream(new File("d:/block0"));
while(in.read(offset, b, 0, 4096)!=-1){
os.write(b);
offset += 4096;
if(offset>=length) return;
};
os.flush();
os.close();
in.close();
}
}
五、案例:shell脚本日志采集
采用shell编写的脚本如下:
#!/bin/bash #set java env
export JAVA_HOME=/home/hadoop/app/jdk1..0_51
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH #set hadoop env
export HADOOP_HOME=/home/hadoop/app/hadoop-2.6.
export PATH=${HADOOP_HOME}/bin:${HADOOP_HOME}/sbin:$PATH #版本1的问题:
#虽然上传到Hadoop集群上了,但是原始文件还在。如何处理?
#日志文件的名称都是xxxx.log1,再次上传文件时,因为hdfs上已经存在了,会报错。如何处理? #如何解决版本1的问题
# 、先将需要上传的文件移动到待上传目录
# 、在讲文件移动到待上传目录时,将文件按照一定的格式重名名
# /export/software/hadoop.log1 /export/data/click_log/xxxxx_click_log_{date} #日志文件存放的目录
log_src_dir=/home/hadoop/logs/log/ #待上传文件存放的目录
log_toupload_dir=/home/hadoop/logs/toupload/ #日志文件上传到hdfs的根路径
hdfs_root_dir=/data/clickLog// #打印环境变量信息
echo "envs: hadoop_home: $HADOOP_HOME" #读取日志文件的目录,判断是否有需要上传的文件
echo "log_src_dir:"$log_src_dir
ls $log_src_dir | while read fileName
do
if [[ "$fileName" == access.log.* ]]; then
# if [ "access.log" = "$fileName" ];then
date=`date +%Y_%m_%d_%H_%M_%S`
#将文件移动到待上传目录并重命名
#打印信息
echo "moving $log_src_dir$fileName to $log_toupload_dir"xxxxx_click_log_$fileName"$date"
mv $log_src_dir$fileName $log_toupload_dir"xxxxx_click_log_$fileName"$date
#将待上传的文件path写入一个列表文件willDoing
echo $log_toupload_dir"xxxxx_click_log_$fileName"$date >> $log_toupload_dir"willDoing."$date
fi done
#找到列表文件willDoing
ls $log_toupload_dir | grep will |grep -v "_COPY_" | grep -v "_DONE_" | while read line
do
#打印信息
echo "toupload is in file:"$line
#将待上传文件列表willDoing改名为willDoing_COPY_
mv $log_toupload_dir$line $log_toupload_dir$line"_COPY_"
#读列表文件willDoing_COPY_的内容(一个一个的待上传文件名) ,此处的line 就是列表中的一个待上传文件的path
cat $log_toupload_dir$line"_COPY_" |while read line
do
#打印信息
echo "puting...$line to hdfs path.....$hdfs_root_dir"
hadoop fs -put $line $hdfs_root_dir
done
mv $log_toupload_dir$line"_COPY_" $log_toupload_dir$line"_DONE_"
done
脚本文件
加入定时任务调度,参考大数据之Linux基础
大数据入门第六天——HDFS详解的更多相关文章
- hadoop大数据基础框架技术详解
一.什么是大数据 进入本世纪以来,尤其是2010年之后,随着互联网特别是移动互联网的发展,数据的增长呈爆炸趋势,已经很难估计全世界的电子设备中存储的数据到底有多少,描述数据系统的数据量的计量单位从MB ...
- 大数据平台Lambda架构详解
Lambda架构由Storm的作者Nathan Marz提出.旨在设计出一个能满足.实时大数据系统关键特性的架构,具有高容错.低延时和可扩展等特. Lambda架构整合离线计算和实时计算,融合不可变( ...
- CentOS6.5下如何正确下载、安装Intellij IDEA、Scala、Scala-intellij-bin插件、Scala IDE for Eclipse助推大数据开发(图文详解)
不多说,直接上干货! 第一步:卸载CentOS中自带openjdk Centos 6.5下的OPENJDK卸载和SUN的JDK安装.环境变量配置 第二步:安装Intellij IDEA 若是3节点 ...
- 30个mysql千万级大数据SQL查询优化技巧详解
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...
- 【大数据系列】MapReduce详解
MapReduce是hadoop中的一个计算框架,用来处理大数据.所谓大数据处理,即以价值为导向,对大数据加工,挖掘和优化等各种处理. MapReduce擅长处理大数据,这是由MapReduce的设计 ...
- 大数据之ETL设计详解
ETL是BI项目最重要的一个环节,通常情况下ETL会花掉整个项目的1/3的时间,ETL设计的好坏直接关接到BI项目的成败.ETL也是一个长期的过程,只有不断的发现问题并解决问题,才能使ETL运行效率更 ...
- 【大数据笔记】白话详解Zookeeper的一致性
下面内容主要摘抄于<<Hadoop实战>>,红色高亮部分是本人添加的白话注释. Zookeeper 是一种高性能.可扩展的服务. Zookeeper 的读写速度非常快,并且读的 ...
- 大数据入门基础系列之Hadoop1.X、Hadoop2.X和Hadoop3.X的多维度区别详解(博主推荐)
不多说,直接上干货! 在前面的博文里,我已经介绍了 大数据入门基础系列之Linux操作系统简介与选择 大数据入门基础系列之虚拟机的下载.安装详解 大数据入门基础系列之Linux的安装详解 大数据入门基 ...
- HDFS详解
HDFS详解大纲 Hadoop HDFS 分布式文件系统DFS简介 HDFS的系统组成介绍 HDFS的组成部分详解 副本存放策略及路由规则 命令行接口 Java接口 客户端与HDFS的数据流讲解 目标 ...
随机推荐
- JSP九大内置对象与Servlet的对应关系
JSP对象 Servlet中怎样获得 request service方法中的request参数 response service方法中的res ...
- Oracle EBS AP 供应商取值
SELECT --nvl(substr(po.vendor_name,1,instr(po.vendor_name,',',1)-1),po.vendor_name) vendor_name, po. ...
- idea 版本控制忽略文件、文件夹设置
setting 或者底部的 设置 忽略某个文件 后面选择框可以去选择 忽略某个文件夹 后面选择框可以去选择 忽略某种文件 后面输入填写如: *.txt
- Windows+Git+TortoiseGit+COPSSH 安装教程及问题收集
准备工作: 1. git-1.8.1.2-preview20130201.exe 下载地址: https://code.google.com/p/msysgit/downloads/list 2. C ...
- 发布MVCIIS报错未能加载文件或程序
未能加载文件或程序集“System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e3 ...
- ASP.NET MVC 5搭建自己的视图基架 (CodeTemplate)
我们知道,在MVC项目中添加视图时,在添加面板有模板可以选择,这里会有人疑问,这个模板位于哪里?我可以搭建自己的基架吗? 首先回答第二个问题,答案是当然可以 我这里使用的是Visual Studio ...
- C++:sprintf()的用法(转)
转:http://blog.csdn.net/masikkk/article/details/5634886 更多:http://blog.csdn.net/zjuwispersure/article ...
- C# 词法分析器(一)词法分析介绍
系列导航 (一)词法分析介绍 (二)输入缓冲和代码定位 (三)正则表达式 (四)构造 NFA (五)转换 DFA (六)构造词法分析器 (七)总结 虽然文章的标题是词法分析,但首先还是要从编译原理说开 ...
- python第五课——流程控制语句
流程控制语句: 分类: 1).顺序结构 2).判断结构解析:如果...否则... 3).循环结构 1.判断结构: 格式分类:三种格式 格式一: ① if 条件表达式: 语句块 ② 执行流程: 计算机会 ...
- linux中Vi编辑器使用
1.如需要编辑aaa.txt文件: vi aaa.txt 就可以进入到 aaa.txt文件中, 输入 i 进入到编辑模式, 按 Esc 退出编辑模式 , :wq 保存退出编辑模式 ...