设为首页 加入收藏

TOP

Hadoop分布式———分布式存储系统HDFS
2019-04-24 00:16:04 】 浏览:51
Tags:Hadoop 分布式 存储 系统 HDFS

Hadoop分布式

将一个庞大的数据或复杂的业务分发到不同的计算机节点或服务器上运行或处理。

  1. Hadoop的思想之源:来自于Google 03年发布3大论文, GFS、mapreduce、 Bigtable ;Dougcutting用Java实现)
  2. 狭义:hadoop1=hdfs1+mr1
    hadoop2=hdfs2+mr2+yarn
  3. hadoop 生态2

分布式文件存储系统HDFS

优缺点

  1. 优点:
    分布式特性:
  • 适合大数据处理:GB 、TB 、甚至PB 级及以上的数据
  • 百万规模以上的文件数量:10K+ 节点。(1万多个节点(服务器))
  • 适合批处理:移动计算而非数据(MR),数据位置暴露给计算框架
    自身特性:
  • 可构建在廉价机器上:
  • 高可靠性:通过多副本提提高
  • 高容错性:数据自动保存多个副本;副本丢失后,自动恢复,提供了恢复机制
  1. 缺点:
  • 低延迟高数据吞吐访问问题
    比如不支持毫秒级
    吞吐量大但有限制于其延迟
  • 小文件存取占用NameNode大量内存(寻道时间超过读取时间(99%))
  • 不支持文件修改:一个文件只能有一个写者(深入)
    仅支持append不支持修改(其实本身是支持的,主要为了空间换时间,节约成本)

HDFS架构图:

namenode和datanode之间有:心跳机制、负载均衡、多副本
1

HDFS 数据存储模型 block

  • 文件被线性切分成固定大小的数据块block
    通过偏移量offset(单位:byte)标记
    默认数据块大小为64MB (hadoop1.x),可自定义配置
    若文件大小不到64MB ,则单独存成一个block
  • 一个文件存储方式
    按大小被切分成若干个block ,存储到不同节点上
    默认情况下每个block都有2个副本 共3个副本
    副本数不大于节点数
  • Block大小和副本数通过Client端上传文件时设置,文件上传成功后副本数可以变更,Block Size大小不可变更

nameNode(NN)

  1. NameNode主要功能:
    1、接受客户端的读/写服务。
    2、接受DN汇报的block位置信息。
  2. NameNode保存metadate元信息。
    基于内存存储 :不会和磁盘发生交换;
    metadate元数据信息包括以下:
    文件owership(归属)和permissions(权限)
    文件大小 时间
    Block列表[偏移量]:即一个完整文件有哪些block(b0+b1+b2+…=file)
    位置信息=Block每个副本保存在哪个DataNode中(由DataNode启动时上报给NN 因为会随时变化,不保存在磁盘)–动态的!
  3. NameNode的metadate信息在启动后会加载到内存
    metadata存储到磁盘文件名为”fsimage”的镜像文件
    Block的位置信息不会保存到fsimage
    edits记录对metadata的操作日志

secondaryNameNode(SNN)

  • 它的主要工作是帮助NN合并edits log文件和内存中的元数据,落地到磁盘形成fsimage.减少NN启动时间,它不是NN的备份(但可以做备份)。
  • SNN执行合并时间和机制
    A、根据配置文件设置的时间间隔fs.checkpoint.period 默认3600秒
    B、根据配置文件设置edits log大小 fs.checkpoint.size 规定edits文件的最大值默认是64MB

SecondaryNameNode SNN合并流程

DataNode(DN)

  1. 存储数据(Block)
  2. 启动DN线程的时候会向NameNode汇报block位置信息
  3. 通过向NN发送心跳保持与其联系(3秒一次),如果NN 10分钟没有收到DN的心跳,则认为其已经lost,并copy其上的block到其它DN

Block的副本放置策略

  1. 第一个副本:集群内部提交放置在上传文件的DN;如果是集群外提交,则随机挑选一台磁盘不太满,CPU不太忙的节点。
  2. 第二个副本:放置在于第一个副本不同的机架的节点上。
  3. 第三个副本:与第二个副本相同机架的不同节点。
  4. 更多副本:随机节点

HDFS读文件过程

1

  1. 首先调用FileSystem对象的open方法,其实是一个DistributedFileSystem的实例。
  2. DistributedFileSystem通过rpc协议获得文件的第一批block的locations地址,(同一个block按照重复数会返回多个locations,因为同一文件的block分布式存储在不同节点上),这些locations按照hadoop拓扑结构排序,距离客户端近的排在前面(就近原则选择)。
  3. 前两步会返回一个FSDataInputStream对象,该对象会被封装DFSInputStream对象,DFSInputStream可以方便的管理datanode和namenode数据流。客户端调用read方法,DFSInputStream最会找出离客户端最近的datanode并连接。
  4. 数据从datanode源源不断的流向客户端。
    这些操作对客户端来说是透明的,客户端的角度看来只是读一个持续不断的流。
  5. 如果第一批block都读完了, DFSInputStream就会去namenode拿下一批block的locations,然后继续读,如果所有的块都读完,这时就会关闭掉所有的流。
    如果在读数据的时候, DFSInputStream和datanode的通讯发生异常,就会尝试正在读的block的排序第二近的datanode,并且会记录哪个datanode发生错误,剩余的blocks读的时候就会直接跳过该datanode。 DFSInputStream也会检查block数据校验和,如果发现一个坏的block,就会先报告到namenode节点,然后DFSInputStream在其他的datanode上读该block的镜像。
    该设计就是客户端直接连接datanode来检索数据并且namenode来负责为每一个block提供最优的datanode, namenode仅仅处理block location的请求,这些信息都加载在namenode的内存中,hdfs通过datanode集群可以承受大量客户端的并发访问。
    RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。
    RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

HDFS写文件过程

文件写过程

  1. 客户端通过调用DistributedFileSystem的create方法创建新文件。
  2. DistributedFileSystem通过RPC调用namenode去创建一个没有blocks关联的新文件,创建前, namenode会做各种校验,比如文件是否存在,客户端有无权限去创建等。如果校验通过, namenode就会记录下新文件,否则就会抛出IO异常。
  3. 前两步结束后,会返回FSDataOutputStream的对象,与读文件的时候相似,FSDataOutputStream被封装成DFSOutputStream。
    DFSOutputStream可以协调namenode和datanode。客户端开始写数据到DFSOutputStream,DFSOutputStream会把数据切成一个个小的packet,然后排成队列data quene。
  4. DataStreamer会去处理接受data quene,它先询问namenode这个新的block最适合存储的在哪几个datanode里(比如重复数是3,那么就找到3个最适合的datanode),把他们排成一个管道pipeline输出。DataStreamer把packet按队列输出到管道的第一个datanode中,第一个datanode又把packet输出到第二个datanode中,以此类推。
  5. DFSOutputStream还有一个对列叫ack quene,也是由packet组成等待datanode的收到响应,当pipeline中的datanode都表示已经收到数据的时候,这时ack quene才会把对应的packet包移除掉。 如果在写的过程中某个datanode发生错误,会采取以下几步:
    1) pipeline被关闭掉;
    2)为了防止防止丢包。ack quene里的packet会同步到data quene里;创建新的pipeline管道怼到其他正常DN上
    3)剩下的部分被写到剩下的两个正常的datanode中;
    4)namenode找到另外的datanode去创建这个块的复制。当然,这些操作对客户端来说是无感知的。
  6. 客户端完成写数据后调用close方法关闭写入流。
    PS:注意:客户端执行write操作后,写完的block才是可见的,正在写的block对客户端是不可见的,只有调用sync方法,客户端才确保该文件的写操作已经全部完成,当客户端调用close方法时,会默认调用sync方法。是否需要手动调用取决你根据程序需要在数据健壮性和吞吐率之间的权衡。

HDFS文件权限和安全模式

  1. 文件权限
  • 与Linux文件权限类似 :
    r: read; w:write; x:execute,权限x对于文件忽略,对于文件夹表示是否允许访问其内容
  • 如果Linux系统用户zhangsan使用hadoop命令创建一个文件,那么这个 文件在HDFS中owner就是zhangsan。
  • HDFS的权限目的:阻止好人做错事,而不是阻止坏人做坏事。HDFS 相信,你告诉我你是谁,我就认为你是谁。
  1. 安全模式
  • namenode启动的时候,首先将映像文件(fsimage)载入内存,并执行编辑日志(edits)中的各 项操作。
  • 一旦在内存中成功建立文件系统元数据的映射,则创建一个新的fsimage文件(这个操作不需要SecondaryNameNode)和一个空的编辑日志。
  • 此刻namenode运行在安全模式。即namenode的文件系统对于客服端来说是只读的。(显示 目录,显示文件内容等。写、删除、重命名都会失败)。
  • 在此阶段Namenode收集各个datanode的报告,当数据块达到最小副本数以上时,会被认为是“安全”的, 在一定比例(可设置)的数据块被确定为“安全”后,再过若干时间,安全模式结束
  • 当检测到副本数不足的数据块时,该块会被复制直到达到最小副本数,系统中数据块的位 置并不是由namenode维护的,而是以块列表形式存储在datanode中。
    PS:1

完全分布式搭建

  1. 下载解压缩Hadoop
  2. 配置etc/hadoop/hadoop-env.sh
    export JAVA_HOME=本机JDK路径(echo $JAVA_HOME输出JDK路径)
  3. core-site.xml:
    fs.defaultFS 默认的服务端口NameNode URI
    hadoop.tmp.dir 是hadoop文件系统依赖的基础配置,很多路径都依赖它。如果hdfs-site.xml中不配 置namenode和datanode数据的存放位置,默认就放在这个路径中
<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://node01:9000</value>
    </property>
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/opt/hadoop-2.6.5</value>
    </property>
</configuration>
  1. hdfs-site.xml:
    dfs.datanode.https.address https服务的端口
<configuration>
  <property>
      <name>dfs.replication</name>
      <value>1</value>
 </property>
 <property>
        <name>dfs.namenode.secondary.http-address</name>
        <value>node02:50090</value>
    </property>
<property>
        <name>dfs.namenode.secondary.https-address</name>
        <value>node02:50091</value>
    </property>
</configuration>
  1. Masters: master 可以做主备的SNN
    在/home/hadoop-2.6.5/etc/hadoop/新建masters文件 写上SNN节点名: node02
  2. Slaves: slave 奴隶 苦干;拼命工作
    在/home/hadoop-2.5.1/etc/hadoop/slaves文件中填写DN 节点名:node2 node3 node4 [注意:每行写一个 写成3行]
  3. 最后将配置好的Hadoop通过SCP命令发送都其他节点
    配置Hadoop的环境变量
  4. vi ~/.bash_profile (最好手敲输入 粘贴有时候会出错)
    export HADOOP_HOME/home/hadoop-2.6.5
    export PATH=PATH:PATH:HADOOP_HOME/bin:$HADOOP_HOME/sbin
  5. 记得一定要 source ~/.bash_profile
  6. 回到跟目录下对NN进行格式化 hdfs namenode -format
  7. 启动HDFS: start-dfs.sh
  8. 关闭防火墙:service iptables stop
    在浏览器输入 node1:50070
    到datanode节点验证hadoop.tmp.dir目录
    注意:HDFS集群有clusterID,datanode启动时会和namenode对比clusterID,如果相同,启动成功,如果不同,自杀进程
  9. hdfs dfs 命令:
    hdfs dfs -du [-s][-h]URI[URI …] 显示文件(夹)大小.
    hdfs dfs -mkdir[-p] 创建
    hdfs dfs -rm -r /myhadoop1.0 删除
    hdfs dfs -cp [-f][-p|-p[topax]]URI[URI…]复制文件(夹),可以覆盖,可以保留原有权限信息
    hdfs dfs -count [-q][-h]列出文件夹数量、文件数量、内容大小.
    hdfs dfs -chown [-R][OWNER][:[GROUP]]URI[URI] 修改所有者.
    hdfs dfs -chmod [-R]<MODE[,MODE]…|OCTALMODE>URI[URI …] 修改权限.
    等等。。。。。。
  10. 检测block切分 1.*MB block按1MB切分:
    for i in seq 100000;do echo “hello sxt $i” >> test.txt;done
    hdfs dfs -D dfs.blocksize=1048576 -put test.txt /lm

eclipse插件安装配置

解压eclipse插件压缩包:eclipse-mars
将以下jar包放入eclipse的plugins文件夹中
hadoop-eclipse-plugin-2.6.0.jar
启动eclipse:出现界面如下:
在这里插入图片描述
新建Java项目:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述Eclipse插件安装完后修改windows下的用户名,然后重启:
【注意:改成Windows下用户的用户名root(重启生效)或改Linux文件的用户】
在这里插入图片描述

在这里插入图片描述

My网盘

3-1、代码编写
新建Java项目,导入所需要的jar包
hadoop中的share\hadoop\hdfs
hadoop中的share\hadoop\hdfs\lib
hadoop中的share\hadoop\common
hadoop中的share\hadoop\common\lib
下的jar包。

block底层—offset偏移量来读取字节数组

private static void blk() throws Exception {
Path ifile = new Path("");
FileStatus file = fs.getFileStatus(ifile );
// 获取block的location信息 HDFS分布式文件存储系统根据其偏移量的位置信息来读取其内容

BlockLocation[] blk = fs.getFileBlockLocations(file , 0, file.getLen());
		 		for (BlockLocation bb : blk) { 			
		 		System.out.println(bb); 		
		 		} 		
		 		FSDataInputStream input = fs.open(ifile); 		
		 		System.out.println((char)input.readByte()); 		
		 		System.out.println((char)input.readByte());

	
//		指定从哪个offset的位置偏移量来读
		

    

input.seek(1048576);
    		System.out.println((char)input.readByte());
    		input.seek(1048576);
    		System.out.println((char)input.readByte()); 	
    		}
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Hadoop伪分布式部署之hdfs 下一篇使用JavaAPI操作HDFS创建目录和权..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目