HDFS快速入门

概述

  • 简介:
    • 源自Google的GFS论文的巨大分布式文件系统
  • 特点:
    1. 扩展性
    2. 容错性
    3. 海量数据存储
  • 优缺点:
    • 优点:
      1. 数据冗余, 硬件容错
      2. 处理流式(一次写入多次读取)的数据访问
      3. 适合存储大文件
      4. 构建在廉价机器上
    • 缺点:
      1. 不满足低延迟的数据访问
      2. 不适合小文件的存储
  • 存储:
    • 将文件切分成指定大小的数据块并以多副本的存储在多个机器上
    • 数据的切分,多副本,容错等操作对用户透明
    NameNode (Filename, numReplicas, block-ids)
    

架构

  • 简介:
    1. 一个Master(NameNode/NN)带N个Slaves(DataNode/DN)
    2. 一个文件会被拆分成多个Block, 默认blocksize:128M

NameNode

  1. 负责客户端请求的响应
  2. 负责元数据(文件的名称、副本系数、Block存放的DN)的管理

DataNode

  1. 存储用户的文件对应的数据块(Block)
  2. 要定期向NN发送心跳信息, 汇报本身及所有的block信息, 健康状况

副本机制

副本存放策略

HDFS文件读写流程

环境搭建

伪分布式

  1. jdk和ssh安装
  2. 免密登录配置:
ssh-keygen -t rsa
cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
ssh localhost
  1. 下载解压
tar -zxvf hadoop-x.x.x-cdhx.x.x -C ~/app
  1. 配置文件修改: hadoop_home/etc/hadoop
    • hadoop-env.sh配置: JAVA_HOME=/usr/lib/jvm/java-x.x
    • core-site.xml配置: 默认目录位于/tmp, 重启后会丢失
    <configuration>
        <property>
            <name>fs.defaultFS</name>
            <!-- 外网访问改成ip -->
            <value>hdfs://localhost:8020</value>
        </property>
        <property>
            <name>hadoop.tmp.dir</name>
            <value>/home/hadoop/app/tmp</value>
        </property>
    </configuration>
    
    • hdfs-site.xml配置:
    <configuration>
        <property>
            <name>dfs.replication</name>
            <value>1</value>
        </property>
    </configuration>
    
    • slavs配置(伪分布式不需要配置)
  2. 启动
# 格式化文件系统, 仅第一次执行, 使用hdfs代替hadoop(depressed))
./bin/hdfs namenode -format
# 启动NameNode, DataNode
./sbin/start-dfs.sh
# 进程验证 DataNode SecondaryNameNode NameNode
jps
# 网页方式验证
curl http://localhost:50070/
# 防火墙添加规则
# vim /etc/sysconfig/iptables
-A INPUT -p tcp -m tcp --dport 50070 -j ACCEPT
  1. 停止: ./sbin/stop-dfs.sh

HDFS Shell操作

  • 配置hadoop/bin的环境变量
# vi ~/.bashrc
export HADOOP_HOME=/opt/apache/hadoop/hadoop-2.6.0-cdh5.7.0
export PATH=$HADOOP_HOME/bin:$PATH

# 使生效 
source ~/.bashrc
  • 查看命令参数: hadoop fs(hdfs dfs)

常用操作

  1. ls:
# 查看根目录
hadoop fs -ls /
# 递归查看
hadoop fs -ls -R /
  1. mkdir
# 根目录创建test目录
hadoop fs -mkdir /test
# 递归创建目录
hadoop fs -mkdir -p /test/a
  1. put: 将本地文件传到hdfs
# 将hello.txt传到hdfs根目录
hadoop fs -put hello.txt /
  1. get
# 将hdfs中的/test/a/h.txt拷贝到本地
hadoop fs -get /test/a/h.txt
  1. rm: 删除文件
# 删除文件
hadoop fs -rm /hello.txt
# 递归删除
hadoop fs -rm -R /test
  1. cat: 查看文件内容
hadoop fs -cat /hello.txt
# 也可以使用-text
hadoop fs -text /hello.txt
  1. copyFromLocal: 从本地拷贝到hdfs
# 将本地hello.txt文件拷贝到hdfs的/test/a目录下, 文件名为h.txt
fs -copyFromLocal hello.txt /test/a/h.txt
  1. test
hdfs dfs -test -[ezd] URI

Java API操作HDFS

  • 默认副本系数为3

步骤

  1. 添加依赖
<properties>
    <cdh.version>2.6.0-cdh5.7.0</cdh.version>
</properties>
<repositories>
    <repository>
        <id>cloudera</id>
        <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
</repositories>
<dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>${cdh.version}</version>
</dependency>
  1. 创建连接
// 该路径为core-site.xml中配置
public static final String HADOOP_PATH = "hdfs://192.168.33.12:8020";
FileSystem fileSystem = null;
Configuration configuration = null;

configuration = new Configuration();
// 指定用户为hadoop
fileSystem = FileSystem.get(new URI(HADOOP_PATH), configuration, "hadoop");
// 创建文件夹
fileSystem.mkdirs(new Path("/hdfsapi/test"));

//创建文件并写入内容
FSDataOutputStream outputStream = fileSystem.create(new Path("/hdfsapi/test/a.txt"));
outputStream.write("hello hdfs".getBytes());
outputStream.flush();
outputStream.close();

//将内容输出到控制台
FSDataInputStream inputStream = fileSystem.open(new Path("/hdfsapi/test/a.txt"));
IOUtils.copyBytes(inputStream, System.out, 1024);   // IOUtils为hadoop.io包
inputStream.close();

// 重命名
Path srcPath = new Path("/hdfsapi/test/a.txt");
Path dstPath = new Path("/hdfsapi/test/b.txt");
boolean rename = fileSystem.rename(srcPath, dstPath);
System.out.println(rename);

// 本地文件上传到hdfs
Path localPath = new Path("E:\\WorkSpace\\data\\test.txt");
Path hdfsPath = new Path("/hdfsapi/test");
fileSystem.copyFromLocalFile(localPath, hdfsPath);

//带进度的大文件上传
InputStream inputStream = new BufferedInputStream(
        new FileInputStream(new File("E:\\WorkSpace\\Web\\bigFile"))
);

FSDataOutputStream fsDataOutputStream = fileSystem.create(new Path("/hdfsapi/test"), new Progressable() {
    @Override
    public void progress() {
        System.out.println(".");
    }
});
IOUtils.copyBytes(inputStream, fsDataOutputStream, 4096);

// 下载文件
Path localPath = new Path("E:\\WorkSpace\\b.txt");
Path hdfsPath = new Path("/hdfsapi/test/b.txt");
fileSystem.copyToLocalFile(hdfsPath, localPath);

// 列出文件信息
FileStatus[] listStatus = fileSystem.listStatus(new Path("/hdfsapi/test"));
for (FileStatus status : listStatus) {
    String file = status.isDirectory() ? "文件夹" : "文件";
    short replication = status.getReplication();    //副本
    long len = status.getLen(); // 文件大小
    String path = status.getPath().toString();

    System.out.println(file + "\t" + replication + "\t" + len + "\t" + path);
}

//删除文件
fileSystem.delete(new Path("/hdfsapi/test/a.txt"), true);

HDFS文件读写流程

存储数据

  • client(divide into blocks)->NameNode->DataNode

读取数据

  • client从NameNode获取元数据信息
  • client从DataNode请求数据

参考