hadoop-hdfs学习2

来源:互联网 发布:淘宝体检中心登陆 编辑:程序博客网 时间:2024/05/18 02:30

HDFS


HDFS特点

  • 硬件故障
  • 流式的数据访问:HDFS设计适合批量处理
  • 大数据集
  • 简单一致性模型
  • 移动计算比移动数据更经济
  • 轻便访问异构的软硬件平台
  • 名字节点和数据节点:HDFS是主从结构的体系
  • 文件名字空间:支持传统的继承式的文件组织,一个用户或一个程序可以创建目录,存储文件到很多目录之中。
  • 数据复制:HDFS能可靠地在集群中的机器之间存储非常大量的文件,它以块序列的形式存储每一个文件。属于文件的块为了故障容错而被复制。
  • 复制的选择:同机架优于跨机架,同机房优于跨机房
  • 安全模式
  • 元数据的持久化:名字节点用事务日志(EditsLog)来持久化每一个对文件系统的元数据的改变。名字节点在本地文件系统中用一个文件来存储这个EditsLog,完整的文件系统名字空间、文件块的映射和文件系统的配置都存在一个叫FsImage的文件中。
  • 通信协议:建立在TCP/IP之上,一个客户央和明确的配置端口的名字节点建立连接之后,它和名字节点的协议是ClientProtocal。数据节点和名字节点之间通信用DatanodeProtocal。RPC抽象地包装 ClientProtocal和DataNodeProtocal。根据设计,名字节点不会发起一个RPC,它只是对数据节点和客户端发起的RPC作出反馈。
  • 鲁棒性:HDFS的主要目标是存在故障的情况下可靠地存储数据。三个普通的故障是名字节点失效、数据节点失效和网络断开。
  • 磁盘故障、心跳和重新复制
  • 集群的重新均衡
  • 数据正确性
  • 元数据磁盘实效
  • 快照:HDFS目前还不支持快照
  • 数据组织:HDFS典型的块大小是64M,一个HDFS文件最多可以切分成128个块,每个块分布在不同的数据节点上。

Hadoop文件系统接口

Java API可以实现与Hadoop文件系统的交互操作。 
- Thrift:提供多种语言接口 
- C语言:libhdfs,开发一般滞后于JavaAPI 
- FUSE:用户空间文件系统 
- WebDAV:基于HTTP1.1的一个通信协议,使应用程序可以直接将文件写到WebServer上,写文件时可以加锁,写完后解锁。 
- HTTP:只读接口用于检索 
- FTP:将任意FTP服务器向外暴露为Hadoop文件系统。

HDFS的WEB服务

参数名称功能描述默认配置文件例子值fs.default.nameNameNode RPC交互端口8020core-site.xmlhdfs://master:8020/dfs.http.addressNameNode Web管理端口50070hdfs-site.xml0.0.0.0:50070dfs.datanode.addressDataNode 控制端口50010hdfs-site.xml0.0.0.0:50010dfs.datanode.ipc.addressDataNode的RPC服务器地址和端口50020hdfs-site.xml0.0.0.0:50020dfs.datanode.http.addressDataNode的HTTP服务器和端口50075hdfs-site.xml0.0.0.0:50075

HDFS架构图

这里写图片描述

机架

一个Block的三个副本通常会保存到两个或两个以上的Rack中。

数据块

默认64M大小。使用fsck命令显示文件系统中各个文件由哪些块构成。

$ haddop fsck / -files -blocks
  • 1
  • 1

元数据节点

元数据节点NameNode是管理者,一个Hadoop集群只有一个NameNode节点,是一个通常在HDFS实例中的单独机器上运行的软件。实际的I/O事务并没有经过NameNode,只有表示DataNode和块的文件映射数据经过NamNode。当外部客户机发送请求要求创建文件时,NameNode会以块标识和该块的第一个副本的DataNode IP地址作为响应。这个NameNode还会通知其它将要接收该块的副本的DataNode。 
NameNode在一个FsImage文件中存储所有关于文件系统名称空间的信息。

NameNode的主要功能: 
- NameNode提供名称查询服务,它是一个Jetty服务器 
- 保存metadata信息,包括:文件owership和permissions;文件包含哪些块; Block保存在哪个Data屡有 
- NameNode的metadata信息在启动后会加载到内存。 
- 设置一个Block 64M,如果上传文件小于该值,仍然会占用一个Blcok的NameNode metadata,但物理存储不会占用64M空间。 
VERSION文件是一个属性文件,保存了HDFS的版本号等信息。 
layoutVersion是一个负整数,保存了HDFS的持续化在硬盘上的数据结构的格式版本号。 
namespaceID是文件系统的唯一标识符,是在文件系统初次格式化时生成的。 
cTime此处为0 
storageType表示此文件夹中保存的是元数据节点的数据结构。 
这里写图片描述

数据节点

DataNode通常以机架的形式组织,机架通过一个交换机将所有系统连接起来。DataNode的主要功能: 
- 保存Block,每个块对应一个元数据信息文件。这个文件主要描述这个块属于哪个文件、第几个块等信息 
- 启动DataNode线程的时候会向NameNode汇报Block信息; 
- 通过向NameNode发送心跳保持与其联系(3秒一次)。如果NameNode10分钟没有收到DataNode的心跳,则认为其lost,并将其上的Block复制到其它DataNode。

辅助元数据节点

SecondaryNameNode,周期性地将EditsLog文件中记对HDFS的操作合并到一个FsImage文件中,然后清空EditsLog文件。这个合并可以减少NameNode重启时间。

名字空间

数据复制

块备份

设置集群Block的备份数: 
修改conf下的hdfs-site.xml

<property>  <name>dfs.replication</name>  <value>1</value>  ...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

其默认值是3.只在文件被 写入dfs时起作用,不会改变之前写入的文件的备份数。需要重启HDFS。

命令:

bin/hadoop fs -setrep -R 1/
  • 1
  • 1

改变整个HDFS的备份数,不需要重启HDFS系统。

机架感知

默认情况下机架感知 没有启用 ,需要手动指定机器属于哪个。 
机架感知配置是在hadoop-site.xml的topology.script.file.name

Hadoop的RPC机制

一般我们所了解的RPC机制都要面对两个问题:1.对象调用方式 2.序列/反序列化机制。 
Hadoop自己实现了简单 RPC组件,依赖地Hadoop Vritable类型的支持。

Hadoop Writable接口要求每个类都要确保将本类的对象正确序列化(writeObject)和反序列化(readObject)。因此,hadoop RPC使用Java动态代理与反射实现对象调用方式。客户端到服务器数据的序列化与反序列化由Hadoop框架或用户自己来实现,也就是数据组装是定制的。

RPC的实现流程

简单来说,Hadoop RPC = 动态代理 + 定制的二进制流。 
这里写图片描述 
远程的对象拥有固定的接口,这个接口用户也是可见的,只是真正的实现(Object)只在服务端。用户如果想使用那个实现的话,他的调用过程如此:先根据那个接口动态代理生成一个代理对象,调用这个代理对象的时候,用户的调用请求被RPC捕捉到,然后包装成调用请求,序列化成数据流发送到服务端;服务端从数据流中解析出调用请求,然后根据用户所希望调用的接口,调用接口真正的实现对象,再把调用结果返回给客户端。

RPC的实体模型

创建代理对象时需要为它关联一个InvocationHandler,对代理对象的每次调用都会进入绑定的InvocationHandler中,RPC就从这里获取用户的请求。

Listener

  监听RPC server的端口,如果客户端有连接请求到达,它就接受连接,然后把连接转发到某个Reader,让Reader去读取那个连接的数据。如果有多个Reader的话,当有新连接过来时,就在这些Reader间顺序分发。这里需要提到的是,Hadoop0.21版本在支持多Reader时有个bug(JIRA),如果有Reader在server运行期没被使用,Server进程不能正常关闭 

Reader

  Reader的职责就是从某个客户端连接中读取数据流,然后把它转化成调用对象(Call),然后放到调用队列(call queue)里 

Handler

  真正做事的实体。它从调用队列中获取调用信息,然后反射调用真正的对象,得到结果,然后再把此次调用放到响应队列(response queue)里    

Responder

  它不断地检查响应队列中是否有调用信息,如果有的话,就把调用的结果返回给客户端。   整个调用流程中与网络有关的地方都是用NIO来处理的。 

文件的读取

文件的写入

文件的一致模型

HDFS的HA机制

Hadoop2.0.0 版本后,提供选择运行在同一集群中的一个热备用的“主/备”两个冗余NameNode,允许在机器宕机或系统维护的时候,快速转移到另一个NameNode。 
一个典型的HA集群,两个单独的机器配置为NameNode,在任何时候,一个NameNode处于活动状态,另一个处于待机状态,活动的NameNode负责处理集群中所有客户的操作,待机时仅仅作为一个slave,保持足够的状态,如果有必要提供一个快速的故障转移。

HA架构

在一个典型的HDFS(HA) 集群中,使用两台单独的机器配置为NameNodes 。在任何时间点,确保NameNodes 中只有一个处于Active 状态,其他的处在Standby 状态。其中ActiveNameNode 负责集群中的所有客户端操作,StandbyNameNode 仅仅充当备机,保证一旦ActiveNameNode 出现问题能够快速切换。 
为了保证Standby 节点与Active 节点的状态保持同步,目前是通过两个节点同时访问一个共享的存储设备( 如NFS) 来实现的,在以后的版本中可能会做进一步的改进。 
当Active 节点的namespace 发生改变时,存储在共享目录中的日志文件也会被修改,Standby 节点监测到日志变化后,将其作用到自身的namespace 。当Active 节点发生故障需要进行切换时,Standby 节点由Standby 状态转换为Active 状态前将会把所有未读日志作用到自身的namespace 以确保自身的namespace 与主节点的namespace 保持一致。 
为了实现快速切换,Standby 节点获取集群的最新文件块信息也是很有必要的。为了实现这一目标,DataNode 需要配置NameNodes 的位置,并同时给他们发送文件块信息以及心跳检测。 
任意时间只有一个ActiveNameNode 对于HDFS(HA) 集群的正常运行至关重要,否则两者的namespace 将不能保持同步,面临数据丢失和其它问题的危险性。为了防止出现这种情况,管理员必须为共享存储配置至少一个安全机制。这种机制应该保证: 在切换期间,如果不能证实当前Active 节点已经改变了状态,那么此机制应切断当前Active 节点对共享存储的访问,这样可以防止在切换期间当前Active 节点继续对namespace 进行修改,确保新的Active 节点能够安全的切换。 
注意: 
此版本只支持手动切换,这意味着集群并不能自动检测Active 节点发生故障。

为什么会有HA机制

  1. 单点故障:
  2. 集群容量和集群性能:当数据量足够大时,NameNode会成为瓶颈。

HDFS的Federation机制

使HDFS支持多个名字空间,并允许在HDFS中同时存在多个NameNode,对HDFS系统中文件的隔离,Federation能够快速解决大部分单NameNode HDFS的问题。

Hadoop文件系统访问

安全模式

主要为了系统启动 时候检查各个DataNode上数据块的有效性,同时根据策略复制或删除部分数据块。运行期通过命令也可以进入安全模式。

$ hdfs dfsadmin -safemode enter      
  • 1
  • 1

参数说明 :

  • enter:进入安全模式
  • leave:强制NameNode离开安全模式
  • get:返回安全模式是否开启的信息
  • wait:等待,一直到安全模式结束

HDFS中的常用到的命令

hadoop新版本将 hadoop命令变更为 hdfs命令。下面命令中hadoop可替换为hdfs。

hadoop fs

hadoop fs -ls /    hadoop fs -lsr /                遍历(已过时)hadoop dfs -ls -R /             遍历hadoop fs -mkdir /user/hadoop   创建文件夹hadoop fs put a.txt /user/hadoop/a.txt 上传文件rm a.txthadoop fs get /user/hadoop/a.txt /user/hadoophadoop fs -cp src dsthadoop fs -mv src dsthadoop fs -cat /user/hadoop/a.txthadoop fs -rm /user/hadoop/a.txthadoop fs -rmr /user/hadoop/a.txthadoop fs -text /user/hadoop/a.txthadoop fs -copyFromLocal localsrc dst 与hadoop fs -put功能类似。hadoop fs -moveFromLocal localsrc dst 将本地文件上传到hdfs,同时删除本地文件。 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

hadoop fsadmin

hadoop dfsadmin -reporthadoop dfsadmin -safemode enter | leave | get | waithadoop dfsadmin -setBalancerBandwidth 1000
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

hadoop fsck

start-balancer.sh

Java 访问 HDFS

实验环境,www.shiyanlou.com

vi /etc/hosts
  • 1
  • 1
192.168.40.13 503691...  hadoop
  • 1
  • 1
cd /app/hadoop-1.1.2/bin./start-all.shcd /app/hadoop-1.1.2/inputtouch quangle.txtvi quangle.txt
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

内容:

On the top of the Crumpetty TreeThe Quangle Wangle sat,But his face you could not see,On account of his Beaver Hat.
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
hadoop fs -mkdir /class4hadoop fs -ls /cd /app/hadoop-1.1.2/inputhadoop fs -copyFromLocal quangle.txt /class4/quangle.txthadoop fs -ls /class4
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

配置本地环境

cd /app/hadoop-1.1.2/confsudo vi hadoop-env.sh
  • 1
  • 2
  • 1
  • 2
export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:/app/hadoop-1.1.2/myclass
  • 1
  • 1

示例:读取文件内容

cd /app/hadoop-1.1.2/myclass/vi FileSystemCat.java
  • 1
  • 2
  • 1
  • 2
package aa;import java.io.InputStream;import java.net.URI;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.*;import org.apache.hadoop.io.IOUtils;public class FileSystemCat {    public static void main(String[] args)throws Exception{        String uri=args[0];        Configuration conf=new Configuration();        FileSystem fs = FileSystem.get(URI.create(uri),conf);        InputStream in = null                try{                    in=fs.open(new Path(uri));                    IOUtils.copyBytes(in,System.out,4096,false);                }        finally{            IOUtils.closeStream(in);        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
javac -classpath ../hadoop-core-1.1.2.jar FileSystemCat.java
  • 1
  • 1

运行:

hadoop FileSystemCat /class4/quangle.txt
  • 1
  • 1

这里写图片描述

写入测试(测试时需要删除中文)

import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.OutputStream;import java.net.URI;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FSDataInputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IOUtils;import org.apache.hadoop.util.Progressable;public class LocalFile2Hdfs {    public static void main(String[] args) throws Exception {        // 获取读取源文件和目标文件位置参数        String local = args[0];        String uri = args[1];        FileInputStream in = null;        OutputStream out = null;        Configuration conf = new Configuration();        try {            // 获取读入文件数据            in = new FileInputStream(new File(local));            // 获取目标文件信息            FileSystem fs = FileSystem.get(URI.create(uri), conf);            out = fs.create(new Path(uri), new Progressable() {                @Override                public void progress() {                    System.out.println("*");                }            });            // 跳过前100个字符            in.skip(100);            byte[] buffer = new byte[20];            // 从101的位置读取20个字符到buffer中            int bytesRead = in.read(buffer);            if (bytesRead >= 0) {                out.write(buffer, 0, bytesRead);            }        } finally {            IOUtils.closeStream(in);            IOUtils.closeStream(out);        }            }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

编译:

javac -classpath ../hadoop-core-1.1.2.jar LocalFile2Hdfs.java
  • 1
  • 1
cd /app/hadoop-1.1.2/inputvi local2hdfs.txt
  • 1
  • 2
  • 1
  • 2

内容:

Washington (CNN) -- Twitter is suing the U.S. government in an effort to loosen restrictions on what the social media giant can say publicly about the national security-related requests it receives for user data.The company filed a lawsuit against the Justice Department on Monday in a federal court in northern California, arguing that its First Amendment rights are being violated by restrictions that forbid the disclosure of how many national security letters and Foreign Intelligence Surveillance Act court orders it receives -- even if that number is zero.Twitter vice president Ben Lee wrote in a blog post that it's suing in an effort to publish the full version of a "transparency report" prepared this year that includes those details.The San Francisco-based firm was unsatisfied with the Justice Department's move in January to allow technological firms to disclose the number of national security-related requests they receive in broad ranges.
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4
cd /app/hadoop-1.1.2/inputhadoop LocalFile2Hdfs local2hdfs.txt /class4/local2hdfs_part.txthadoop fs -cat /class4/local2hdfs_part.txt
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

反向测试示例

从hadoop向本地输出文件。 
代码:

import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.OutputStream;import java.net.URI;import org.apache.hadoop.conf.Configuration;import org.apache.hadoop.fs.FSDataInputStream;import org.apache.hadoop.fs.FileSystem;import org.apache.hadoop.fs.Path;import org.apache.hadoop.io.IOUtils;public class Hdfs2LocalFile {    public static void main(String[] args) throws Exception {        String uri = args[0];        String local = args[1];        FSDataInputStream in = null;        OutputStream out = null;        Configuration conf = new Configuration();        try {            FileSystem fs = FileSystem.get(URI.create(uri), conf);            in = fs.open(new Path(uri));            out = new FileOutputStream(local);            byte[] buffer = new byte[20];            in.skip(100);            int bytesRead = in.read(buffer);            if (bytesRead >= 0) {                out.write(buffer, 0, bytesRead);            }        } finally {            IOUtils.closeStream(in);            IOUtils.closeStream(out);        }        }}
0 0