Hadoop学习笔记(六)——分布式文件系统

一 简介

HDFS,它是一个文件系统,用于存储文件,通过目录树来定位文件:其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
HDFS的设计适合一次写入,多次读出的场景,且不支持文件的修改。适合用来做数据分析,并不适合用来做网盘应用。

二 体系结构和基本概念

1 特点:

  • 可拓展
  • 容错:有备份
  • 高可用:对于多个Master
  • 高吞吐:多台机器并发读

2 设计分布式文件系统思路

1 系统架构

HDFS
  • 有多台Masters,其中一台为Active状态,其他Standby
  • 多个Slaves同时向Active的Master发送Heartbeat
  • 若Active的Master出现宕机,则转向其他Master

2 日志存取

存log.png
  • Client有200M的log文件需要存储,首先与Master进行RPC通通信
  • Master将有剩余空间的Slave传给Client
  • Client将log文件传给该Slave


    读取
  • 当另一台Clinet需要读取时,同理通过Master

但是以上存在问题,没有副本。当该Slave宕机,数据无法读取。
因此存数据时,需要同时复制给其他Slaves。(通过Buket复制,而不是全部写完再复制)

三 HDFS Shell

查看HDFS Shell命令

在hadoop文件夹下的bin中执行

./hdfs dfs

命令

[-appendToFile ... ] #追加内容
[-cat [-ignoreCrc] ...]#查看内容
[-checksum ...]#查看
[-chgrp [-R] GROUP PATH...]#改变所有组
[-chmod [-R] PATH...]#改变全新
[-chown [-R] [OWNER][:[GROUP]] PATH...]#改变所属用户
[-copyFromLocal [-f] [-p] [-l] [-d] [-t ] ... ]#从本地复制一份上传到HDFS
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] ... ]#吧HDFS考到本地
[-count [-q] [-h] [-v] [-t []] [-u] [-x] [-e] ...]#统计数量
[-cp [-f] [-p | -p[topax]] [-d] ... ]#拷贝
[-createSnapshot []]#创建快照
[-deleteSnapshot ]#删除快照
[-df [-h] [ ...]]#查看磁盘使用情况
[-du [-s] [-h] [-v] [-x] ...]
[-expunge]
[-find ... ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] ... ] #下载
[-getfacl [-R] ]
[-getfattr [-R] {-n name | -d} [-e en] ]
[-getmerge [-nl] [-skip-empty-file] ]
[-head ]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [ ...]]
[-mkdir [-p] ...]
[-moveFromLocal ... ]
[-moveToLocal ]
[-mv ... ]
[-put [-f] [-p] [-l] [-d] ... ] #上传
[-renameSnapshot ]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] ...] #删除
[-rmdir [--ignore-fail-on-non-empty]

...] #删除文件夹
[-setfacl [-R] [{-b|-k} {-m|-x } ]|[--set ]]
[-setfattr {-n name [-v value] | -x name} ]
[-setrep [-R] [-w] ... ]#修改副本数
[-stat [format] ...] #查看文件信息
[-tail [-f] ] #查看末尾
[-test -[defsz] ]
[-text [-ignoreCrc] ...] #查看内容
[-touch [-a] [-m] [-t TIMESTAMP ] [-c] ...]
[-touchz ...]
[-truncate [-w] ...]
[-usage [cmd ...]]

将HDFS加入环境变量

为方便操作,可将hdfs添加到环境变量

  • 进入hadoop目录

vi /etc/profile

  • 添加hadoop目录

export HADDOP_HOME=/bigdata/hadoop-3.2.0

  • 添加path

export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin

查看文件 -ls

查看HDFS下的文件

hdfs dfs -ls /

循环查看目录

hdfs dfs -ls -R

自动读取core-site.xml的信息,得到namenode的位置,不需要指定

查看Linux下的文件

ls

HDFS.png

将文件写入HDFS -put

将文件上传到根目录

hdfs dfs -put 文件名 hdfs://主机名:端口号/

删除文件

hdfs dfs -rm 文件名

文件通过切割上传
BlockSize: 128M


切割上传

该文件174.76M被切成两块
在该目录下可看到文件大小(单位为字节)

/bigdata/tmp/dfs/data/current/BP-595572733-127.0.0.1-1563891152282/current/finalized/subdir0/subdir0

文件大小.png

红框中为切块的大小,相加即为文件大小

从HDFS上下载文件 -get

hdfs dfs -get /文件名 /保存路径/保存文件名

下载多个文件并合并为一个文件

hdfs dfs -getmerge /a.txt /b.txt /home/c.txt
a.txt,b.txt为下载的文件,c.txt为存储的文件名

查看文件 -cat 或 -text

hdfs dfs -cat /文件名(HDFS上的文件)

创建目录 -mkdir

hdfs dfs -mkdir -p log/2019

从HDFS上删除文件 -rm

hdfs dfs -rm /文件名

修改权限 -chmod

hdfs dfs -chmod +w /文件名

计数 -count

hdfs dfs -count /

四 HDFS的Java编程API

将本地文件上传至HDFS

1 创建maven项目

参考 https://blog.csdn.net/qq_35437792/article/details/80631434

2

package myhadoop.cn;

import com.google.common.annotations.VisibleForTesting;
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.junit.Before;
import org.junit.Test;

import java.io.*;

public class HDFSAPI {

    private FileSystem fileSystem = null;

    @Before
    public void init() throws Exception {
        //与HDFS建立连接,知道NameNode地址即可
        Configuration conf = new Configuration();
        System.setProperty("HADOOP_USER_NAME","root");

        conf.set("fs.defaultFS", "hdfs://myhadoop.cn:9000");

        fileSystem = FileSystem.get(conf);
    }

    @Test
    public void testUpload() throws Exception {
        //打开本地文件系统的一个文件作为输入流
        InputStream in = new FileInputStream("C://Users//33598//Desktop//salary.txt");

        //使用hdfs的filesystem打开一个输入流
        OutputStream out = fileSystem.create(new Path("/salary.txt"));

        IOUtils.copyBytes(in, out, 1024, true);
    }

}

踩雷1
报错

参考 https://blog.csdn.net/fragrant_no1/article/details/85842038

踩雷2 could only be written to 0 of the 1 minReplication nodes.

(忘记截图)

https://blog.csdn.net/qfxsxhfy/article/details/80909953

踩雷3 Permission denied: user=hadoop, access=WRITE, inode="/":root:supergroup:drwxr-xr-x

增加环境变量


HADOOP_USER_ NAME

并且重启IDEA

成功!


成功上传salery.txt

创建目录

    @Test
    public void testMkdir() throws Exception {
        fileSystem.mkdirs(new Path("/a/b"));
        fileSystem.close();
    }

删除文件

    @Test
    public void testDel() throws Exception {
        boolean flag = fileSystem.delete(new Path("/a"),false);
        System.out.println(flag);
        fileSystem.close();
    }

delete()函数的第二个参数false为不是递归删除,true为递归删除。
以上代码删除刚才创建的a文件夹。由于a文件夹下还存在b文件夹,当参数为false时报错:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.fs.PathIsNotEmptyDirectoryException): `/a is non empty': Directory is not empty
改为true:
成功!

五 HDFS架构原理

概念

  • 文件切块:打开一个文件进行写入(按字节),当到达切块大小后,将该文件关闭,重新打开另一个文件,继续写入。
  • 副本的存放:当一台机器宕机后用户仍可从其他机器读取数据
  • 元数据:上传的数据,datanode存放真正的数据,namenode存放数据的描述信息(元数据)

重要组件

  • NameNode:负责管理
  • DataNode:存储数据,维护block
  • SecondaryNameNode (伪分布式和非高可用的集群才有):帮助NameNode进行数据的同步(对磁盘和内存进行同步)


    HDFS aRchitecture

    一个Rack1上放多台服务器,block存放在服务器上(绿色方块)。Client上运行程序,读取数据。首先向Namenode读取数据信息(文件存储份数,存储机器),反回元数据,Client根据返回的元数据,从服务器上读取。


    Namenode

    写数据:
  • 将文件切分成blk_1
  • 将数据包blk_1写到h0上,再进行水平复制到h1 h3上
  • 将剩下的数据blk_2写到h0上,复制到h2 h4上

Namenode工作机制

NameNode工作机制
  • 目录树:NameNode记录文件夹的逻辑结构(并非真正的文件夹)
  • fsimage: 磁盘中的数据(某一段时间的信息),最新信息在内存中
  • edits: 标记是否上传成功,元数据每隔一段时间清理标记失败的文件
  • fstime: 新版本不保存在这里,保存在Linux文件系统中

SecondaryNameNode工作机制

SecondaryNameNode工作机子

HA(高可用)


Hadoop1.x数据同步

在新版中并不替换,而是生成新的名字保存。

DataNode工作机制

DataNode工作机制1

DataNode工作机制2

六 Hadoop的RPC通信机制

什么是RPC(Remote Procedure Call):(https://baike.baidu.com/item/%E8%BF%9C%E7%A8%8B%E8%BF%87%E7%A8%8B%E8%B0%83%E7%94%A8/7854346),它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

文件读取过程

例子

服务端

package myhadoop.rpc;

import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;

import java.io.IOException;

public class RPCServer implements RPCService{
    public static void main(String[] args) throws HadoopIllegalArgumentException, IOException {
        Configuration conf = new Configuration();
        RPC.Server server = new RPC.Builder(conf)
                .setProtocol(RPCService.class)
                .setBindAddress("192.168.106.1")
                .setPort(9527)
                .setInstance(new RPCServer())
                .build();
        server.start();
    }

    public String sayHi(String name) {

        return "Hi~" + name;
    }
}

服务端接口

package myhadoop.rpc;

public interface RPCService {

    //客户端指定的versionID,使客户端服务端一致
    public static final long versionID = 10010L;

    public String sayHi(String name);
}

客户端

package myhadoop.rpc;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;

import java.io.IOException;
import java.net.InetSocketAddress;

public class RPCClient {
    public static void main(String[] args) throws IOException {

        Configuration conf = new Configuration();
        //在客户端获取代理对象,有代理对象就可以获取目标对象(RPCServer)的方法
        RPCService proxy = RPC.getProxy(RPCService.class,10010, new InetSocketAddress("192.168.106.1", 9527),conf);
        //
        String result = proxy.sayHi("Tom");
        System.out.println(result);
        RPC.stopProxy(proxy);
    }
}

客户端调用服务器段方法,最终将值返回给客户端

将客户端部署在Linux上

参考 https://blog.csdn.net/branwel/article/details/79918018

你可能感兴趣的:(Hadoop学习笔记(六)——分布式文件系统)