HDFS(Hadoop Distributed File System),它是一个文件系统
HDFS的使用场景:适合一次写入,多次读出的场景。
优点:
缺点:
不适合低延时数据访问,比如毫秒级的存储数据
原因:结点间的数据访问涉及网络io,被带宽和距离,丢包(校验)等因素限制
无法高效的对大量小文件进行存储:
1)小文件的元数据会占用nn大量内存
2)存储的寻址时间>读取时间
不支持并发写入和随机修改:
1)不允许多个线程同时写一个文件–>读读可并发;读写可并发;写(append)写不能并发;不可上传同一路径的同一文件
2)仅支持数据append(追加),不支持文件的随机修改。
随机修改:只能下载后修改再上传
nn(管理者):
dn(执行者):
2nn(辅助nn)
客户端:
发送读写请求,与nn和dn交互,上传(写)之前先将文件切块;
这里客户端不仅指发送指令的linux系统,windows环境下通过设置依赖亦可实现客户端环境,甚至在hdfs里nn的9870端口的web界面操作也可以对HDFS增删查
hdfs中文件在物理上分块(Block)存储:128M是hadoop2.x/3.x版本中的默认值
如何得到块大小:
寻址时间(找到block的时间)约10ms,其为传输时间的1/%时为最佳.
因此传输时间为1s,目前磁盘传输速率普遍100MB/s.所以块大小理论为100MB(按2进制)取整为128M
能否修改块大小且怎么修改合适?
hadoop fs 具体命令 或者 hdfs dfs 具体命令
[atguigu@hadoop102 hadoop-3.1.3]$ bin/hadoop fs
[-appendToFile <localsrc> ... <dst>]//追加一个文件到已经存在的文件末尾
[-cat [-ignoreCrc] <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] <localsrc> ... <dst>]//从本地文件系统中拷贝文件到HDFS路径去,上传的同时可以改名
[-copyToLocal [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]//从HDFS拷贝到本地
[-count [-q] <path> ...]
[-cp [-f] [-p] <src> ... <dst>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] <path> ...]
[-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]//等同于copyToLocal,生产环境更习惯用get,下载也支持改名
[-getmerge [-nl] <src> <localdst>]
[-help [cmd ...]]
[-ls [-d] [-h] [-R] [<path> ...]]
[-mkdir [-p] <path> ...]//在hdfs创建文件夹
[-moveFromLocal <localsrc> ... <dst>]//从本地剪切粘贴到HDFS
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] <localsrc> ... <dst>]//等同于copyFromLocal,生产环境更习惯用put
[-rm [-f] [-r|-R] [-skipTrash] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
<acl_spec> <path>]]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] <file>]
[-test -[defsz] <path>]
[-text [-ignoreCrc] <src> ...]
常用命令包含:
4个上传命令(put,appendToFile),2个下载命令(get)
-du 统计文件夹的大小信息 信息内容:文件大小 大小*副本数 绝对路径
-setrep 设置HDFS中文件的副本数量
这里设置的副本数只是记录在NameNode的元数据中
只有3台设备,最多也就3个副本
还得看DataNode的数量
因此:副本数调整上限和集群扩容情况有关
在准备客户端环境时主要步骤:
//客户端操作HDFS
public class HDFS_Demo {
public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {
//hdfs通信端协议
URI uri = new URI("hdfs://hadoop102:8020");
//配置对象
//加载配置文件,并读
//加载Configuration类时,执行静态代码块,site配置文件覆写default文件,修改了默认值
Configuration conf = new Configuration();
String user = "zxk";//指定用户以使用该用户权限
//如果不传uri参数则获取本地文件系统
//FileSystem fs = FileSystem.get(conf);
//org.apache.hadoop.hdfs.DistributedFileSystem分布式文件系统
//通过反射使用配置文件conf创建文件系统
FileSystem fs = FileSystem.get(uri, conf, user);
fs.mkdirs(new Path("/java"));
fs.close();//关闭客户端
}
}
步骤说明:
提前创建hdfs通信端协议URI(选择8020通信端口,不是9870web端口)
创建配置类(Configuration)对象,加载配置文件,并读
注意:加载Configuration类时,执行静态代码块,site配置文件覆写default文件,修改了默认值
指定用户以使用该用户权限
通过反射使用配置文件conf创建文件系统FileSystem
说明:FileSystem是抽象类,调用构造方法时,传入的参数不同,获得的文件系统不同,具体为:
若传入协议和用户,则获得hdfs分布式文件系统org.apache.hadoop.hdfs.DistributedFileSystem
若只传入配置,则获得windows环境下的本地文件系统
org.apache.hadoop.fs.RawLocalFileSystem
使用API
关闭客户端
前置工作:
将hdfs-site.xml拷贝到项目的resources资源目录下,文件中将副本参数设置为1
编写上传文件的源代码,在创建配置对象后,调用方法修改副本参数为2
configuration.set(“dfs.replication”, “2”);
运行程序结果:hdfs中该文件的副本数为2
总结:
加载配置类时,静态代码块中可以看到,site配置文件中的内容会覆写default配置文件,而客户端代码中参数为最终结果,因此:
参数优先级:1xxx-default.xml服务器的默认配置<2xxx-site.xml服务器的自定义配置<3conf.set()客户端代码中设置的值
以上传为例,步骤:
创建本地系统的流,new FileInputStream/FileOutputStream()
创建hdfs的流,fs.create(new Path())
流的对拷:IOUtils.copyBytes(本地流,hdfs流,conf)
这里传入配置信息目的是提取一个参数–>缓冲大小(4096)
可以直接将conf替换为4096
关流
第1步前置工作:客户端将文件切块Block,创建文件系统,按块逐个上传
第4步:按副本数选择节点数,存储节点选择机制:
节点1:本地,即客户端所在的节点,如果本地负载过高,考虑负载均衡,就近选择第一个节点,另外:如果客户端在集群外,则随机选择第一个节点
节点2:节点1的另一个机架的节点,这样可以保证副本的安全
节点3:节点2所在机架的另一个节点(就近原则)
第5步:使用块传输通道(pipeline)的方式,优势在于可以保持丢包率的一直一致性
第7步:chunksum(4字节的校验和文件)包含:时间戳.元数据等信息
使用同一个交换机的服务器构成机架,多个机架构成集群,多个集群构成数据中心
节点距离:两个节点到达最近的共同祖先的距离总和。
问题1:当客户端不在dn节点上(比如windows),客户端如何确定上传成功?怎么确定是否丢包,以及怎么补救?
确认回收机制:DataStreamer thread将包放进dataQueue发给管道第一个dn,然后从dataQueue移到ackQueue,处理器从dn收取ack.当收到所有节点的对应包的ack,处理器从ackQueue移除相应的包;如果没有收到ack,移除节点 的相关包(事务),重发
问题2:通道pipeline断开,通道上的某些节点不再传输怎么解决?
当dn节点不工作,从ackQueue中移除所有未完成的数据包,先剔除坏掉的节点,建立新的传输通道,开始新的传输工作
说明:
思考:
问题1:通过oiv命令可以查看Fsimage文件中的内容,可以看出,Fsimage中没有记录块所对应DataNode,为什么?
可以看到,文件中记录了块的副本数和块的信息,而在集群启动后,要求DataNode上报数据块信息,并间隔一段时间后再次上报。–>每隔6小时自动上报块的位置,以此还能检验副本是否丢失,即上报的节点个数必须等于副本数–>若不满足副本数,则自动补全机制
问题2:NameNode如何确定下次开机启动的时候合并哪些Edits?
查看元数据存放的目录,看fsimage编号,fsimage_502存在,说明从edits_502以后开始合并
DataNode掉线时限,超时时长的计算公式为:
TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
而默认的dfs.namenode.heartbeat.recheck-interval 大小为300000ms(5分钟),dfs.heartbeat.interval默认为3秒。