Hadoop基础【HDFS的shell,客户端操作、上传下载流程】

1、常用命令

查看父进程子进程id        ps-ef
查看端口                 netstat -nltp | grep 端口号
如果命令不存在使用        yun provides 命令名 显示它在哪个包中,然后yum install -y 包名
tree 文件名:            以树形结构查看目录
top                     查看系统进程
free -h                 查看剩余内存
df -h                   查看磁盘分区大小
du -h 文件夹名           查看文件夹用了多少
iotop                   查看磁盘读写性能

2、HDFS概论

        什么是HDFS

        HDFS(Hadoop Distributed File System),hadoop分布式文件系统,可以理解为一个巨大的硬盘,适合一次读入,多次读出,不支持文件的随机修改,多用于数据的分析,而不是网盘。

        优点

        高容错性:自动将数据保存多个副本,当副本丢失时,可以自动恢复,通过软件层面(多副本机制)实现高可靠;

        适合处理大数据:数据规模大(甚至是PB级别),文件规模大(能够处理百万规模以上的文件数量)。

        缺点

        不适合低延时的数据访问,做不到毫秒级的存储数据,数据分析一般都是1-2个小时,此时高延时的20-30ms显得不是很重要,所以适合使用HDFS进行大数据的分析;

        无法高效对大量的小文件进行存储,也是大多数存储设备的缺点;

        不支持并发写入,不支持文件随机修改,仅支持数据的追加(append)。

        HDFS架构

        NameNode(nn):master,管理者,相当于一个目录,配置副本策略(副本安排哪几个DataNode上,以及挂了要不要备份),管理数据块的映射信息(一个文件进入HDFS就会被切分成一个一个的数据块,而dn存储的是一个一个的数据块,哪些块存储到哪个dn上,需要由nn负责),存储数据的元数据(文件名,文件目录结构,文件属性)、负责每个文件的块列表和块所在的DataNode,处理客户端的读写请求。

        DataNode(dn):存储实际的数据块,执行对数据块的读写操作,在本地文件系统存储文件块数据,块数据的校验和。

        NameNode(主)与DataNode(从)之间的关系:一主N从。

        Secondary NameNode(2nn):nn在集群中只有一个,如果nn挂了,就会造成文件的查询出现问题,2nn不是nn的热备份,2nn隔一段时间对nn元数据进行备份,是nn的助手

        Client:客户端,文件切分(文件上传HDFS时,Client将文件分成一个一个的数据块,Client负责将这个文件分几块,每块分多大,这些块怎么存储是nn决定),与nn交互(获取文件的位置信息,下载需要知道块在哪里),与dn交互(读取或者写入数据)。

        HDFS块的大小

        寻址时间和传输时间为1:100时效率最高,块不能太小,因为会造成寻址时间过长,不能太大,读块会很困难,默认为128M。每一个块在nn占据一个索引。

3、HDFS的Shell操作

        语法        

hadoop fs或者 hdfs dfs
hadoop fs -help 命令名:查看命令的帮助信息

        hadoop fs -help 命令名:查看命令的帮助信息。 

        本地-->HDFS 上传

put:hadoop fs -put 本地文件名 /上传到哪里
    hadoop fs -put LICENSE.txt /
copyFromLocal:和put基本一样,此命令可以多线程拷贝
moveFromLocal:上传后将原始文件删除
appendToFile:在某一文件后面追加信息
    hadoop fs -appendToFile 追加谁(文件名) 追加到哪个目录下的哪个文件
    或者
    hadoop fs -appendToFile - 追加到哪个目录下的哪个文件   将输入的信息追加到文件中

        HDFS-->HDFS

hadoop fs -cp
hadoop fs -mv
hadoop fs -chown:更改用户名和组
hadoop fs -chmod
hadoop fs -mkdir
hadoop fs -du:显示文件大小
hadoop fs -df 
hadoop fs -cat
hadoop fs -rm

        HDFS-->本地

get:下载
    hadoop fs -get 要下载的文件名 下载到哪个目录

getmerge:合并下载,将HDFS上能够通过通配符匹配的文件一键下载
    hadoop fs -getmerge /*.txt ./1.txt  将HDFS上的txt文件下载到本地的1.txt

copyToLocal:下载,与get完全一样
    hadoop fs -copyLocal 要下载的文件名 下载到哪个目录

        设置HDFS中文件的副本数

hadoop fs -setrep 副本数量 文件名称
    hadoop fs -setrep 10 /LICENSE.txt    

        实际上只有三个副本,在HDFS内部,副本数量不能超过节点数量,创建节点的目的是当某一个节点瘫痪时,可以从其他节点获取到数据。

4、HDFS的客户端操作

        创建maven项目,引入依赖

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-slf4j-impl</artifactId>
            <version>2.12.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client-api</artifactId>
            <version>3.1.3</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client-runtime</artifactId>
            <version>3.1.3</version>
        </dependency>
    </dependencies>

        创建log4j2.xml。目的:把所有info级别的日志打印到控制台上

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" name="XMLConfig">
    <Appenders>
        <!-- 类型名为Console,名称为必须属性 -->
        <Appender type="Console" name="STDOUT">
            <!-- 布局为PatternLayout的方式,
            输出样式为[INFO] [2018-01-22 17:34:01][org.test.Console]I'm here -->
            <Layout type="PatternLayout"
                    pattern="[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c{10}]%m%n" />
        </Appender>

    </Appenders>

    <Loggers>
        <!-- 可加性为false -->
        <Logger name="test" level="info" additivity="false">
            <AppenderRef ref="STDOUT" />
        </Logger>

        <!-- root loggerConfig设置 -->
        <Root level="info">
            <AppenderRef ref="STDOUT" />
        </Root>
    </Loggers>

</Configuration>

        通过客户端上传文件

    @Test
    public void test() throws IOException, InterruptedException {
        //1.新建HDFS对象
        //new Configuration()就是在linux环境下配置的那几个配置文件        
        //Configuration().set可以设置一些参数值,如:副本数,块大小
        //fileSystem 代替了整个HDFS集群
        FileSystem fileSystem = FileSystem.get(URI.create("hdfs://hadoop101:8020"), new Configuration(), "hike");

        //2.操作集群,上传文件
        //第一个Path为需要上传文件的地址,第二个Path为上传到hadoop的哪里
        fileSystem.copyFromLocalFile(
                new Path("C:\\Users\\ASUS\\Pictures\\Camera Roll\\1349658050.jpeg"),
                new Path("/"));

        //3.关闭资源
        fileSystem.close();

        修改一些配置信息

        Configuration configuration = new Configuration();
        configuration.set("dfs.replication","4");       //修改副本数量
        configuration.set("dfs.blocksize","67108864");  //修改块大小


        //1.新建HDFS对象
        FileSystem fileSystem = FileSystem.get(URI.create("hdfs://hadoop101:8020"), configuration, "hike");

        代码的重复性很高,修改以上代码,并完成下载工作。

    FileSystem fileSystem;

    @Before
    public void before() throws IOException, InterruptedException {
        fileSystem = FileSystem.get(URI.create("hdfs://hadoop101:8020"),new Configuration(), "hike");
    }

    @After
    public void after() throws IOException{
        fileSystem.close();
    }

    /**
     * 下载
     */
    @Test
    public void test2() throws IOException {
        fileSystem.copyToLocalFile(new Path("/1349658050.jpeg"),
                new Path("c:/")
        );
    }

        追加内容

    @Test
    public void test3() throws IOException {
        //获取流对象
        FSDataOutputStream append = fileSystem.append(new Path("/1349658050.jpeg"));
        //追加内容
        append.write("testAPI".getBytes());
        //关闭流
        IOUtils.closeStream(append);
    }

        删除文件

    @Test
    public void test4() throws IOException {
        fileSystem.delete(new Path("/LICENSE.txt"),true);
    }

        查看目录下的所有文件

    @Test
    public void test5() throws IOException {
        //想看哪个路径下的文件,获取到的是一个数组
        FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
        for (FileStatus fileStatus : fileStatuses) {
            System.out.println(fileStatus.getPath());
            System.out.println(fileStatus.getOwner());
            System.out.println("--------------------");
        }
    }

        上传一个文件夹  hadoop fs -put logs /

        查看文件夹内部的所有文件

    @Test
    public void test6() throws IOException {
        //获取迭代器
        RemoteIterator<LocatedFileStatus> statusRemoteIterator = fileSystem.listFiles(new Path("/"), true);
        while(statusRemoteIterator.hasNext()){
            LocatedFileStatus fileStatus = statusRemoteIterator.next();
            System.out.println(fileStatus.getPath());
            //获取块信息
            BlockLocation[] blockLocations = fileStatus.getBlockLocations();
            //获取每块的信息
            for (int i = 0; i < blockLocations.length; i++) {
                System.out.println("第" + i + "块");
                String[] hosts = blockLocations[i].getHosts();
                for (String host : hosts) {
                    System.out.print(host + " ");
                }
                System.out.println();
            }
            System.out.println("--------------------------");
        }
    }

        移动文件,在移动的同时可以更改文件名

    @Test
    public void test7() throws IOException {
        fileSystem.rename(
                new Path("/1349658050.jpeg"),       //移动谁
                new Path("/logs/1349658050.jpeg")); //移动到哪里
    }

5、HDFS的读写操作

        上传流程--读

        当一个文件想要上传到Hadoop,需要先经过客户端(Client),Client内部会生成一个FileSystem对象,这个对象代表了整个集群的抽象,之后通过copyFromLocalFile操作。然后Client会向NameNode发送上传文件的申请,当nn接受到申请时,会判断这个申请是否符合规则(不能有同名的文件,上传的文件必须要有写权限),如满足条件,NameNode会向Client响应,Client收到响应信息,Client会在内部开一个FSDataOutputStream流,之后Client向nn申请上传第一个Block,nn会向Client返回一个list,list包含三个dn(包含几个dn根据副本数和机器数量共同决定,为什么选择这三个:第一个会选择距离客户端最近的一个【不是物理距离,而是网络拓扑距离】),第二个、第三个会根据第一个的位置来选择),之后,Client会向dn申请建立一条tcp串行通道(如并行,Client压力大,为提高传输效率),dn1收到请求会依次向后建立tcp通道,dn3会一次向前回应“建立通道成功”的信息,然后,Client会以Packet(64KB)的方式将文件通过建立好的通道传送到节点中,最后,dn现将信息写入到缓存中(写队列),dn1一边往磁盘中写,一边将收到的Packet发送给dn2,以同样方式,dn2将Packet发送给dn3。

        如果在传输过程中,通道意外断开,只要有一个dn接受到了数据,则系统会报告Excrption,但根据HDFS副本自动备份机制,不会对系统造成影响。

        当所有Block上传完成时,关闭FSDataOutputStream流,Client告知nn,文件上传完成,nn更新元数据。

       网络拓扑:为了研究物与物之间的关系,而忽略其实体。在dn内部发起上传,则它自己一定是第一台dn,因为它自己距离自己最近。

        副本分配策略


        For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack. This policy cuts the inter-rack write traffic which generally improves write performance. The chance of rack failure is far less than that of node failure; this policy does not impact data reliability and availability guarantees. However, it does reduce the aggregate network bandwidth used when reading data since a block is placed in only two unique racks rather than three. With this policy, the replicas of a file do not evenly distribute across the racks. One third of replicas are on one node, two thirds of replicas are on one rack, and the other third are evenly distributed across the remaining racks. This policy improves write performance without compromising data reliability or read performance.


        下载流程--写

        当需要下载数据时,Client会建立Distributed FileSystem,之后Client会向nn发送下载文件申请(判断文件是否存在,对文件是否有读权限),满足条件,nn会向Client发出响应。然后Client会开FSDataInputStream输入流,请求下载第一个Block,nn会向Client返回一个list,包含三个dn的信息,Client随机向一个dn建立通道,以Packet传输数据即可,当第一个连接失败,Client就会向第二个dn请求建立连接,之后请求第二个Block的信息,最后nn向Client告知数据传输完毕。
 

                 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OneTenTwo76

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值