大数据-HDFS(五)
目录
本章节主要讲解DataNode的工作机制以及数据存储原理。
每天进步一小点,加油鸭~
DataNode工作机制以及数据存储
DataNode工作机制
- 一个数据块在datanode上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据包括数据块的长度,块数据的校验和,以及时间戳。
- DataNode启动后向namenode注册,通过后,周期性(1小时)的向namenode上报所有的块信息。
- 心跳是每3秒一次,心跳返回结果带有namenode给该datanode的命令如复制块数据到另一台机器,或删除某个数据块。如果超过10分钟没有收到某个datanode的心跳,则认为该节点不可用。
- 集群运行中可以安全加入和退出一些机器。
数据完整性
- 当DataNode读取block的时候,它会计算checksum。
- 如果计算后的checksum,与block创建时值不一样,说明block已经损坏。
- client读取其他DataNode上的block。
- datanode在其文件创建后周期验证checksum。
掉线时限参数设置
DataNode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:timeout = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。而默认的dfs.namenode.heartbeat.recheck-interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。需要注意的是hdfs-site.xml 配置文件中的heartbeat.recheck.interval的单位为毫秒,dfs.heartbeat.interval的单位为秒。
<property>
<name>dfs.namenode.heartbeat.recheck-interval</name>
<value>300000</value>
</property>
<property>
<name> dfs.heartbeat.interval </name>
<value>3</value>
</property>
DataNode的目录结构
和namenode不同的是,datanode的存储目录是初始阶段自动创建的,不需要额外格式化。
在/hlbdx/install/hadoop-2.6.0-cdh5.14.2/hadoopDatas/datanodeDatas/current这个目录下查看版本号
[root@node01 current]# cat VERSION
#Thu Mar 14 07:58:46 CST 2019
storageID=DS-47bcc6d5-c9b7-4c88-9cc8-6154b8a2bf39
clusterID=CID-dac2e9fa-65d2-4963-a7b5-bb4d0280d3f4
cTime=0
datanodeUuid=c44514a0-9ed6-4642-b3a8-5af79f03d7a4
storageType=DATA_NODE
layoutVersion=-56
具体解释
- storageID:存储id号
- clusterID:集群id,全局唯一
- cTime:属性标记了datanode存储系统的创建时间,对于刚刚格式化的存储系统,这个属性为0;但是在文件系统升级之后,该值会更新到新的时间戳。
- datanodeUuid:datanode的唯一识别码
- storageType:存储类型
- layoutVersion:是一个负整数。通常只有HDFS增加新特性时才会更新这个版本号。
DataNode多目录配置
DataNode也可以配置成多个目录,每个目录存储的数据不一样。即:数据不是副本。具体配置如下:
cd /hlbdx/install/hadoop-2.6.0-cdh5.14.2/etc/hadoop
vim hdfs-site.xml
<!-- 定义dataNode数据存储的节点位置,实际工作中,一般先确定磁盘的挂载目录,然后多个目录用,进行分割 -->
<property>
<name>dfs.datanode.data.dir</name>
<value>file:///hlbdx/install/hadoop-2.6.0-cdh5.14.2/hadoopDatas/datanodeDatas</value>
</property>
HDFS 的小文件治理
hdfs大量小文件会引发的问题
- NameNode存储着文件系统的元数据,每个文件、目录、块大概有150字节的元数据;
- 因此文件数量的限制也由NameNode内存大小决定,如果小文件过多则会造成NameNode的压力过大;
- 且HDFS能存储的数据总量也会变小。
HAR文件方案
- 本质启动mr程序,所以需要启动yarn
用法:archive -archiveName <NAME>.har -p <parent path> [-r <replication factor>]<src>* <dest>
第一步:创建归档文件
注意:归档文件一定要保证yarn集群启动
cd /hlbdx/install/hadoop-2.6.0-cdh5.14.2
bin/hadoop archive -archiveName myhar.har -p /user/hadoop /user
第二步:查看归档文件内容
hdfs dfs -lsr /user/myhar.har
hdfs dfs -lsr har:///user/myhar.har
第三步:解压归档文件
hdfs dfs -mkdir -p /user/har
hdfs dfs -cp har:///user/myhar.har/* /user/har/
Sequence Files方案
- SequenceFile文件,主要由一条条record记录组成;每个record是键值对形式的。
- SequenceFile文件可以作为小文件的存储容器;
- 每条record保存一个小文件的内容
- 小文件名作为当前record的键;
- 小文件的内容作为当前record的值;
- 如10000个100KB的小文件,可以编写程序将这些文件放到一个SequenceFile文件。
- 一个SequenceFile是可分割的,所以MapReduce可将文件切分成块,每一块独立操作。
- 具体结构(如下图):
- 一个SequenceFile首先有一个4字节的header(文件版本号)
- 接着是若干record记录
- 记录间会随机的插入一些同步点sync marker,用于方便定位到记录边界
- 不像HAR,SequenceFile支持压缩。记录的结构取决于是否启动压缩
- 支持两类压缩:
- 不压缩NONE,如下图
- 压缩RECORD,如下图
- 压缩BLOCK,①一次性压缩多条记录;②每一个新块Block开始处都需要插入同步点;如下图
- 在大多数情况下,以block(注意:指的是SequenceFile中的block)为单位进行压缩是最好的选择
- 因为一个block包含多条记录,利用record间的相似性进行压缩,压缩效率更高
- 把已有的数据转存为SequenceFile比较慢。比起先写小文件,再将小文件写入SequenceFile,一个更好的选择是直接将数据写入一个SequenceFile文件,省去小文件作为中间媒介.
- 支持两类压缩:
- 向SequenceFile写入数据
package com.kaikeba.hadoop.sequencefile;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.compress.BZip2Codec;
import java.io.IOException;
import java.net.URI;
public class SequenceFileWriteNewVersion {
//模拟数据源
private static final String[] DATA = {
"The Apache Hadoop software library is a framework that allows for the distributed processing of large data sets across clusters of computers using simple programming models.",
"It is designed to scale up from single servers to thousands of machines, each offering local computation and storage.",
"Rather than rely on hardware to deliver high-availability, the library itself is designed to detect and handle failures at the application layer",
"o delivering a highly-available service on top of a cluster of computers, each of which may be prone to failures.",
"Hadoop Common: The common utilities that support the other Hadoop modules."
};
public static void main(String[] args) throws IOException {
//输出路径:要生成的SequenceFile文件名
String uri = "hdfs://node01:8020/writeSequenceFile";
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(URI.create(uri), conf);
//向HDFS上的此SequenceFile文件写数据
Path path = new Path(uri);
//因为SequenceFile每个record是键值对的
//指定key类型
IntWritable key = new IntWritable();
//指定value类型
Text value = new Text();
//
// FileContext fileContext = FileContext.getFileContext(URI.create(uri));
// Class<?> codecClass = Class.forName("org.apache.hadoop.io.compress.SnappyCodec");
// CompressionCodec SnappyCodec = (CompressionCodec)ReflectionUtils.newInstance(codecClass, conf);
// SequenceFile.Metadata metadata = new SequenceFile.Metadata();
// //writer = SequenceFile.createWriter(fs, conf, path, key.getClass(), value.getClass());
// writer = SequenceFile.createWriter(conf, SequenceFile.Writer.file(path), SequenceFile.Writer.keyClass(IntWritable.class),
// SequenceFile.Writer.valueClass(Text.class));
//创建向SequenceFile文件写入数据时的一些选项
//要写入的SequenceFile的路径
SequenceFile.Writer.Option pathOption = SequenceFile.Writer.file(path);
//record的key类型选项
SequenceFile.Writer.Option keyOption = SequenceFile.Writer.keyClass(IntWritable.class);
//record的value类型选项
SequenceFile.Writer.Option valueOption = SequenceFile.Writer.valueClass(Text.class);
//SequenceFile压缩方式:NONE | RECORD | BLOCK三选一
//方案一:RECORD、不指定压缩算法
SequenceFile.Writer.Option compressOption = SequenceFile.Writer.compression(SequenceFile.CompressionType.RECORD);
SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressOption);
//方案二:BLOCK、不指定压缩算法
// SequenceFile.Writer.Option compressOption = SequenceFile.Writer.compression(SequenceFile.CompressionType.BLOCK);
// SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressOption);
//方案三:使用BLOCK、压缩算法BZip2Codec;压缩耗时间
//再加压缩算法
// BZip2Codec codec = new BZip2Codec();
// codec.setConf(conf);
// SequenceFile.Writer.Option compressAlgorithm = SequenceFile.Writer.compression(SequenceFile.CompressionType.RECORD, codec);
// //创建写数据的Writer实例
// SequenceFile.Writer writer = SequenceFile.createWriter(conf, pathOption, keyOption, valueOption, compressAlgorithm);
for (int i = 0; i < 100000; i++) {
//分别设置key、value值
key.set(100 - i);
value.set(DATA[i % DATA.length]);
System.out.printf("[%s]\t%s\t%s\n", writer.getLength(), key, value);
//在SequenceFile末尾追加内容
writer.append(key, value);
}
//关闭流
IOUtils.closeStream(writer);
}
}
- 命令查看SequenceFile内容
hadoop fs -text /writeSequenceFile
- 读取SequenceFile文件
package com.kaikeba.hadoop.sequencefile;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.SequenceFile;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.util.ReflectionUtils;
import java.io.IOException;
public class SequenceFileReadNewVersion {
public static void main(String[] args) throws IOException {
//要读的SequenceFile
String uri = "hdfs://node01:8020/writeSequenceFile";
Configuration conf = new Configuration();
Path path = new Path(uri);
//Reader对象
SequenceFile.Reader reader = null;
try {
//读取SequenceFile的Reader的路径选项
SequenceFile.Reader.Option pathOption = SequenceFile.Reader.file(path);
//实例化Reader对象
reader = new SequenceFile.Reader(conf, pathOption);
//根据反射,求出key类型
Writable key = (Writable)
ReflectionUtils.newInstance(reader.getKeyClass(), conf);
//根据反射,求出value类型
Writable value = (Writable)
ReflectionUtils.newInstance(reader.getValueClass(), conf);
long position = reader.getPosition();
System.out.println(position);
while (reader.next(key, value)) {
String syncSeen = reader.syncSeen() ? "*" : "";
System.out.printf("[%s%s]\t%s\t%s\n", position, syncSeen, key, value);
position = reader.getPosition(); // beginning of next record
}
} finally {
IOUtils.closeStream(reader);
}
}
}
HDFS 的其他功能介绍
多个集群之间的数据拷贝
在我们实际工作当中,极有可能会遇到将测试集群的数据拷贝到生产环境集群,或者将生产环境集群的数据拷贝到测试集群,那么就需要我们在多个集群之间进行数据的远程拷贝,hadoop自带也有命令可以帮我们实现这个功能。
- 本地文件拷贝scp
cd /hlbdx/soft
scp -r jdk-8u141-linux-x64.tar.gz hadoop@node02:/hlbdx/soft
- 集群之间的数据拷贝distcp
cd /hlbdx/install/hadoop-2.6.0-cdh5.14.2/
bin/hadoop distcp hdfs://node01:8020/jdk-8u141-linux-x64.tar.gz hdfs://cluster2:8020/
HDFS 快照 SnapShot 管理
快照顾名思义,就是相当于对我们的hdfs文件系统做一个备份,我们可以通过快照对我们指定的文件夹设置备份,但是添加快照之后,并不会立即复制所有文件,而是指向同一个文件。当写入发生时,才会产生新文件。
快照使用基本语法
1、开启指定目录的快照功能
hdfs dfsadmin -allowSnapshot 路径
2、禁用指定目录的快照功能(默认就是禁用状态)
hdfs dfsadmin -disallowSnapshot 路径
3、给某个路径创建快照snapshot
hdfs dfs -createSnapshot 路径
4、指定快照名称进行创建快照snapshot
hdfs dfs -createSanpshot 路径 名称
5、给快照重新命名
hdfs dfs -renameSnapshot 路径 旧名称 新名称
6、列出当前用户所有可快照目录
hdfs lsSnapshottableDir
7、比较两个快照的目录不同之处
hdfs snapshotDiff 路径1 路径2
8、删除快照snapshot
hdfs dfs -deleteSnapshot <path> <snapshotName>
快照操作实际案例
- 开启与禁用指定目录的快照
[hadoop@node01 hadoop-2.6.0-cdh5.14.2]hdfs dfsadmin -allowSnapshot /user
Allowing snaphot on /user succeeded
[hadoop@node01 hadoop-2.6.0-cdh5.14.2]# hdfs dfsadmin -disallowSnapshot /user
Disallowing snaphot on /user succeeded
- 对指定目录创建快照
注意:创建快照之前,先要允许该目录创建快照
[hadoop@node01 hadoop-2.6.0-cdh5.14.2]# hdfs dfsadmin -allowSnapshot /user
Allowing snaphot on /user succeeded
[hadoop@node01 hadoop-2.6.0-cdh5.14.2]# hdfs dfs -createSnapshot /user
Created snapshot /user/.snapshot/s20190317-210906.549
通过web浏览器访问快照
http://node01:50070/explorer.html#/user/.snapshot/s20190317-210906.549
- 指定名称创建快照
[hadoop@node01 hadoop-2.6.0-cdh5.14.2]# hdfs dfs -createSnapshot /user mysnap1
Created snapshot /user/.snapshot/mysnap1
- 重命名快照
hdfs dfs -renameSnapshot /user mysnap1 mysnap2
- 列出当前用户所有可以快照的目录
hdfs lsSnapshottableDir
- 比较两个快照不同之处
hdfs dfs -createSnapshot /user snap1
hdfs dfs -createSnapshot /user snap2
hdfs snapshotDiff snap1 snap2
- 删除快照
hdfs dfs -deleteSnapshot /user snap1
HDFS 回收站
任何一个文件系统,基本上都会有垃圾桶机制,也就是删除的文件,不会直接彻底清掉,我们一把都是将文件放置到垃圾桶当中去,过一段时间之后,自动清空垃圾桶当中的文件,这样对于文件的安全删除比较有保证,避免我们一些误操作,导致误删除文件或者数据。
- 回收站配置两个参数
默认值fs.trash.interval=0,0表示禁用回收站,可以设置删除文件的存活时间。
默认值fs.trash.checkpoint.interval=0,检查回收站的间隔时间。
要求fs.trash.checkpoint.interval <=fs.trash.interval。
- 启用回收站
修改所有服务器的core-site.xml配置文件
<!-- 开启hdfs的垃圾桶机制,删除掉的数据可以从垃圾桶中回收,单位分钟 -->
<property>
<name>fs.trash.interval</name>
<value>10080</value>
</property>
- 查看回收站
回收站在集群的 /user/hadoop/.Trash/ 路径下
注意:通过javaAPI删除的数据,不会进入回收站,需要调用moveToTrash()才会进入回收站
Trash trash = New Trash(conf);
trash.moveToTrash(path);
- 恢复回收站数据
hdfs dfs -mv trashFileDir hdfsdir
trashFileDir :回收站的文件路径
hdfsdir :将文件移动到hdfs的哪个路径下
- 清空回收站
hdfs dfs -expunge
此博文仅供学习参考,如有错误欢迎指正。
上一篇《大数据-HDFS(六)》
下一篇《大数据-MapReduce(一)》
希望对大数据相关技术感兴趣的友友们关注一下,大家可以一起交流学习哦~