本篇博文主要讲讲HDFS的一些基础性的原理以及应用。
HDFS:Hadoop Distributed File System
HDFS 优点:
高容错性
适合批处理
适合大数据处理
流式文件访问
可构建在廉价机器上
HDFS 缺点:
不适合低延迟数据访问
不太适合小文件存取
不支持并发写入、文件随机修改
仅支持append,保存副本一致性。应用场景:日志,搜索等
HDFS 设计思想
一个文件传到集群中,先把这个文件切分成等大,这里假设是64MB的block。然后以块为单位存到不同的节点上。再用两张表来记录,第一张表记录这个文件由多少block组成,注意这个有先后顺序;第二张表记录每个block在哪些节点上。有了这两张表就很容易追踪这个文件是怎样存的。用户是感知不到文件的切分和拼装。
这种存储方式有两点好处:
①很容易做负载均衡:块是等大的,一个节点最多比其他节点多存一个block。这样每个节点的利用率差不多,不会存在一个节点利用率很大,而另一个节点利用率很小。
②很容易和上层的计算框架做结合:因为文件以多个块分在多个节点上,这里我们假设起五十个任务来并行处理这些文件,那么这个五十个任务并行的跑在存储这些文件的节点上,这样就分摊了每个节点的带宽,充分的并行。
HDFS 架构(master-slave架构)
这里面master就是namenode,slave就是这些datanode。namenode里面存的就是这些block的元信息,就是存储上面的那两张表。namenode有两个,一个是active namenode,一个是standby namenode,一旦active namenode挂了,standby namenode就来接管他。datanode就是用来存储实际的数据块,datanode会定期的向namenode汇报心跳信息,例如不断告诉namenode我还活着,我存储了多少数据块等信息。如果在指定的时间内没有汇报信息,那么namenode会认为这个datanode挂了。
Active Namenode
Standby NameNode(定期同步namnode里面的元信息)
Datanode
Client
访问HDFS
standby namenode不是必须有的,比如在伪分布式中,只有一个节点,那么就没必要再弄个standby namenode。假设在线上环境,有五个节点,那么可以搞个standby namenode,这时候建议每个节点部署datanode,两个节点部署namenode,也就是说有两个节点同时部署namenode和datanode,因为此时只有五个节点,namenode压力不大,如果两个节点仅仅部署namenode资源太浪费。
HA 与 Federation
上图中NN是namenode缩写,DN是datanode缩写,如果此时要管理的文件数非常非常多,此时一对的namenode(active和standby,其实只有一个active namenode在管理,active namenode挂了standby namenode才会管理)就管理不了了,这时可以再搞一对namenode,相当于这对namenode管理这部分文件,另外一对namenode管理另一部分的namenode。然后一对的namenode,里面选谁做active namenode,谁做standby namenode呢?avtive namenode挂了怎么切换到standby namenode呢?这个是有Zookeeper来管理的。有两个namenode时需要Zookeeper做主从的选择以及协调。
NameNode两个重要文件:
元数据镜像:
合并fsimage与edits
HDFS 数据块( block ):
文件被切分成固定大小的数据块
为何数据块如此之大
一个文件存储方式
HDFS 内部机制 — 写流程:
上图中有四个节点,没有部署standby namenode,当客户端向namenode发送一个写的请求信息,namenode收到写请求会查看他内存里面的元信息,看看存不存在这个目录或文件,如果存在就拒绝,如果不存在就接受。客户端首先会把这个文件切成多个block,先写第一个block,写的过程中和namenode通信,领取三个datanode地址,就是要存三个副本的地址。首先客户端会向第一个节点写一个小的package(不是128MB,这里假设是64k),并且会源源不断的写,同时的话,第一个节点会源源不断的把这个小的package发送到其他的副本节点。直到写完一个block。
HDFS 内部机制 — 读流程:
同样客户端向namenode发送一个读的请求,namenode查看内存里信息元,如果文件或目录存在,则可读,然后向其返回三个block地址。客户段根据地址读取文件,然后再读取第二个block直到把文件读完,客户端会把这些block(根据读取的先后顺序)拼装成一个完整的文件,返回给用户。
HDFS 内部机制 — 物理拓扑(也即副本放置策略)
读数据尽量在一个机柜上读,在不同的机柜之间读数据要通过交换机,延迟比较高。
同一个机柜内两个节点同时出故障的概率要比不同机柜内两个节点出故障高很多。因为同一个机柜的两个节点共享一个交换机,物理上许多东西都是共享的,那么同时出故障概率要高。
HDFS 内部机制 — 副本放置策略
一个文件划分成多个block,每个block存多份,如何为每个block选择节点存储这几份数据?
那么可能会有人问,为什么不把三个副本放在三个不同的机架上?这样容错能力岂不是更强?上面已经说了不同机架之间的读写效率低,因为要通过一个交换机,而交换机的速率可能有瓶颈。所以把三个副本放在两个不同的机架上基于性能和可靠性的一个折中。
HDFS 内部机制 — 可靠性策略
文件完整性
Heartbeat
元数据信息
HDFS 访问方方式:
HDFS Shell 命令
将本地文件上传到HDFS上
hdfs dfs -put /local/data /hdfs/data
删除文件/目录
hdfs dfs -rm /hdfs/data
创建目录
hdfs dfs ‐mkdir /hdfs/data
HDFS Shell 命令 — 管理命令
HDFS Shell 命令 — 管理脚本:
在sbin目录下
单独启动某个服务:
HDFS Shell 命令 — 文文件管理命令 fsck:
HDFS Shell 命令 — 数据均衡器 balancer:
数据块重分布
start-balancer.sh -threshold < percentage of disk capacity >
percentage of disk capacity(当节点之间负载不均衡时,比如新买了几台电脑,把负载很高的节点block搬运到其他节点)
HDFS达到平衡状态的磁盘使用率偏差值
值越低各节点越平衡,但消耗时间也更长
HDFS Shell 命令 — 设置目目录份额:
限制一个目录最多使用磁盘空间
hadoop dfsadmin -setSpaceQuota 1t /user/username 这个目录下最多只能使用1t空间
限制一个目录包含的最多子目录和文件数目
hadoop dfsadmin -setQuota 10000 /user/username
HDFS Shell 命令 — 增加 / 移除节点:
加入新的datanode
移除旧datanode
HDFS Java API 介绍
Configuration类:该类的对象封装了配置信息,这些配置信息来自core-*.xml;
FileSystem类:文件系统类,可使用该类的方法对文件/目录进行操作。一般通过FileSystem的静态方法get获得一个文件系统对象;
FSDataInputStream和FSDataOutputStream类:HDFS中的输入输出流。分别通过FileSystem的open方法和create方法获得。
以上类均来自java包:org.apache.hadoop.fs
HDFS Java 程序举例
将本地文件拷贝到HDFS上
Configuration config = new Configuration();//创建一个配置文件,从环境变量里读取hdfs-site.xml来获取hdfs相关配置,如果没有会使用默认的,就是本地的hdfs配置。
FileSystem hdfs = FileSystem.get(config);//获取句柄
//创建两个文件目录
Path srcPath = new Path(srcFile);
Path dstPath = new Path(dstFile);
hdfs.copyFromLocalFile(srcPath, dstPath);// 调用hdfs把新创建的两个文件拷贝过去。
创建HDFS文件
//byte[] buff – 文件内容
Configuration config = new Configuration();
FileSystem hdfs = FileSystem.get(config);
Path path = new Path(fileName);
FSDataOutputStream outputStream = hdfs.create(path);
outputStream.write(buff, 0, buff.length);
关键操作步骤:
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-commonartifactId>
<version>2.7.3version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-hdfsartifactId>
<version>2.7.3version>
dependency>
<dependency>
<groupId>org.apache.hadoopgroupId>
<artifactId>hadoop-clientartifactId>
<version>2.7.3version>
dependency>
然后进入这个maven项目目录内使用命令:mvn clean install,下载依赖。
5.在src/main/java目录下创建一个App.java文件:
package my.hadoopstudy;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
public class App {
public static void testMkdirPath(String path) throws Exception {
FileSystem fs = null;
try {
System.out.println("Creating " + path + " on hdfs...");
Configuration conf = new Configuration();
// First create a new directory with mkdirs
Path myPath = new Path(path);
fs = myPath.getFileSystem(conf);
fs.mkdirs(myPath);
System.out.println("Create " + path + " on hdfs successfully.");
} catch (Exception e) {
System.out.println("Exception:" + e);
} finally {
if(fs != null)
fs.close();
}
}
public static void testDeletePath(String path) throws Exception {
FileSystem fs = null;
try {
System.out.println("Deleting " + path + " on hdfs...");
Configuration conf = new Configuration();
Path myPath = new Path(path);
fs = myPath.getFileSystem(conf);
fs.delete(myPath, true);
System.out.println("Deleting " + path + " on hdfs successfully.");
} catch (Exception e) {
System.out.println("Exception:" + e);
} finally {
if(fs != null)
fs.close();
}
}
public static void main(String[] args) {
try {
//String path = "hdfs:namenodehost:8020/test/mkdirs-test";
String path = "/test/mkdirs-test";
testMkdirPath(path);
//testDeletePath(path);
} catch (Exception e) {
System.out.println("Exceptions:" + e);
}
System.out.println("timestamp:" + System.currentTimeMillis());
}
}
上面代码中就是用在本地对HDFS进行文件操作,比如创建文件,删除文件,写文件等操作等。
6.如果在eclipse里面直接run as java Application,那么是在本地生成这个文件。
7.如果想在hadoop节点上生成文件,那么可以把这个项目打成jar包,然后在节点上用命令hadoop jar xx.jar。因为这个时候会把所有的hadoop环境变量放进去运行。
具体操作步骤可参考
使用Maven搭建Hadoop开发环境,
用Maven构建Hadoop项目
win 10 + maven + idea 15 + Hadoop 2.7.3开发环境配置
HDFS 优化小小技巧:原始日日志存储格式选择
文本文件
SequenceFile
HDFS 优化小技巧:小文件优化
合并成大文件
合并成Sequence file
用Hadoop Archive打包
保存到key/value系统中
HBase
TFS(Tao Bao FileSystem)
日志分析系统: 文文件存储模块注意事项
数据分区
年/月/日
数据压缩
较少存储空间
数据存储格式选择
原始日志存储格式选择Sequence file(便于压缩),而不是文本格式
原始用户信息和商品信息可采用列式存储格式(ORC或Parquet)保存
日志分析系统:数据格式选择
日志分析系统:增大“热点文件”的副本数
通过程序API修改
FileSystem fs = FileSystem.get(path, conf);
fs.setReplication(path, (short) 4);//默认是3
通过配置参数修改
在hdfs-site.xml修改dfs.replication: 4,这样的话所有文件的block都是4,故不建议使用。
通过命令行
增加文件的副本数:hadoop dfs -setrep -w 4 /path/to/file // 这里面file是一个文件
递归增加目录下文件的的副本数:hadoop dfs –setrep -R -w 4 /path/to/file // file是一个目录。
日志分析系统:分析冷热数据:
“冷热”数据
冷数据:过去半年内没访问过的数据
冷数据可进行特殊处理,包括高压缩,小文件合并等
找出“冷热”数据
hdfs oiv -i /home/hadoop/data/hdfs/name/current/fsimage_0000000000001619538 -p XML -o fsimage.xml
找出上次访问时间为半年之前的文件:< atime>1475047293212< /atime>
就是利用hdfs里面的命令oiv命令将hdfs里面的一些元信息(故oiv后面要设置一个路径,就是hadoop安装目录里面的配置文件hdfs-site.xml里面配置的dfs.namenode.name.dir对应的value值就是保存元信息的位置信息)拉出来然后保存为xml格式,然后xml文件内有一个atime就是上一次访问的时间。
日志分析系统:处理“冷”数据
高压缩比算法进行压缩
Gzip或bzip2
合并小文件
使用MapReduce实现
异构存储
http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-hdfs/ArchivalStorage.html
每个节点是由多种异构存储介质构成的
可以在datanode节点上配置每个盘的类型,比如是disk类型还是ssd类型。
然后可以使用命令:
hdfs storagepolicies -setStoragePolicy -path < path> -policy < policy>
对指定路径下path的目录指定他的存储策略policy。
比如All_SSD,表示这个目录下文件都采用SSD。