zoukankan      html  css  js  c++  java
  • 大数据学习---day05----hadoop02--------1补充配置(hadoop的环境变量配置,修改shell客户端默认操作的文件系统为hdfs系统,集群的批量启动(hdfs-site.xml中各参数的详解),查看那么node和datanode的日志信息,namenode和datanode的交互过程)2HDFS的客户端操作(上传,下载等等)

    1.补充配置

    1.1 Hadoop的环境变量的配置

    vi  /etc/profile

     $PATH:表示取出前面的环境变量的配置,此处前面有java环境变量的配置,所以不需要再配置,若没有则需要

     “:”  表示连接符号,功能和windows中的%一样

    export:  类似public的作用,扩大作用范围的

    1.2 修改shell客户端默认操作的文件系统为hdfs系统

      hdfs文件系统提供了一套操作文件系统的shell客户端命令,但是其默认操作的是本地系统,如下

    不加上namenode的路径,操作的是本地系统

    加上namenode的地址,操作的就是hdfs的文件系统

     但是每次都这样写就很麻烦,所以进行相应的配置,如下:

    在core-site.xml文件中添加如下:

    <property>
      <name>fs.defaultFS</name>
      <value>hdfs://doit01:9000/</value>
    </property>

    这个时候执行   hdfs dfs -ls / 就能直接操作hdfs文件系统了

    1.3 集群的批量启动

    1.3.1 过程

    直接在配置文件中的slaves文件中加入datanode的名字,如feng01   feng02   feng03

    在执行start-dfs.sh, stop-dfs.sh的时候会读取这个文件  ,在配置的节点上分别启动datanode

    1.3.2 知识点

    在配置文件中有个slaves文件,slaves文件里记录的是集群里所有的datanode的主机名,那么它到底是怎么样作用的呢?slaves文件只作用在NameNode上面,比如我在slaves里面配置了

    host1

    host2

    host3

    三台机器,这时候如果突然间新增了一台机器,比如是host4,会发现在NN上host4也自动加入到集群里面了,HDFS的磁盘容量上来了,这下子不是出问题了?假如host4不是集群的机器,是别人的机器,然后配置的时候指向了NN,这时候NN没有做判断岂不是把数据也有可能写到host4上面?这对数据安全性影响很大。所以可以在hdfs-site.xml里面加限制。

     
    dfs.hosts 
    /home/hadoop-2.0.0-cdh4.5.0/etc/hadoop/slaves 

    这相当于是一份对于DN的白名单,只有在白名单里面的主机才能被NN识别。配置了这个之后,就能排除阿猫阿狗的DN了。其实slaves文件里不一定要写主机名,最终的都是通过IP来判断,完全可以写一个IP就行。

    dfs.hosts
            預設值 : N/A
            說明 : 預設不指定的狀況下,只要 datanodes 在 hdfs-site.xml 指定 namenode,在 mapred-site.xml 指定 jobtracker 的位址就可以加入這個 cluster。但是為了安全的考量,系統管理者可能要決定只有特定的 nodes 可以加入。此值是指定一個檔案位置,名字可自取,例如 : /etc/hadoop/conf/dfs-hosts,並列出所有可以連結 namenode 的機器清單。不在清單上的機器是沒有權限的。在 mapred-site.xml 裡也有個類似的值 mapred.hosts 來指定可以連 jobtracker 的機器清單。
    dfs.hosts.exclude
            預設值 : N/A
            說明 : 當需要汰換或移除多台機器時會用到。理論上一台機器無預期的當機,Hadoop 會偵測並把該機器上的 blocks 搬到其他的 datanodes 上,並不需要系統管理員做額外的動作。但是停掉多台機器的情況下是有風險的,假設備份個數為 3 並停掉三台機器,則有一定的機率某些 blocks 正好只在這三台機器上,移掉之後資料也救不回來了。正確的做法是先告訴 namenode 這些機器將被移除,讓 namenode 把上面的資料全部備份到其他的 datanodes 上,再進行停機。跟 dfs.hosts 一樣,指定一個檔案位置,名字可自取,例如 : /etc/hadoop/conf/dfs-exclude-hosts,並列出所有需汰換的機器清單。設定後要執行以下的指令通知 namenode 做搬資料的動作。
    hdfs-site.xml文件参数详解
    NameNode
    dfs.name.dir
            預設值 : ${hadoop.tmp.dir}/dfs/name
            說明 : 指定本機上存取 fsimage 及 editlog 的目錄,這個目錄非常的重要,如果損毀就無法存取 HDFS 的資料了,所以不建議放在 ${hadoop.tmp.dir} 目錄下。更好的做法是用 “," 指定多個目錄,Hadoop 會複製 fsimage 的資料到所有的目錄下,如果其中一個目錄損毀 Hadoop 會自動使用正常的目錄並把對的資料再複製到損毀的目錄下。
            指定多個目錄後在 HDFS portal 會看到多個目錄,正常狀況會是 Active,當損毀時會變成 Inactive
           
    
    dfs.namenode.logging.level
            預設值 : info
            說明 : 這個值是指定 namenode 的 logging level。其他的值有
    dir : 看 namenode server 的變化
    block : 看 blocks 新增刪除或 replication 的變化
    all : 顯示全部的 log
            除非是為了 debug,不然不建議用其他的等級,會造成 Hadoop 的 log 檔案太大。       
    dfs.http.address
            預設值 : 0.0.0.0:50070
            說明 : Web UI 用的 port。除非是為了 security 的考量才會需要改 binding 的 IP/Port,不然不需要改這個值。
    dfs.https.enable
            預設值 : false
            說明 : namenode 預設並沒有啟動 https,在設定 https 的 IP/Port 之前要先確定這個值設為 true。
    dfs.https.address
            預設值 : 0.0.0.0:50470
            說明 : Web UI 用的 port,用 https protocol。除非是為了 security 的考量才會需要改 binding 的 IP/Port,不然不需要改這個值。
    dfs.replication
            預設值 : 3
            說明 : 預設 blocks 的備份數量。如果不需要太多的備份或 cluster 比較小,可以改為 2。Client 端也可以根據使用狀況自行更改這個值。只是如果所設的值小於 dfs.replication,在執行 hadoop fsck 指令時會看到這個 block 被標示為 Under-Replicated Blocks。至於備份的機制可以參考 Hadoop 參數設定 – core-site.xml 裡的 topology.script.file.name 說明。
    dfs.replication.min
            預設值 : 1
            說明 : 不需要特別改這個值。因為並不是所有在 HDFS 上的資料都需要有 3 份備份,這可以由 client 來決定。如果對資料備份非常敏感可以把這個值設為跟 dfs.replication 一樣。
    dfs.replication.max
            預設值 : 512
            說明 : 因為 client 可以自行決定每個 block 要有幾份備份,為了怕誤操作導致備份過多而影響整個 cluster 的使用量,建議給一個小一點的值,例如 10。
    dfs.block.size
            預設值 : 67108864(byte)
            說明 : 預設每個 block 是 64MB。如果確定存取的檔案都很大可以改為 134217728(128MB)。Client 也可自行決定要使用的 block size  而不需要更改整個 cluster 的設定。
           
    1    hadoop fs -D dfs.block.size=134217728 -put local_name remote_location
    
    
    
    
    dfs.safemode.threshold.pct
            預設值 : 0.999f
            說明 : Hadoop 在啟動時預設會進入 safe mode,也就是唯讀模式,這時是不能寫入資料的。只有當 99.9% 的 blocks 達到最小的 dfs.replication.min 數量(預設是 1)才會離開 safe mode。在 dfs.replication.min 設的比較大或 data nodes 數量較多時會等比較久。
            下面討論兩個極端的狀況
    設為大於 1 : 表示永遠不會離開 safe mode,這在當 Hadoop cluster 需要做 migration 時很好用,即可繼續提供讀取服務,又可防止使用者寫入資料導至 migration 不完全。
    設為 0 : 表示不會啟動 safe mode。在 local 測試時會非常的方便,不然常常需要等一段時間或直接執行
                   
    1    hadoop dfsadmin -safemode leave
    
    
    
    
                    才能離開 safe mode。
    dfs.hosts
            預設值 : N/A
            說明 : 預設不指定的狀況下,只要 datanodes 在 hdfs-site.xml 指定 namenode,在 mapred-site.xml 指定 jobtracker 的位址就可以加入這個 cluster。但是為了安全的考量,系統管理者可能要決定只有特定的 nodes 可以加入。此值是指定一個檔案位置,名字可自取,例如 : /etc/hadoop/conf/dfs-hosts,並列出所有可以連結 namenode 的機器清單。不在清單上的機器是沒有權限的。在 mapred-site.xml 裡也有個類似的值 mapred.hosts 來指定可以連 jobtracker 的機器清單。
    dfs.hosts.exclude
            預設值 : N/A
            說明 : 當需要汰換或移除多台機器時會用到。理論上一台機器無預期的當機,Hadoop 會偵測並把該機器上的 blocks 搬到其他的 datanodes 上,並不需要系統管理員做額外的動作。但是停掉多台機器的情況下是有風險的,假設備份個數為 3 並停掉三台機器,則有一定的機率某些 blocks 正好只在這三台機器上,移掉之後資料也救不回來了。正確的做法是先告訴 namenode 這些機器將被移除,讓 namenode 把上面的資料全部備份到其他的 datanodes 上,再進行停機。跟 dfs.hosts 一樣,指定一個檔案位置,名字可自取,例如 : /etc/hadoop/conf/dfs-exclude-hosts,並列出所有需汰換的機器清單。設定後要執行以下的指令通知 namenode 做搬資料的動作。
           
    1    hadoop dfsadmin -refreshNodes
    
    
    
    
            進度可以在 web UI 上看到,當該 datanodes 的狀態顯示為 “Decommissioned" 表示可以安全的移除機器了。
    dfs.support.append
            預設值 : false
            說明 : 指定是否可在 HDFS 原有檔案內容之後加入新資料。看 hfds-default.xml 裡對這個參數的說明是有 bug “This is currently set to false because there are bugs in the “append code" and is not supported in any prodction cluster."。但是 HBase Configuration 裡另外說明了以上的資訊是過時的,在 Cloudera 及 MapR 的版本都已經加入了這個功能。如果有使用 HBase,為了避免資料遺失,請把這個值設為 true。
    dfs.namenode.handler.count
            預設值 : 10
            說明 : 設定 namenode server threads 的數量,這些 threads 會用 RPC 跟其他的 datanodes 溝通。當 datanodes 數量太多時會發現很容易出現 RPC timeout,解決方法是提升網路速度或調高這個值,但要注意的是 thread 數量多也表示 namenode 吃的記憶體也隨著增加。在 Hadoop Cluster Setup 這篇文章裡的提到 900 個 nodes 只需要設成 40,但是在個人經驗裡是 100 個 nodes 配 100 個 threads。
    dfs.namenode.keytab.file
            預設值 : N/A
            說明 : 當 core-site.xml 裡的 hadoop.security.authentication 參數設為 “kerberos" 時就要指定 keytab 的位置。例如 : /etc/hadoop/conf/hdfs.keytab
    dfs.namenode.kerberos.principal
            預設值 : N/A
            說明 : 指定 kerberos principal 名稱,這在產生 keytab 檔案時會指定,一般常用的命名規則是 hdfs/_HOST@KERBEROS-REALM.COM
    Secondary NameNode
    dfs.secondary.namenode.keytab.file
            預設值 : N/A
            說明 : 當 core-site.xml 裡的 hadoop.security.authentication 參數設為 “kerberos" 時就要指定 keytab 的位置。例如 : /etc/hadoop/conf/hdfs.keytab
    dfs.secondary.namenode.kerberos.principal
            預設值 : N/A
            說明 : 指定 kerberos principal 名稱,這在產生 keytab 檔案時會指定,一般常用的命名規則是 hdfs/_HOST@KERBEROS-REALM.COM
    DataNode
    dfs.data.dir
            預設值 : ${hadoop.tmp.dir}/dfs/data
            說明 : 指定本機上放 data nodes 資料的目錄,如果要指定多個目錄(volumes) 可用 “," 分隔。在 production 環境會指定多個,並設定 dfs.datanode.failed.volumes.tolerated。一般來說,多個目錄會對應到系統上不同的 partitions,不同的硬碟。設定多個可加快存取速度,及避免硬碟壞掉需要抽換用。
    dfs.datanode.address
            預設值 : 0.0.0.0:50010
            說明 : datanode service 聽的 port,用來傳輸資料用。除非是為了 security 的考量才會需要改 binding 的 IP/Port,不然不需要改這個值。
    dfs.datanode.http.address
            預設值 : 0.0.0.0:50075
            說明 : Web UI 用的 port。除非是為了 security 的考量才會需要改 binding 的 IP/Port,不然不需要改這個值。
    dfs.datanode.handler.count
            預設值 : 3
            說明 : 指定 data node 上用的 thread 數量。在 production 的環境建議調到 100。
    dfs.datanode.max.xcievers
            預設值 : 256
            說明 : 這個值是指定 datanode 可同時處理的较大檔案數量。但是預設值很小,當多個或一個大型程式存取時會發生下面的錯誤訊息
           
    1    10/12/08 20:10:31 INFO hdfs.DFSClient: Could not obtain block blk_XXXXXXXXXXXXXXXXXXXXXX_YYYYYYYY from any node: java.io.IOException:
    
    2    No live nodes contain current block. Will get new block locations from namenode and retry...
    
    
    
    
            以使用 HBase 為例,建議值是 4096。如果還有多個程式存取可再乘 2。
    dfs.datanode.failed.volumes.tolerated
            預設值 : 0
            說明 : 這個值要對應 dfs.data.dir 參數設定的目錄個數,0 表示只要有任何一個 volume 壞掉 data nodes 就會被強制停掉。假設掛載 n 個 volumns,Hadoop 會確定 n – dfs.datanode.failed.volumes.tolerated 不能小於 0。設定錯誤在啟動 data node 會看到下面的訊息
           
    01    2011-08-27 11:53:03,785 ERROR org.apache.hadoop.hdfs.server.datanode.DataNode: org.apache.hadoop.util.DiskChecker$DiskErrorException: Invalid value for validVolsRequired : -1 ,  Current valid volumes: 1
    
    02           at org.apache.hadoop.hdfs.server.datanode.FSDataset.<init>(FSDataset.java:906)
    
    03           at org.apache.hadoop.hdfs.server.datanode.DataNode.startDataNode(DataNode.java:373)
    
    04           at org.apache.hadoop.hdfs.server.datanode.DataNode.<init>(DataNode.java:282)
    
    05           at org.apache.hadoop.hdfs.server.datanode.DataNode.makeInstance(DataNode.java:1544)
    
    06           at org.apache.hadoop.hdfs.server.datanode.DataNode.instantiateDataNode(DataNode.java:1484)
    
    07           at org.apache.hadoop.hdfs.server.datanode.DataNode.createDataNode(DataNode.java:1502)
    
    08           at org.apache.hadoop.hdfs.server.datanode.DataNode.secureMain(DataNode.java:1627)
    
    09           at org.apache.hadoop.hdfs.server.datanode.SecureDataNodeStarter.start(SecureDataNodeStarter.java:103)
    
    10           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    
    11           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    
    12           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    
    13           at java.lang.reflect.Method.invoke(Method.java:597)
    
    14           at org.apache.commons.daemon.support.DaemonLoader.start(DaemonLoader.java:177)
    
    
    
    
            如果 data volumns 有 4 個,dfs.datanode.failed.volumes.tolerated 可設為 2。表示當有 2 個硬碟壞掉時 data nodes 還是可以正常運作。這時只要換壞掉硬碟即可,並不需要停掉 data nodes。
    dfs.datanode.data.dir.perm
            預設值 : 700
            說明 : 這個值是設定 data node 寫資料到 local disk 上的權限。使用 POSIX 表示法。在 production 上為了 security 考量,不建議改這個參數。如果是測試環境為了方便其他 users 用工具分析資料,可以改成 755。
    dfs.datanode.du.reserved
            預設值 : 0(byte)
            說明 : 預設值表示 data nodes 會使用整個 volumns,寫滿之後會導致無法再寫入 M/R jobs 或啟動 data nodes 時的暫存檔。如果還有其他程式共用這些目錄也會受到影響。建議保留至少 1073741824(1G) 的空間。
    dfs.datanode.keytab.file
            預設值 : N/A
            說明 : 當 core-site.xml 裡的 hadoop.security.authentication 參數設為 “kerberos" 時就要指定 keytab 的位置。例如 : /etc/hadoop/conf/hdfs.keytab
    dfs.datanode.kerberos.principal
            預設值 : N/A
            說明 : 指定 kerberos principal 名稱,這在產生 keytab 檔案時會指定,一般常用的命名規則是 hdfs/_HOST@KERBEROS-REALM.COM
    Etc
    dfs.balance.bandwidthPerSec
            預設值 : 1048576(byte)
            說明 : 這個值是決定 file blocks 從一個 data node 搬到另一個 data node 的速度, 預設為 1MB。主要是用在 re-balance,如果覺得執行速度太慢可以調整這個參數加快 blocks 的搬移。但是這也表示會多佔頻寬,可能會影響正常 M/R jobs 或 applications 的執行。建議值為 4194304(4MB)
    View Code

     1.4  查看那么node和datanode的日志信息

     

    •  clusterID:集群版本,datanode和namenode上要保持一致
    • storeageID:每个datanode的唯一标识

     

     可见datanode和namenode上的集群I版本是要一样的

    问题一

     当元数据(即/opt/hdpdata)被删除以后namenode找不到fsImage会闪退,解决办法

    当我们重新格式化namenode以后 ,会生成新的集群版本 , 那么原来的datanode就无法完成注册 ,闪退

     问题二

    如果克隆了一台datanode角色的机器,会出现datanode无法注册,因为两个克隆机器的storeageID相同,namenode只能识别一个 

    1.5 namenode和datanode的交互过程

     注意:心跳汇报时,datanode会从namenode那领取任务,如备份任务。

    当一个节永远点宕机时,name是如何剔除掉这个节点的呢?

    如上图,首先namenode会等10次datanode的心跳汇报时间,10次后还没收到来自此节点的心跳汇报,namenode隔5min就会向datanode发送校验信息,若没回复,再隔5min,namenode又会向datanode发送校验信息,若还是收不到回复,namenode就会将该节点剔除这个集群,不在管理这个节点。

     2. HDFS的客户端操作

     HDFS提供了两套供客户端使用的API(shell客户端和java客户端)

     2.1 HDFS的shell客户端

     知识点1处讲过如何将hdfs的客户端默认操作改成HDFS系统

     

     当使用hdfs dfs命令时,得到如下结果

     如:创建文件夹: hdfs dfs -mkdir  /aa

     2.2 HDFS的java客户端

     2.2.1 获取java客户端对象

    FileSystem fs = FileSystem.get(URI uri, Configuration conf, String user);
    参数一: 指定操作的HDFS系统的位置 就是namenode的位置
    参数二: 配置对象 用户可以使用这个对象定制化配置 , 比如设置副本的个数 数据切块存储的大小
    参数三 : 执行命令的用户的用户名 默认是自己的主机名

    public class GetHdfsClient {
        public static void main(String[] args) throws Exception {
            // 指定操作HDFS系统的位置,就是namenode的位置
            URI uri = new URI("hdfs://feng01:9000/");
            // 配置对象,用户可以使用这个对象定制化配置,比如设置副本的个数
            Configuration conf = new Configuration();
            // java操作hdfs的客户端对象
            FileSystem fs = FileSystem.get(uri, conf, "root");
            // 操作fs,在hdfs中的所有的文件或者文件夹抽象对象是path  即IO File
            Path path = new Path("/jj");
            boolean b = fs.mkdirs(path);
            if(b) {
                System.out.println("创建文件夹成功");
            }
            fs.close();
        }
    }

    2.2.2 Configuration详解

     设置对象可以设置副本的个数,block的大小,以及系统读取配置文件的顺序

    (1)若不进行conf配置,自动的设置默认的配置信息=====>副本个数为3,block大小为128

    hdfs-default.xml文件中

     

     (2)自动读取类路径下的默认配置文件  hdfs-site.xml   core-site.xml  mapred-site.xml

     (3)使用conf对象在程序中设置(范围小),优先级最高

         confset > 本项目的配置文件 >默认的配置信息 

     案例:

    a. 不进行conf设置

    public class ConfigurationDetail {
        public static void main(String[] args) throws Exception {
            URI uri = new URI("hdfs://feng01:9000/");
            Configuration conf = new Configuration();
            FileSystem fs = FileSystem.get(uri, conf, "root");
            // 上传文件,参数1  本地路径  参数2 hdfs上的路径
            fs.copyFromLocalFile(new Path("E:/javafile/wc1.txt"), new Path("/x/haha.txt"));
            fs.close();
        }
    }

     b . 进行conf配置,即在项目中创建conf文件夹,并创建一个hdfs-site.xml,内容如下

     

     java代码同上(hdfs中的文件改成haha1.txt),结果如下

     c 使用conf对象在程序中进行设置,优先级最高,但作用范围最小

    Configuration conf = new Configuration();
    // 设置上传副本的个数  key  value
    conf.set("dfs.replication", "5");
    // 设置物理块的大小  
    conf.set("dfs.blocksize", "256M");

    2.2.3 上传

     

    参数一: delsrc, 是否删除源文件,true表示删除

    参数二:是否覆盖

    参数三:本地文件

    参数四:HDFS系统的文件历经

    2.2.4 下载

    在将hdfs中的数据下载到windows中,需要在windows中安装hdp环境,将分布式流的数据写到磁盘中需要使用hdp中的转换(需要hdp环境,),但是发现第三种方法不配置hadoop也能下载成功,暂时不知道为什么

    参数一:是否删除hdfs中的源文件

    参数2: hdfs中的路径

    参数3 :本地路径

    参数4 :是否在本地生成一个hdp内部的校验文件  默认是false生成  true不生成

    环境变量的配置:

    (1)配置HADOOP_HOME=hadoop的路径

     (2) Path中添加 %HADOOP_HOME%/bin

    2.2.5 创建文件夹

     

    2.2.6 删除

    public class Delete {
        public static void main(String[] args) throws Exception {
            FileSystem fs = HdfsUtils.getFs();
            Path path = new Path("/a");
            if (fs.exists(path)) {
                /*
                 * 参数一 hdfs的路径 参数二 递归的删除文件夹中的内容
                 */
                boolean b = fs.delete(path, true);
                System.out.println(b ? "成功" : "失败");
    
            }else {
                System.out.println("文件不存在");
            }
            fs.close();
        }
    }

    2.2.7  读取文件内容 

     字节流

    public class ReadDataFromHdfsFile {
        public static void main(String[] args) throws Exception {
            //创建java操作hdfs系统的对象
            FileSystem fs = HdfsUtils.getFs();
            FSDataInputStream inputStream = fs.open(new Path("/word.txt"));
            byte[] b = new byte[2048];
            int len = 0;
            while((len=inputStream.read(b))!=-1) {
                System.out.println(new String(b,0,len));
            }
            fs.close();
        }
    }

    包装成缓冲字符流

    public class ReadDataFromHdfsFile {
        public static void main(String[] args) throws Exception {
            //创建java操作hdfs系统的对象
            FileSystem fs = HdfsUtils.getFs();
            // 获取文件的输入流,字节流
            FSDataInputStream fis = fs.open(new Path("/word.txt"));
            // 读取的是文本内容,可以用字符流包装
            BufferedReader br = new BufferedReader(new InputStreamReader(fis));
            String line = null;
            while((line=br.readLine())!=null) {
                System.out.println(line);
            }
        }
    }

    读取的结果如下:

    注意:此处若使用seek(i),则表示跳过i个字节(hdfs支持随机读),如代码变成如下:

     这可以用于多台机器同时读取一个大文件

    如下图,假设有一个30G的文件,使用3台机器去读取这个文件

    2.2.8 判断文件夹是否存在

    2.2.9 向文件夹中写入数据(不常用)

      支持追加,不支持随机写,建议不要修改文件的内容(一般不用这功能)

    原因:HDFS的定位是存储海量数据,而不是对数据进行写操作,其一般是一次存入,多次取出

    • append 向一个已经存在的文件中追加内容
    • create 创建文件再追加内容
    public class WriteDataToHdfsFile {
    
        public static void main(String[] args) throws Exception {
            FileSystem fs = HdfsUtils.getFs();
            // fs.append(f) // 追加内容到文件 文件存在
            // fs.create(f) ; 创建文件再追加内容
            /*
             * FSDataOutputStream fout = fs.append(new Path("/word.doc"));
             * fout.writeUTF("hello 熊大!"); // 刷写 fout.flush(); fout.close();
             */
            Path path = new Path("/word2.doc");
            if(fs.exists(path)) {
                FSDataOutputStream fout = fs.append(new Path("/word.doc"));
            }else {
                FSDataOutputStream fout = fs.create(new Path("/word2.doc"));
                fout.writeUTF("hello Jerry");
                fout.flush();
            }
            fs.close();
        }
    }

    2.2.10 查看内容列表

     此处查看的是HDFS分布式系统的根目录,如下

    第一种形式(listFiles):只能查看文件,不能查看文件夹

     代码:

    public class seeList {
        public static void main(String[] args) throws Exception {
            FileSystem fs = HdfsUtils.getFs();
            // 得到的是一个迭代器
            RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
            while(listFiles.hasNext()) {
                LocatedFileStatus next = listFiles.next();
                // 获取文件的路径
                Path path = next.getPath();
                System.out.println(path);
            }
        }
    }

    运行结果:

     

     除此之外,还可以查看更多的内容,如下:

    public class SeeList {
        public static void main(String[] args) throws Exception {
            FileSystem fs = HdfsUtils.getFs();
            // 参数一  文件夹 参数二 是否递归查看 文件
            RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/aa"), true);
            while(listFiles.hasNext()) {
                // 遍历的每个文件
                LocatedFileStatus next = listFiles.next();
                // 获取文件的路径
                Path path = next.getPath();
                next.getAccessTime();  // 上次访问的时间
                // 获取每个文件块的消息   每个块数据在哪个机器上  0,67,doit03,doit02,doit01
                BlockLocation[] locations = next.getBlockLocations();
                for (BlockLocation blockLocation : locations) {
                    System.out.println(blockLocation);
                }    
                next.getBlockSize(); // 每个文件块的大小
                next.getLen() ; //文件的真正的大小
                next.getModificationTime() ;// 上次修改的时间
                next.getReplication() ; //副本的个数
                next.getPermission() ; // 获取权限
                
                System.out.println(path);
            }
            fs.close();
        }
    }

     第二种形式(listStatus):既可以查看文件,也可以查看文件夹

    public class seeListStatus {
        public static void main(String[] args) throws Exception {
            FileSystem fs = HdfsUtils.getFs();
            // 这个数组包含了文件夹的很多信息,一个数组代表一个文件夹
            FileStatus[] listStatus = fs.listStatus(new Path("/"));
            for (FileStatus fileStatus : listStatus) {
                // 打印文件夹的信息
                System.out.println(fileStatus);
                //获取文件或者文件夹的路径
                Path path = fileStatus.getPath();
                if(!fs.isDirectory(path)) { // 是文件夹 ==> if(fs.isFile(path))
                    // 获取文件的消息
                    System.out.println(path);
                }
            }
        }
    }

    打印部分结果

    数组部分(包含的信息如下):

    FileStatus{path=hdfs://feng01:9000/feng; isDirectory=true; modification_time=1572809795905; access_time=0; owner=root; group=supergroup; permission=rwxr-xr-x; isSymlink=false}

     3 HDFS读写数据流程

     3.1 上传(写)

    •  block

      文件上传前需要分块,这个块就是block,一般为128M,当然你可以去改,不过不推荐。因为块太小,寻址世家占比过高。块太大,map任务数太少,作业执行速度变慢。它是最大的一个单位

    •  packet

      packet是第二大的单位,它是client端向DataNode,或DataNode的PipLine之间数据传输的基本单位,默认是64KB

    •  chunk

           chunk是最小的单位,它是client向DataNode或者是DataNode的PipLine之间进行数据校验的基本单位,默认512Byte,因为用作校验,故每个chunk需要带有4Byte的校验位。所以实际每个chunk写入packet的大小为516Byte。由此可见真是数据与校验值数据的比值约为128:1

    基本流程:

    (1)请求namenode上传数据(上传到哪去,副本的个数,物理块的大小)

    (2)namenode接收到请求,计算数据存储的块的个数,以及集群中各个datanode的数据存储能力

    (3)划分存储的任务,记录元数据,并回复客户端准备工作做好了,可以上传数据了

    (4)客户端接收到请求许可之后,开始请求上传第一块文件,namenode返回给客户端第一块数据的原信息(如:blkID:host 0 128M )

    (5)接收到相应的元数据信息后,客户端请求离自己最近的一个机器(有个算法裘最近机器)建立连接通道

    (6)读取上传第一块数据,存储在datanode节点上,集群中存储其他两个副本(client每向第一个DataNode写入一个packet,这个packet便会直接在pipeline里传给第二个、第三个…DataNode。 

      (注:并不是写好一个块或一整个文件后才向后分发)

    (7)请求上传第二,第三。。。。。。(数据是一块一块传的,并不是分布式的

    (8)每个datanode写完一个块后,会返回确认信息

      (注:并不是每写完一个packet后就返回确认信息,个人觉得因为packet中的每个chunk都携带校验信息,没必要每写一个就汇报一下,这样效率太慢。正确的做法是写完一个block块后,对校验信息进行汇总分析,就能得出是否有块写错的情况发生)

    (9)写完数据,关闭输出流

    (10)发送完成信号给NameNode(所有datanode写完)

    (注:发送完成信号的时机取决于集群是强一致性还是最终一致性,强一致性则需要所有DataNode写完后才向NameNode汇报。最终一致性则其中任意一个DataNode写完后就能单独向NameNode汇报,HDFS一般情况下都是强调强一致性)

     

    3.2 下载(读)

     (1)客户端向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址

     (2)挑选一台datanode(就近原则)服务器,请求读取数据

     (3)datanode开始传输数据给客户端

     (4)客户端以packet为单位接受,先在本地缓存,然后写入目标文件

  • 相关阅读:
    基于SpringBoot打造在线教育系统(6)-- 二级分类模块UI篇
    基于SpringBoot打造在线教育系统(5)-- 课程分类模块
    基于SpringBoot打造在线教育系统(4)-- SpringBoot集成ElementUI
    基于SpringBoot打造在线教育系统(3)-- 登录与授权管理
    基于SpringBoot打造在线教育系统(2)-- 深入学习JPA与Junit测试
    我只会HelloWorld,但是我却完成了一个SpringBoot项目!(1)
    Constrast Learnning
    BlazePose: On-device Real-time Body Pose tracking
    pytest---fixture作用范围
    pytest---fixture中conftest.py文件
  • 原文地址:https://www.cnblogs.com/jj1106/p/11785656.html
Copyright © 2011-2022 走看看