HDFS

来源:互联网 发布:无线鼠标品牌知乎 编辑:程序博客网 时间:2024/06/07 22:50

====HDFS================================================

HDFS(Hadoop Distributed File System)
    ** block:(见图)
    ** HDFS把文件划分成block存储在不同节点上
        --默认128M(以前是64M,今后可能会变为256M)
        --dfs.blocksize属性(hdfs-site.xml)
        --该属性应该由文件大小的数值分布来决定,比如80%的文件大小为200M左右,那么该值设定为256M或者128就比较合适
          另如,大都是G级单位大小的文件,该值就应该尽量设置的大些
    ** 如果一个文件大小只有1M,它实际占用的空间也是1M,并非128M,并不会浪费空间
        client(1M) --> namenode(128M逻辑空间) --> datanode(1M实际占用空间)
    ** 遵循:一次写入多次读取

    ** namenode(一台)
        --存储和管理整个文件系统的元数据,目录和文件的元数据会被持久化保存
        --管理文件块和datanode节点的对应关系,该数据保存在内存中,
          记录一个block的信息大约需要0.15K,因此内存的大小,会限制能够存储的文件的总数
        --整个文件系统集群的访问入口,无论读写数据,都要首先访问namenode
          在namenode上找到了对应的datanode,数据读写就不再需要经过namenode
        --监听datanode节点的存活状态
        
    ** datanode(多台)
        --以块(block)的形式存储数据
        --默认每个块有三个副本(包括自身),都是存储在不同的节点
        --向namenode发送心跳信息(默认3s),超时则认为该节点不可用(默认超过10m)
          一旦发生,namenode会复制该节点上的所有block到其他节点
        --向namenode发送存储的所有块的信息
        --真正响应客户端数据读写请求
        
Hadoop默认block副本存放策略(分布式系统默认为3,伪分布式只能是1)
    官方说法:
    ** 第一个副本放在本机架某一个datanode节点
    ** 第二个副本放在同一机架另外一个datanode节点
    ** 第三个副本放在另外一个机架的节点(离架)
    参见:http://hadoop.apache.org/docs/r2.5.2/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html
    (For the common case, when the replication factor is three, HDFS’s placement policy is to put
    one replica on one node in the local rack/机架, another on a different node in the local rack, and
    the last on a different node in a different rack. )

    另外一种说法(Hadoop权威指南):
    ** 第一个副本放在运行客户端程序的节点,如果该节点位于集群外,就随机选择一个节点
    ** 第二个副本放在和第一个副本不同机架的随机节点(离架)
    ** 第三个副本放在与第二副本同一机架的随机节点
    ** 如果需要存放其他副本,则在集群中随机选择其他节点,系统会尽量避免过多副本集中在同一个机架的现象
    -- 其实这两种说法类似,都是一个机架放一个,另外一个机架放两个,其他随机存放
    -- 客户端读取副本: 就近原则

----------------------------------------

NameNode元数据(见图)
    ** fsimage    文件系统镜像
    ** edits     编辑日志
        client操作行为: put、rm...  ==>  记录到edits文件(变化的元数据)
    -- 存放位置由dfs.namenode.name.dir属性(hdfs-site.xml)决定,
       默认为/opt/modules/hadoop-2.5.0/data(即${hadoop.tmp.dir})/dfs/name,可以查看
    -- 类似的,数据存放位置由dfs.datanode.data.dir属性决定,默认为file://${hadoop.tmp.dir}/dfs/data
    -- 回顾:hadoop.tmp.dir在core-site.xml(见上一章)

NameNode启动过程
    ** 加载fsimage,并重新执行edits文件,然后加载到内存
        ** 如果edits文件比较大,合并会非常消耗时间
        ** 解决方法:通过Secondarynamenode合并
    ** 等待dataNode发送block report(块报告)到namenode
        ** 等待过程中,整个HDFS进入安全模式(safemode)

SecondaryNamenode
    ** 辅助Namenode,进行fsiamge和edits文件合并
    ** 避免Namenode下一次重启fsiamge和edits合并时间过长问题
    ** SecondaryNamenode不是namnode的热备

安全模式safemode
    ** 整个文件系统只能读,不能写
    ** 为什么要设计一个安全模式?  保证数据的完整和安全性
    ** 什么条件下我们会进入安全模式
        ** namenode启动过程中
        ** 使用命令手动进入(如:维护阶段)
    ** NameNode重启时,进入安全模式,DataNode需要向NameNode发送块的信息,NameNode只有当整个文件系统中99.9%
      (可以通过dfs.namenode.safemode.threshold-pct属性配置)的块满足最小副本要求,才会自动退出安全模式。
    ** 假设我们设置的副本数(dfs.replication属性)是5,那么在dataNode上,每个块就应该有5个副本存在,假设现在
      只存在3个副本,那么比率就是3/5=0.6,明显小于0.999,因此系统会自动的复制副本到其他dataNode,直到至少
      99.9%的块都有5个副本,才会自动退出安全模式。
    ** 同样,如果系统中有8个副本,超过我们设定的5个副本,那么系统也会删除多余的3个副本。
    
查看安全模式
$ bin/hdfs dfsadmin -safemode get
进入安全模式    
$ bin/hdfs dfsadmin -safemode enter    
离开安全模式    
$ bin/hdfs dfsadmin -safemode leave
    
-----------------------------------
    
HDFS里面常见的SHELL操作命令

$ bin/hdfs dfs
Usage: hadoop fs [generic options]
    [-cat [-ignoreCrc] <src> ...]
    [-chgrp [-R] GROUP PATH...]
    [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
    [-chown [-R] [OWNER][:[GROUP]] PATH...]
    [-cp [-f] [-p | -p[topax]] <src> ... <dst>]
    [-du [-s] [-h] <path> ...]
    [-get [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
    [-ls [-d] [-h] [-R] [<path> ...]]
    [-mkdir [-p] <path> ...]
    [-mv <src> ... <dst>]
    [-put [-f] [-p] <localsrc> ... <dst>]
    [-rm [-f] [-r|-R] [-skipTrash] <src> ...]
    [-text [-ignoreCrc] <src> ...]
    
例子:
上传文件:(测试HDFS)
    #随便创建一个文件a.txt,测试用
    $ vi a.txt
    # 打开网页,Utilities--Browse file system
    $ hdfs dfs -mkdir /input2          #在HDFS上创建文件夹,没有类似-cd进入目录的参数
    $ hdfs dfs -mkdir -p /aaa/bbb/ccc #级联创建目录
    $ hdfs dfs -ls /                  #查看
    $ hdfs dfs -put a.txt /input      #把本地文件拷到HDFS
    $ hdfs dfs -cat /input2/a.txt     #查看文件
    $ hdfs dfs -text /input2/a*          #同上,查看文件内容(可以查看非纯文本格式文件)
    $ hdfs dfs -rm /input2/a.txt      #删除文件
    $ hdfs dfs -rmr /input?           #递归删除文件夹和里面的文件,推荐使用'-rm -r'格式;单字符通配符'?'
    $ hdfs dfs -help

PS:    
# hadoop fs  :可以跨文件系统操作,到了2.x版本,分成hdfs和yarn两个命令
# hadoop dfs :功能有限,不赞成使用(Deprecated)
    $ hadoop fs -mkdir /input2      #用法和'hdfs dfs'类似
    $ hadoop fs -ls /               
    $ hadoop fs -put b.txt /input2
    $ hadoop fs -cat /input2/b.txt
    $ hadoop fs -rm /input2/b.txt
    $ hadoop fs -rmr /input2
    $ hadoop fs -help

----日志-------------------------------------

日志文件格式 (.log和.out),位于$HADOOP_HOME/logs
***帮助我们排错
 .log:通过log4j记录的,记录大部分应用程序的日志信息,主要
 .out:记录标准输出和标准错误日志,少量记录,次要
常见命名规则:框架名-用户名-进程名-主机名.后缀
        例如:hadoop-tom-namenode-blue01.mydomain.log

----配置文件----------------------------------

默认配置文件:
core-default.xml
#core-default.xml位于${HADOOP_HOME}/share/hadoop/common/hadoop-common-2.5.0.jar压缩包里
#查看压缩包里文件:jar -tvf hadoop-common-2.5.0.jar | grep -i default.xml
#解压后可以查看文件内容
#$ mkdir aaa
#$ unzip hadoop-common-2.5.0.jar -d aaa
#其他3个类似,有兴趣可以自己去找
hdfs-default.xml
yarn-default.xml
mapred-default.xml

自定义配置文件:${HADOOP_HOME}/etc/hadoop
core-site.xml、hdfs-site.xml、
mapred-site.xml、yarn-site.xml

** 当对应的进程启动时,会先加载默认配置文件,再加载自定义配置文件,属性重复时,后者覆盖前者

====maven和eclipse================================================

1、安装maven
$ tar zxvf /opt/softwares/apache-maven-3.0.5-bin.tar.gz

配置MAVEN_HOME:# vi /etc/profile (root用户)
MAVEN_HOME=/opt/modules/apache-maven-3.0.5
export PATH=$PATH:$MAVEN_HOME/bin

2、创建maven本地仓库
*** 若.m2文件夹不存在,则自己创建 $ mkdir /home/tom/.m2
*** 将提供的本地仓库包解压缩
$ tar zxvf /opt/softwares/repository.tar.gz -C /home/tom/.m2

# /home/tom/.m2/repository 是maven默认的本地仓库
# maven仓库分为远程仓库和本地仓库,当在pom里配置依赖项目后,maven首先会从本地仓库查找该项目,
  如果没有找到,则通过远程仓库下载该项目并保存在本地仓库里

3、安装eclipse
$ tar zxvf eclipse-jee-kepler-SR1-linux-gtk-x86_64.tar.gz
$ ./eclipse或是配置PATH
#others
export PATH=$PATH:/opt/modules/eclipse
# 在eclipse里设置maven路径
window--preference--maven--installation,添加(Add)maven安装路径

4、在eclipse里创建maven工程:
a)
maven archetype(就是创建项目的脚手架,用来简化项目创建工作):选择quickstart(默认)
groupId:你的主包名,比如:com.myblue
artifactId:你的项目名,比如:myhdfs
***参见maven项目目录结构

b)
创建好后,打开pom.xml
junit版本建议改为:4.10
添加dependency:
<dependency>
  <groupId>org.apache.hadoop</groupId>
  <artifactId>hadoop-client</artifactId>
  <version>2.5.0</version>
</dependency>
** 配置后,所需要的jar包会被自动导入

c)
创建"Source Folder":src/main/resources目录,用来存放core-site.xml、hbase-site.xml等
将core-site.xml拷贝过来:
$ cp etc/hadoop/core-site.xml  /home/tom/workspace/hdfs/src/main/resources/

----HDFS API--------------------------------

package com.myblue.myhdfs;

import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

public class Hello {

    public static FileSystem getFs() throws IOException {
        Configuration conf = new Configuration();
        conf.set("fs.defaultFS", "hdfs://blue01.mydomain:8020");
        FileSystem fs = FileSystem.get(conf);
        return fs;
    }

    public static void main(String[] args) throws IOException {
        
        FileSystem fs = Hello.getFs();
        FSDataInputStream inStream = fs.open(new Path("/input/a.txt"));

        //创建目录,会将所有不存在的目录一起创建出来
//        fs.mkdirs(new Path("/input/xxx/yyy"));
        //创建一个空文件,不存在的路径会自动创建
//        fs.create(new Path("/input/aaa/c.txt"));
        //是否递归删除,连带里面的内容一起删除
//        fs.delete(new Path("/input/aaa"), true);
        
        //将Linux本地文件拷到HDFS
//        fs.copyFromLocalFile(new Path("/home/tom/a.txt"), new Path("/input/e.txt"));
        //得到文件夹内所有文件的信息
//        FileStatus[] status=fs.listStatus(new Path("/input"));
//        System.out.println(status[0].getPath()+" "+status[0].getLen());
//        System.out.println(status[1].getPath()+" "+status[1].getLen());

        try {
            //后两个参数:缓存大小、结束后是否关闭
            IOUtils.copyBytes(inStream, System.out, 4096, false);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            IOUtils.closeStream(inStream);
        }
    }
}
0 0
原创粉丝点击