Hadoop入門|HDFS分布式文件系統(tǒng)

寫在前面

我自己一直比較喜歡大數(shù)據(jù)這個(gè)方向的工作,雖然自己也在大數(shù)據(jù)相關(guān)的崗位上工作了小兩年,但一直沒(méi)有系統(tǒng)的學(xué)習(xí)過(guò)大數(shù)據(jù)相關(guān)的知識(shí)。

說(shuō)到自身經(jīng)歷,可能和大部分程序員一樣,一直混跡于小公司,我從第一家公司離職的理由就是拖欠工資,那個(gè)時(shí)候又是剛畢業(yè),手里沒(méi)有一點(diǎn)積蓄,后來(lái)實(shí)在沒(méi)辦法只能離職求活路。不過(guò)很感謝第一家公司,在那是我進(jìn)步最快的地方,我從事大數(shù)據(jù)崗位也是那家公司花錢讓我去學(xué)習(xí)的。除了是小公司,其他的都很好,技術(shù)氛圍很棒!第二家公司雖然比較大,但是屬于項(xiàng)目外包型公司(雖然我所在的部門屬于自研型,但還是外包的干法,我依舊記得我入職之后才發(fā)現(xiàn)公司代碼沒(méi)有版本管理,所有代碼都在主分支上,沒(méi)有一份技術(shù)文檔,全靠口口相傳)。

今年疫情原因,各個(gè)行業(yè)裁員的裁員,降薪的降薪,我在的公司也不例外,全員降薪30%,然而周末也沒(méi)了,瘋狂趕項(xiàng)目進(jìn)度,我最多的時(shí)候同時(shí)支持了五個(gè)項(xiàng)目組的報(bào)表開(kāi)發(fā),每天做夢(mèng)都?jí)粢?jiàn)自己在催著改報(bào)表。

更恐怖的是開(kāi)發(fā)這個(gè)行業(yè),尤其是有外包性質(zhì),門檻極低,低到令人發(fā)指,我在公司下面帶了三個(gè)那種培訓(xùn)機(jī)構(gòu)出來(lái)的,都是學(xué)了幾個(gè)月轉(zhuǎn)身包裝簡(jiǎn)歷就出來(lái)面試了,那的工資低還比你能加班!

后來(lái)實(shí)在不想每天這樣疲于拼命的機(jī)械式生活,想著多花時(shí)間去學(xué)習(xí),然后跳槽去好一點(diǎn)的公司!然而現(xiàn)實(shí)告訴你,我最缺的就是時(shí)間!直到拉勾推出的大數(shù)據(jù)高薪訓(xùn)練營(yíng)。關(guān)于技術(shù)類的學(xué)習(xí),我有點(diǎn)排斥找培訓(xùn)機(jī)構(gòu),覺(jué)得自己可以通過(guò)自學(xué),在網(wǎng)上翻閱資料啊,找視頻之類的方式學(xué),因?yàn)橄嘈抛约旱膶W(xué)習(xí)能力。但是大家也都知道,網(wǎng)上找的這些東西都能學(xué)會(huì),也可以看得懂。但是當(dāng)自己學(xué)多了就感覺(jué)自己學(xué)的很雜,一點(diǎn)都沒(méi)有系統(tǒng)性的學(xué)。而且相對(duì)于網(wǎng)上找的免費(fèi)的視頻,內(nèi)容很沒(méi)有深度,TB上買的視頻有些章節(jié)的確實(shí)還行,但是感覺(jué)是那種很久之前的東西拿出來(lái)不停的賣,而且關(guān)于技術(shù)方面的東西,肯定是會(huì)有不明白的地方,當(dāng)然遇到這些肯定第一時(shí)間是自己去網(wǎng)絡(luò)上找找解決方案,或者去了解為什么。但是很多東西確實(shí)在網(wǎng)絡(luò)上找不到,久而久之,就積累了各種問(wèn)題。

之前也看過(guò)很多培訓(xùn)機(jī)構(gòu),像什么八斗學(xué)院,馬士兵教育,金訊教育等等,經(jīng)常發(fā)一些二學(xué)員就業(yè)的截圖,薪資都特別高,但其實(shí)在這一行的都知道,大數(shù)據(jù)這塊薪資雖然高,但也沒(méi)有高特別多,只是門檻高,說(shuō)實(shí)話,很討厭這種虛假營(yíng)銷。

選擇拉勾的原因

1. 朋友推薦

剛開(kāi)始知道拉勾除了Java高薪訓(xùn)練營(yíng),但是并不是很感興趣,后來(lái)朋友報(bào)名了Java高薪訓(xùn)練營(yíng),反饋很好,恰逢拉勾推出了大數(shù)據(jù)高薪訓(xùn)練營(yíng),就想著說(shuō)同一家公司的課程,質(zhì)量應(yīng)該差不多,就抱著試一試的想法找拉勾的老師聊了聊,聽(tīng)完介紹感覺(jué)還可以,就報(bào)名了。

2. 拉勾本身

拉勾本身就是做招聘的,對(duì)企業(yè)需求這一塊更加了解企業(yè)需要什么樣能力的人,那么他們的課程在這塊針對(duì)性肯定比其他機(jī)構(gòu)好

結(jié)果

1. 個(gè)人收獲

算算從開(kāi)班到現(xiàn)在,已經(jīng)五個(gè)月了,課程已經(jīng)學(xué)了一半,不是我學(xué)的很慢,而是課程質(zhì)量真的很高,每一個(gè)模塊單獨(dú)拿出來(lái)都可以是一門課了,特別是一塊內(nèi)容學(xué)完就有一個(gè)實(shí)際項(xiàng)目等著你去做,而不是demo!現(xiàn)在養(yǎng)成了學(xué)習(xí)的習(xí)慣之后完全停不下來(lái)了!在這里,我已經(jīng)經(jīng)歷了完整的離線數(shù)倉(cāng)開(kāi)發(fā),包括服務(wù)器選型,技術(shù)選型等等,在需求這塊,老師帶著我們一個(gè)一個(gè)需求的講解,對(duì)于復(fù)雜的需求和實(shí)現(xiàn),老師會(huì)先給出一個(gè)與之相關(guān)但是比較基礎(chǔ)的需求或者實(shí)現(xiàn),讓我們一步一步的學(xué)習(xí)。相比學(xué)之前的我,現(xiàn)在的我可以有底氣的說(shuō)具體某個(gè)組件怎么用,為什么這么用,同類產(chǎn)品有哪些,為什么選擇這個(gè)而不是其他的,甚至部分原理源碼都可以說(shuō)出來(lái),每一個(gè)模塊的最后老師都會(huì)帶著我們深入底層原理去了解具體某一個(gè)功能的實(shí)現(xiàn),也會(huì)帶著我們?nèi)テ饰鲈创a,看看源碼是怎樣寫的!

2. 課程內(nèi)容

課程說(shuō)的再多也不如自己去看,我給幾張知識(shí)思維導(dǎo)圖,看過(guò)就知道干貨有多少了!

Apache Hadoop
Apache Hive.png

教學(xué)服務(wù)

  1. 班主任每天催學(xué)習(xí),提醒交作業(yè),安排直播課,帶動(dòng)群里學(xué)習(xí)氣氛,服務(wù)很周到
  2. 導(dǎo)師解答超級(jí)耐心,不會(huì)因?yàn)槟銌?wèn)的問(wèn)題有多簡(jiǎn)單或者稍微百度以下就能明白,還會(huì)根據(jù)你問(wèn)的問(wèn)題,舉一反三,給你講一些相關(guān)的知識(shí)
  3. 關(guān)于作業(yè),每一個(gè)知識(shí)點(diǎn)結(jié)束,都會(huì)有小作業(yè),每一個(gè)模塊結(jié)束都會(huì)有一個(gè)大作業(yè),每一份作業(yè)導(dǎo)師都會(huì)批改,只有批改通過(guò)了才能學(xué)習(xí)接下來(lái)的內(nèi)容

內(nèi)推服務(wù)

群里已經(jīng)有好幾波內(nèi)推了,這個(gè)月還和京東合作,成立專屬內(nèi)推,解決就業(yè)問(wèn)題。而且投簡(jiǎn)歷之前,可以去找導(dǎo)師修改簡(jiǎn)歷,讓你的簡(jiǎn)歷過(guò)關(guān)的機(jī)會(huì)更高,也會(huì)對(duì)你進(jìn)行面試前的指導(dǎo),簡(jiǎn)直貼心的不要不要!

個(gè)人的兩句話

  1. 自學(xué)固然可以,但是時(shí)間成本很高,而且知識(shí)并不系統(tǒng),是時(shí)間成本更高還是培訓(xùn)費(fèi)成本更高,還有你一個(gè)人能否堅(jiān)持學(xué)習(xí),不受外界誘惑?

  2. 對(duì)于拉勾,我簡(jiǎn)而言之,豐富而完善的知識(shí)體系,行業(yè)大咖的直播解答,獨(dú)家的內(nèi)推資源,導(dǎo)師班主任全程伴讀,在你偷懶的時(shí)候甩出小鞭子,定期測(cè)評(píng),完善的作業(yè)機(jī)制,良好的學(xué)習(xí)環(huán)境


下面正文開(kāi)始


一、HDFS概述

1. HDFS產(chǎn)出背景及定義

  1. HDFS產(chǎn)生背景

隨著數(shù)據(jù)量越來(lái)越大,在一個(gè)操作系統(tǒng)存不下所有的數(shù)據(jù),那么就分配到更多的操作系統(tǒng)管理的磁盤中,但是不方便管理和維護(hù),迫切需要一種系統(tǒng)來(lái)管理多臺(tái)機(jī)器上的文件,這就是分布式文件管理系統(tǒng)。HDFS只是分布式文件管理系統(tǒng)中的一種。

  1. HDFS定義

    HDFS(Hadoop Distributed File System),它是一個(gè)文件系統(tǒng),用于存儲(chǔ)文件,通過(guò)目錄樹來(lái)定位文件;其次,它是分布式的,由很多服務(wù)器聯(lián)合起來(lái)實(shí)現(xiàn)其功能,集群中的服務(wù)器有各自的角色,HDFS是分布式存儲(chǔ)服務(wù)。

    HDFS的使用場(chǎng)景:適合一次寫入,多次讀出的場(chǎng)景,且不支持文件的修改。適合用來(lái)做數(shù)據(jù)分析,并不適合用來(lái)做網(wǎng)盤應(yīng)用。

2. HDFS優(yōu)缺點(diǎn)

  1. 優(yōu)點(diǎn):

    • 高容錯(cuò)性

      • 數(shù)據(jù)自動(dòng)保存多個(gè)副本。它通過(guò)增加副本的形式,提高容錯(cuò)性。

      • 某一個(gè)副本丟失以后,它可以自動(dòng)恢復(fù)。

    • 適合處理大數(shù)據(jù)

      • 數(shù)據(jù)規(guī)模:能夠處理數(shù)據(jù)規(guī)模達(dá)到GB、TB、甚至PB級(jí)別的數(shù)據(jù);
      • 文件規(guī)模:能夠處理百萬(wàn)規(guī)模以上的文件數(shù)量,數(shù)量相當(dāng)之大。
    • 可構(gòu)建在廉價(jià)機(jī)器上,通過(guò)多副本機(jī)制,提高可靠性。

      ?

  2. 缺點(diǎn):

    • 不適合低延時(shí)數(shù)據(jù)訪問(wèn),比如毫秒級(jí)的存儲(chǔ)數(shù)據(jù),是做不到的。

    • 無(wú)法高效的對(duì)大量小文件進(jìn)行存儲(chǔ)。

      • 存儲(chǔ)大量小文件的話,它會(huì)占用NameNode大量的內(nèi)存來(lái)存儲(chǔ)文件目錄和塊信息。這樣是不可取的,因?yàn)镹ameNode的內(nèi)存總是有限的;
      • 小文件存儲(chǔ)的尋址時(shí)間會(huì)超過(guò)讀取時(shí)間,它違反了HDFS的設(shè)計(jì)目標(biāo)。
    • 不支持并發(fā)寫入、文件隨機(jī)修改。

      • 一個(gè)文件只能有一個(gè)寫,不允許多個(gè)線程同時(shí)寫;

      • 僅支持?jǐn)?shù)據(jù)append(追加),不支持文件的隨機(jī)修改。

3. HDFS的重要概念

HDFS 通過(guò)統(tǒng)一的命名空間目錄樹來(lái)定位文件; 另外,它是分布式的,由很多服務(wù)器?聯(lián)合起來(lái)實(shí)現(xiàn)其功能,集群中的服務(wù)器?有各自的角色(分布式本質(zhì)是拆分,各司其職)

  1. 典型的 Master/Slave 架構(gòu)

    • HDFS 的架構(gòu)是典型的 Master/Slave 結(jié)構(gòu)
    • HDFS 集群往往是一個(gè) NameNode+多個(gè)DataNode 組成(HA架構(gòu)會(huì)有兩個(gè)NameNode,聯(lián)邦機(jī)制
    • NameNode 是集群的主節(jié)點(diǎn),DataNode 是集群的從節(jié)點(diǎn)
  2. 分塊存儲(chǔ)(block機(jī)制)

    • HDFS 中的文件在物理上是 分塊存儲(chǔ)(block)的,塊的大小可以通過(guò)配置參數(shù)來(lái)規(guī)定
    • Hadoop2.x 版本中默認(rèn)的block大小是 128M,老版本默認(rèn)是64M
    • 切分規(guī)則:如果有兩個(gè)文件,分別是 200M 和 20M,那么第一個(gè)文件先分成兩個(gè)切片(128M + 72M),第二個(gè)文件分成一個(gè)切片(20M),共三個(gè)切片
  3. 命名空間(NameSpace)

    • HDFS

      支持傳統(tǒng)的層次型文件組織結(jié)構(gòu),用戶或者應(yīng)用程序可以創(chuàng)建目錄,然后將文件保存在這些目錄里。文件系統(tǒng)名字空間的層次結(jié)構(gòu)和大多數(shù)現(xiàn)有的文件系統(tǒng)類似:用戶可以創(chuàng)建、刪除、移動(dòng)或重命名文件

    • Namenode

      負(fù)責(zé)維護(hù)文件系統(tǒng)的名字空間,任何對(duì)文件系統(tǒng)名字空間或?qū)傩缘男薷亩紝⒈?Namenode 記錄下來(lái)

    • 抽象目錄樹

      HDFS 提供給客戶單一的一個(gè)抽象目錄樹,用戶不知道這些文件是存儲(chǔ)在哪個(gè)dataNode上

      訪問(wèn)形式:hdfs://namenode的hostname:port/test/input

      例如:hdfs://linux121:9000/test/input

  4. NameNode 元數(shù)據(jù)管理

    • 我們把 目錄結(jié)構(gòu)文件分塊位置信息 叫做元數(shù)據(jù)
    • NameNode 的元數(shù)據(jù)記錄每一個(gè)文件所對(duì)應(yīng)的 block 信息(block的 id 以及所在的 DataNode 節(jié)點(diǎn)的信息)
  5. DataNode 數(shù)據(jù)存儲(chǔ)

    • 文件的各個(gè) block 的具體存儲(chǔ)管理由 DataNode 節(jié)點(diǎn)承擔(dān)
    • 一個(gè) block 會(huì)有多個(gè) DataNode 來(lái)存儲(chǔ),DataNode 會(huì)定時(shí)向 NameNode 來(lái)匯報(bào)自己持有的 block 信息(<font color=red>這就是高容錯(cuò)的體現(xiàn),很重要</font>
  6. 副本機(jī)制

    • 為了容錯(cuò),文件的所有 block 都會(huì)有副本,默認(rèn)是 3 個(gè)(包括本來(lái)的block,一共 3 個(gè))。每個(gè)文件的 block大小副本系數(shù) 都是可配置

    • 應(yīng)用程序可以指定某個(gè)文件的副本數(shù)目,副本系數(shù)可以在文件創(chuàng)建的時(shí)候指定,也可以在之后改變

    • 如果副本數(shù)量設(shè)置為 10,但設(shè)備數(shù)只有 3臺(tái),那么不會(huì)真正創(chuàng)建 10 個(gè)副本,而是創(chuàng)建相當(dāng)于設(shè)備數(shù)量的副本,即 3個(gè)副本。等設(shè)備數(shù)增加到 10 臺(tái),創(chuàng)建的副本數(shù)才達(dá)到 10 臺(tái)(<font color=red>很重要</font>)

  7. 一次寫入,多次讀出

    • HDFS 是設(shè)計(jì)成適應(yīng) 一次寫入,多次讀出 的場(chǎng)景,且不支持文件的隨機(jī)修改(支持追加寫入,不支持隨機(jī)更新)
    • 因此,HDFS 適合用來(lái)做 大數(shù)據(jù)分析的底層存儲(chǔ)服務(wù),并不適合用來(lái)做網(wǎng)盤等應(yīng)用(修改不方便,延遲大,網(wǎng)絡(luò)開(kāi)銷大,成本太高)

4. HDFS架構(gòu)

  1. NameNode: HDFS集群的管理者,Master
  • 維護(hù)管理Hdfs的名稱空間(NameSpace)
  • 維護(hù)副本策略
  • 記錄?件塊(Block)的映射信息
  • 負(fù)責(zé)處理客戶端讀寫請(qǐng)求
  1. DataNode: NameNode下達(dá)命令,DataNode執(zhí)行實(shí)際操作,Slave節(jié)點(diǎn)。

    • 保存實(shí)際的數(shù)據(jù)塊

    • 負(fù)責(zé)數(shù)據(jù)塊的讀寫

  1. Client: 客戶端
    • 上傳?文件到HDFS的時(shí)候,Client負(fù)責(zé)將?件切分成Block,然后進(jìn)行上傳
    • 請(qǐng)求NameNode交互,獲取文件的位置信息
    • 讀取或?qū)?文件,與DataNode交互
    • Client可以使?一些命令來(lái)管理HDFS或者訪問(wèn)HDFS

二、 HDFS 客戶端操作

1. Shell命令行操作HDFS

  1. 基本語(yǔ)法

    • bin/hadoop fs 具體命令
    • bin/hdfs dfs 具體命令(<font color=red>推薦</font>)
  2. 命令?全

    [root@linux121 hadoop-2.9.2]# bin/hdfs dfs
    Usage: hadoop fs [generic options]
            [-appendToFile <localsrc> ... <dst>]
            [-cat [-ignoreCrc] <src> ...]
            [-checksum <src> ...]
            [-chgrp [-R] GROUP PATH...]
            [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
             
    [-chown [-R] [OWNER][:[GROUP]] PATH...]
            [-copyFromLocal [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
            [-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
            [-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] <path> ...]
            [-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
            [-createSnapshot <snapshotDir> [<snapshotName>]]
            [-deleteSnapshot <snapshotDir> <snapshotName>]
            [-df [-h] [<path> ...]]
            [-du [-s] [-h] [-x] <path> ...]
            [-expunge]
            [-find <path> ... <expression> ...]
            [-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
            [-getfacl [-R] <path>]
            [-getfattr [-R] {-n name | -d} [-e en] <path>]
            [-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
            [-help [cmd ...]]
            [-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [<path> ...]]
            [-mkdir [-p] <path> ...]
            [-moveFromLocal <localsrc> ... <dst>]
            [-moveToLocal <src> <localdst>]
            [-mv <src> ... <dst>]
            [-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
            [-renameSnapshot <snapshotDir> <oldName> <newName>]
            [-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
            [-rmdir [--ignore-fail-on-non-empty] <dir> ...]
            [-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec>
    <path>]]
            [-setfattr {-n name [-v value] | -x name} <path>]
            [-setrep [-R] [-w] <rep> <path> ...]
            [-stat [format] <path> ...]
            [-tail [-f] <file>]
            [-test -[defsz] <path>]
            [-text [-ignoreCrc] <src> ...]
            [-touchz <path> ...]
            [-truncate [-w] <length> <path> ...]
            [-usage [cmd ...]]
            
    Generic options supported are:
    -conf <configuration file>        specify an application configuration file
    -D <property=value>               define a value for a given property
    -fs <file:///|hdfs://namenode:port> specify default filesystem URL to use, overrides 'fs.defaultFS' property from configurations.
    -jt <local|resourcemanager:port>  specify a ResourceManager
    -files <file1,...>                specify a comma-separated list of files to be copied to the map reduce cluster
    -libjars <jar1,...>               specify a comma-separated list of jar files to be included in the classpath
    -archives <archive1,...>          specify a comma-separated list of archives to be unarchived on the compute machines
    
  1. HDFS命令演示

    • 首先啟動(dòng)Hadoop集群(HDFS和YARN要做各自的節(jié)點(diǎn)上啟動(dòng)

      [root@linux121 hadoop-2.9.2]$ sbin/start-dfs.sh
      [root@linux122 hadoop-2.9.2]$ sbin/start-yarn.sh
      
    • -help:輸出這個(gè)命令參數(shù)

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -help rm
      
    • -ls: 顯示?錄信息

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -ls /
      
    • -mkdir: 在HDFS上創(chuàng)建目錄

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -mkdir -p /lagou/bigdata
      
    • -moveFromLocal: 從本地剪切粘貼到HDFS

      [root@linux121 hadoop-2.9.2]$ touch hadoop.txt
      [root@linux121 hadoop-2.9.2]$ hdfs dfs  -moveFromLocal  ./hadoop.txt /lagou/bigdata
      
    • -appendToFile: 追加?個(gè)文件到已經(jīng)存在的?件末尾

      [root@linux121 hadoop-2.9.2]$ touch hdfs.txt
      [root@linux121 hadoop-2.9.2]$ vi hdfs.txt
      
      輸入
      namenode datanode block replication
      [root@linux121 hadoop-2.9.2]$ hdfs dfs -appendToFile hdfs.txt /lagou/bigdata/hadoop.txt
      
    • -cat: 顯示文件內(nèi)容

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -cat /lagou/bigdata/hadoop.txt
      
    • -chgrp 、-chmod、-chown: Linux?件系統(tǒng)中的?法一樣,修改文件所屬權(quán)限

       [root@linux121 hadoop-2.9.2]$ hdfs dfs  -chmod  666 /lagou/bigdata/hadoop.txt
      [root@linux121 hadoop-2.9.2]$ hdfs dfs  -chown  root:root /lagou/bigdata/hadoop.txt
      
    • -copyFromLocal: 從本地?件系統(tǒng)中拷?文件到HDFS路徑去

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -copyFromLocal README.txt /
      
    • -copyToLocal: 從HDFS拷貝到本地

       [root@linux121 hadoop-2.9.2]$ hdfs dfs -copyToLocal /lagou/bigdata/hadoop.txt ./
      
    • -cp : 從HDFS的?個(gè)路徑拷?到HDFS的另一個(gè)路徑

       [root@linux121 hadoop-2.9.2]$ hdfs dfs -cp /lagou/bigdata/hadoop.txt /hdfs.txt
      
    • -mv: 在HDFS?錄中移動(dòng)文件

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -mv /hdfs.txt /lagou/bigdata/
      
    • -get: 等同于copyToLocal,就是從HDFS下載文件到本地

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -get /lagou/bigdata/hadoop.txt ./
      
    • -put: 等同于copyFromLocal

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -mkdir -p /user/root/test/ 
      
      #本地?文件系統(tǒng)創(chuàng)建yarn.txt
      [root@linux121 hadoop-2.9.2]$ vim yarn.txt
      resourcemanager nodemanager
      [root@linux121 hadoop-2.9.2]$ hdfs dfs -put ./yarn.txt /user/root/test/
      
    • -tail: 顯示?個(gè)?件的末尾

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -tail /user/root/test/yarn.txt
      
    • -rm: 刪除?件或?件夾

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -rm /user/root/test/yarn.txt
      
    • -rmdir: 刪除空?錄

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -mkdir /test
      [root@linux121 hadoop-2.9.2]$ hdfs dfs -rmdir /test
      
    • -du: 統(tǒng)計(jì)?件夾的?小信息

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -du -s -h /user/root/test
      [root@linux121 hadoop-2.9.2]$ hdfs dfs -du  -h /user/root/test
      
    • -setrep: 設(shè)置HDFS中?件的副本數(shù)量

      [root@linux121 hadoop-2.9.2]$ hdfs dfs -setrep 10 /lagou/bigdata/hadoop.txt
      

2. JAVA客戶端

2.1 客戶端環(huán)境準(zhǔn)備

  1. 將Hadoop-2.9.2安裝包解壓到非中?路徑(例如:E:\hadoop-2.9.2)。
  1. 配置HADOOP_HOME環(huán)境變量
    image-20201130152417302.png
  1. 配置Path環(huán)境變量。
  1. 創(chuàng)建?個(gè)Maven工程ClientDemo

  2. 導(dǎo)入相應(yīng)的依賴坐標(biāo)+日志配置文件

    • 需要導(dǎo)入三個(gè)模塊:hadoop-common、hadoopclient、hadoop-hdfs

      <dependencies>
        
        <!-- 導(dǎo)入三個(gè)模塊:hadoop-common、hadoopclient、hadoop-hdfs -->
        
        <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-common -->
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-common</artifactId>
             <version>2.9.2</version>
         </dependency>
        
         <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoopclient -->
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-client</artifactId>
             <version>2.9.2</version>
         </dependency>
        
         <!-- https://mvnrepository.com/artifact/org.apache.hadoop/hadoop-hdfs -->
         <dependency>
             <groupId>org.apache.hadoop</groupId>
             <artifactId>hadoop-hdfs</artifactId>
             <version>2.9.2</version>
         </dependency>
        
        <!-- 單元測(cè)試 -->
        <dependency>
             <groupId>junit</groupId>
         <artifactId>junit</artifactId>
             <version>RELEASE</version>
         </dependency>
        
        <!-- 日志打印 -->
         <dependency>
             <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-core</artifactId>
             <version>2.8.2</version>
         </dependency>
      
      </dependencies>
      
    • 為了便于控制程序運(yùn)行打印的日志數(shù)量,需要在項(xiàng)目的 src/main/resources 目錄下,新建一個(gè)文件,命名為 log4j.properties,文件內(nèi)容如下:

      log4j.rootLogger=INFO, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
      log4j.appender.logfile=org.apache.log4j.FileAppender
      log4j.appender.logfile.File=target/spring.log
      log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
      log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
      
  3. 創(chuàng)建包名:com.lagou.hdfs

  4. 創(chuàng)建HdfsClient類

     public class HdfsClient{
        @Test
        public void testMkdirs() throws IOException, InterruptedException, URISyntaxException {
            // 1 獲取?件系統(tǒng)
            Configuration configuration = new Configuration();
            // 配置在集群上運(yùn)行
            // configuration.set("fs.defaultFS", "hdfs://linux121:9000");
            // FileSystem fs = FileSystem.get(configuration);
            FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"),
            configuration, "root");
            // 2 創(chuàng)建目錄
            fs.mkdirs(new Path("/test"));
            // 3 關(guān)閉資源
            fs.close();
     }
    }
    

會(huì)遇到的問(wèn)題:

  1. 如果不指定操作 HDFS 集群的用戶信息,默認(rèn)是 獲取當(dāng)前操作系統(tǒng)的用戶信息,出現(xiàn)權(quán)限被拒絕的問(wèn)題,報(bào)錯(cuò)如下:

出現(xiàn)問(wèn)題的原因:

由于 HDFS 的權(quán)限管理機(jī)制是:用戶告訴 hdfs 自己是什么用戶,hdfs 都會(huì)相信,認(rèn)為用戶不會(huì)做壞事。HDFS?件權(quán)限的目的,防?好?做錯(cuò)事,?不是阻?壞人做壞事。HDFS相信你告訴我你是誰(shuí),你就是誰(shuí)。因此這種權(quán)限管理比較雞肋

解決辦法:

  1. 把 根目錄 的權(quán)限設(shè)置為 777 ,關(guān)于文件權(quán)限管理 交給其他軟件去做

    hdfs dfs -R 777 /
    
  2. 在配置文件 hdfs-site.xml 中添加以下屬性,以關(guān)閉 HDFS 集群權(quán)限校驗(yàn),修改完成之后要分發(fā)到其它節(jié)點(diǎn),同時(shí)要重啟HDFS集群

    vim hdfs-site.xml
    
    #添加如下屬性
    <property>
         <name>dfs.permissions.enabled</name>
         <value>false</value>
    </property>
    
  3. 指定用戶信息獲取 FileSystem 對(duì)象

    FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root")
    
  1. windows 解壓安裝 Hadoop后,在調(diào)用相關(guān)API操作 HDFS 集群時(shí)可能會(huì)報(bào)錯(cuò),如下圖:
    image-20201130153945039.png

出現(xiàn)問(wèn)題的原因:

這是由于 Hadoop 安裝缺少 windows 操作系統(tǒng)相關(guān)文件所致

解決辦法:

將 winutils.exe 拷貝到 windows 系統(tǒng) Hadoop 安裝目錄的 bin 目錄下即可

  1. IDEA 啟動(dòng) Hadoop 的任務(wù)時(shí),出現(xiàn)如下報(bào)錯(cuò):

解決辦法:

將 Hadoop.dll 文件 添加到 C:\Windows\System32 中

參數(shù)的優(yōu)先級(jí)

當(dāng)在配置文件,java 代碼中,包括hdfs服務(wù)器的默認(rèn)配置,都設(shè)置副本數(shù)量時(shí),參數(shù)的優(yōu)先級(jí)是:

<font color=red>代碼中設(shè)置的值 -->用戶自定義配置文件 -->服務(wù)?的默認(rèn)配置</font>

2.2 HDFS的API操作

  1. 上傳文件

    • 可通過(guò) configuration.set("dfs.replication", "2") 設(shè)置副本數(shù)量

      @Test
      public void testCopyFromLocalFile() throws IOException, InterruptedException, URISyntaxException {
      
          // 1 獲取?文件系統(tǒng)
         Configuration configuration = new Configuration();
         configuration.set("dfs.replication", "2");
         FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
      
          // 2上傳?文件
         fs.copyFromLocalFile(new Path("e:/lagou.txt"), new Path("/lagou.txt"));
      
          // 3 關(guān)閉資源
         fs.close();
      }
      
    • 也可通過(guò) 配置文件 hdfs-site.xml 來(lái)指定,文件放在 resources 目錄下

      <font color=red>注:配置文件名 不能寫錯(cuò)??!</font>

      <?xml version="1.0" encoding="UTF-8"?>
      <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
      
      <configuration>
          <property>
              <name>dfs.replication</name>
              <value>1</value>
          </property>
      </configuration>
      
  2. 下載文件

    @Test
    public void testCopyToLocalFile() throws IOException, InterruptedException, URISyntaxException{
    
        // 1 獲取?文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 執(zhí)?行行下載操作
     // boolean delSrc 指是否將原?文件刪除
     // Path src 指要下載的?文件路路徑
     // Path dst 指將?文件下載到的路路徑
     // boolean useRawLocalFileSystem 是否開(kāi)啟?文件校驗(yàn)
     fs.copyToLocalFile(false, new Path("/lagou.txt"), newPath("e:/lagou_copy.txt"), true);
        
        // 3 關(guān)閉資源
     fs.close();
    }
    
  3. 刪除文件/文件夾

    @Test
    public void testDelete() throws IOException, InterruptedException, URISyntaxException{
    
        // 1 獲取?文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 執(zhí)?行行刪除
     fs.delete(new Path("/api_test/"), true);
    
        // 3 關(guān)閉資源
     fs.close();
    }
    
  4. HDFS文件名更改

    @Test
    public void testRename() throws IOException, InterruptedException, URISyntaxException{
    
     // 1 獲取文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
         
     // 2 修改文件名稱
     fs.rename(new Path("/banzhang.txt"), new Path("/banhua.txt"));
         
     // 3 關(guān)閉資源
     fs.close();
    }
    
    
  5. 查看 文件名稱、權(quán)限、長(zhǎng)度、塊信息

    @Test
    public void testListFiles() throws IOException, InterruptedException, URISyntaxException{
    
        // 1獲取?文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 獲取?文件詳情
     RemoteIterator<LocatedFileStatus> listFiles = fs.listFiles(new Path("/"), true);
     
        while(listFiles.hasNext()){
         LocatedFileStatus status = listFiles.next();
         // 輸出詳情
    
            // ?文件名稱
         System.out.println(status.getPath().getName());
    
            // ?長(zhǎng)度
         System.out.println(status.getLen());
        
            // 權(quán)限
         System.out.println(status.getPermission());
    
            // 分組
         System.out.println(status.getGroup());
    
            // 獲取存儲(chǔ)的塊信息
         BlockLocation[] blockLocations = status.getBlockLocations();
         for (BlockLocation blockLocation : blockLocations) {
         
                // 獲取塊存儲(chǔ)的主機(jī)節(jié)點(diǎn)
             String[] hosts = blockLocation.getHosts();
             for (String host : hosts) {
                 System.out.println(host);
             }
         }
    
            System.out.println("-----------華麗的分割線----------");
     }
    
        // 3 關(guān)閉資源
     fs.close();
    } 
    
  6. 區(qū)分文件和文件夾

    @Test
    public void testListStatus() throws IOException, InterruptedException, URISyntaxException{
    
        // 1 獲取?文件配置信息
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 判斷是?文件還是?文件夾
     FileStatus[] listStatus = fs.listStatus(new Path("/"));
     for (FileStatus fileStatus : listStatus) {
         // 如果是?文件
         if (fileStatus.isFile()){ 
                System.out.println("f:"+fileStatus.getPath().getName());
            } else{ 
                System.out.println("d:"+fileStatus.getPath().getName());         
            }
     }
    
         // 3 關(guān)閉資源
     fs.close();
    }
    
  7. 文件上傳 create

    將本地文件上傳到 hdfs 上

    @Test
    public void putFileToHDFS() throws IOException, InterruptedException, URISyntaxException {
    
        // 1 獲取文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 創(chuàng)建輸?流
     FileInputStream fis = new FileInputStream(new File("e:/lagou.txt"));
    
        // 3 獲取輸出流
     FSDataOutputStream fos = fs.create(new Path("/lagou_io.txt"));
    
        // 4 流的拷貝
     IOUtils.copyBytes(fis, fos, configuration);
    
        // 5 關(guān)閉資源(這里其實(shí)不需要關(guān)閉)
     IOUtils.closeStream(fos);
     IOUtils.closeStream(fis);
     fs.close();
    }
    
  8. 文件下載 open

    將 hdfs 文件下載到本地

    @Test
    public void getFileFromHDFS() throws IOException, InterruptedException, URISyntaxException{
    
        // 1 獲取?文件系統(tǒng)
        Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
    
        // 2 獲取輸?入流
     FSDataInputStream fis = fs.open(new Path("/lagou_io.txt"));
    
        // 3 獲取輸出流
     FileOutputStream fos = new FileOutputStream(new File("e:/lagou_io_copy.txt"));
    
        // 4 流的對(duì)拷
     IOUtils.copyBytes(fis, fos, configuration);
    
        // 5 關(guān)閉資源
     IOUtils.closeStream(fos);
     IOUtils.closeStream(fis);
     fs.close();
    }
    
  9. 定位讀取 seek

    將 HDFS上 的 lagou.txt 的內(nèi)容在控制臺(tái)輸出兩次

    @Test
    public void readFileSeek2() throws IOException, InterruptedException, URISyntaxException{
    
        // 1 獲取?文件系統(tǒng)
     Configuration configuration = new Configuration();
     FileSystem fs = FileSystem.get(new URI("hdfs://linux121:9000"), configuration, "root");
     
        // 2 打開(kāi)輸?入流,讀取數(shù)據(jù)輸出到控制臺(tái)
     FSDataInputStream in = null;
     try{
         in = fs.open(new Path("/lagou.txt"));
         IOUtils.copyBytes(in, System.out, 4096, false);
         
            //從頭再次讀取,偏移量為0 表示從頭讀起
            in.seek(0); 
         IOUtils.copyBytes(in, System.out, 4096, false);
     }finally {
         IOUtils.closeStream(in);
            fs.close();
     }
    }
    

三、 HDFS讀寫解析

1. HDFS讀數(shù)據(jù)流程

HDFS讀數(shù)據(jù)流程:

  1. 客戶端通過(guò)Distributed FileSystemNameNode請(qǐng)求下載文件,NameNode通過(guò)查詢?cè)獢?shù)據(jù),找到文件塊所在的DataNode地址。
  2. 挑選一臺(tái)DataNode(就近原則,然后隨機(jī))服務(wù)器,請(qǐng)求讀取數(shù)據(jù)。
  3. DataNode開(kāi)始傳輸數(shù)據(jù)給客戶端(從磁盤里面讀取數(shù)據(jù)輸入流,以Packet(64KB)為單位來(lái)做校驗(yàn))。
  4. 客戶端以Packet為單位接收,先在本地緩存,然后寫入目標(biāo)文件。

2.HDFS寫數(shù)據(jù)流程

HDFS寫數(shù)據(jù)流程:

  1. 客戶端通過(guò)Distributed FileSystem模塊向NameNode請(qǐng)求上傳文件,NameNode檢查目標(biāo)文件是否已存在,父目錄是否存在。
  2. NameNode返回是否可以上傳。
  3. 客戶端請(qǐng)求第一個(gè) Block上傳到哪幾個(gè)DataNode服務(wù)器上。
  4. NameNode返回3個(gè)DataNode節(jié)點(diǎn),分別為dn1、dn2、dn3。
  5. 客戶端通過(guò)FSDataOutputStream模塊請(qǐng)求dn1上傳數(shù)據(jù),dn1收到請(qǐng)求會(huì)繼續(xù)調(diào)用dn2,然后dn2調(diào)用dn3,將這個(gè)通信管道建立完成。
  6. dn1、dn2、dn3逐級(jí)應(yīng)答客戶端。
  7. 客戶端開(kāi)始往dn1上傳第一個(gè)Block(先從磁盤讀取數(shù)據(jù)放到一個(gè)本地內(nèi)存緩存),以Packet(64KB)為單位,dn1收到一個(gè)Packet就會(huì)傳給dn2,dn2傳給dn3;dn1每傳一個(gè)packet會(huì)放入一個(gè)應(yīng)答隊(duì)列等待應(yīng)答。
  8. 當(dāng)一個(gè)Block傳輸完成之后,客戶端再次請(qǐng)求NameNode上傳第二個(gè)Block的服務(wù)器。(重復(fù)執(zhí)行3-7步)。

驗(yàn)證Packet代碼:

  • @Test
    public void testUploadPacket() throws IOException {
        //1 準(zhǔn)備讀取本地文件的輸入流
        final FileInputStream in = new FileInputStream(new File("e:/lagou.txt"));
        //2 準(zhǔn)備好寫出數(shù)據(jù)到hdfs的輸出流
        final FSDataOutputStream out = fs.create(new Path("/lagou.txt"), new Progressable() {
            public void progress() {
                //這個(gè)progress?法就是每傳輸64KB(packet)就會(huì)執(zhí)行一次
                System.out.println("&");
            }
        });
        //3 實(shí)現(xiàn)流拷貝
        IOUtils.copyBytes(in, out, configuration);
        //默認(rèn)關(guān)閉流選項(xiàng)是true,所以會(huì)?動(dòng)關(guān)閉
        //4 關(guān)流 可以再次關(guān)閉也可以不關(guān)了
    }
    

四、 NameNode和SecondaryNameNode

1. NN和2NN工作機(jī)制

問(wèn)題引出: NameNode如何管理和存儲(chǔ)元數(shù)據(jù)?

計(jì)算機(jī)中存儲(chǔ)數(shù)據(jù)的兩種方式:磁盤、內(nèi)存

  • 元數(shù)據(jù)存儲(chǔ)磁盤:存儲(chǔ)磁盤?法?對(duì)客戶端對(duì)元數(shù)據(jù)信息的隨機(jī)訪問(wèn),還有響應(yīng)客戶請(qǐng)求,必然是效率過(guò)低。但是安全性?
  • 元數(shù)據(jù)存儲(chǔ)內(nèi)存:元數(shù)據(jù)存放內(nèi)存,可以高效的查詢以及快速響應(yīng)客戶端的查詢請(qǐng)求,數(shù)據(jù)保存在內(nèi)存,如果斷點(diǎn),內(nèi)存中的數(shù)據(jù)全部丟失。安全性低

解決辦法: 內(nèi)存+磁盤;NameNode內(nèi)存+FsImage的?件(磁盤)

新問(wèn)題: 磁盤和內(nèi)存中元數(shù)據(jù)如何劃分?

兩個(gè)數(shù)據(jù)一模?樣,還是兩個(gè)數(shù)據(jù)合并到一起才是?份完整的數(shù)據(jù)呢?

  • 如果兩份數(shù)據(jù)一模一樣的話,客戶端 Client 如果對(duì)元數(shù)據(jù)進(jìn)行增刪改操作,則需要時(shí)刻保證兩份數(shù)據(jù)的一致性,導(dǎo)致效率變低
  • 如果兩份數(shù)據(jù)合并后 ==> 完整數(shù)據(jù)的情況。NameNode 引入了 edits 文件(日志文件,只能追加寫入),記錄了client 的增刪改操作,而不再讓 NameNode 把數(shù)據(jù) dump 出來(lái)形成 fsimage文件(讓 NameNode 專注于處理客戶端的請(qǐng)求)
  • edits文件:文件生成快,恢復(fù)慢;fsimage文件:文件生成慢,恢復(fù)快

新問(wèn)題: 誰(shuí)來(lái)負(fù)責(zé)文件合并?

如果長(zhǎng)時(shí)間添加數(shù)據(jù)到Edits中,會(huì)導(dǎo)致該文件數(shù)據(jù)過(guò)大,效率降低,而且一旦斷電,恢復(fù)元數(shù)據(jù)需要的時(shí)間過(guò)長(zhǎng)。因此,需要定期進(jìn)行FsImage和Edits的合并,但是誰(shuí)來(lái)合并?

  • NameNode:NameNode本身任務(wù)重,再負(fù)責(zé)合并,勢(shì)必效率過(guò)低,甚至?xí)绊懕旧淼娜蝿?wù)
  • 因此,引入一個(gè)新的節(jié)點(diǎn)SecondaryNamenode,專門用于FsImage和Edits的合并。

流程分析:

  1. 第一階段:NameNode啟動(dòng)
    1. 第一次啟動(dòng)NameNode格式化后,創(chuàng)建Fsimage和Edits文件。如果不是第一次啟動(dòng),直接加載編輯日志和鏡像文件到內(nèi)存。
    2. 客戶端對(duì)元數(shù)據(jù)進(jìn)行增刪改的請(qǐng)求。
    3. NameNode記錄操作日志,更新滾動(dòng)日志(所謂滾動(dòng)日志,即 把前一階段的日志保存成一個(gè)日志文件,再新生成一個(gè)文件,新生成文件后綴帶有 inprogress 字樣)。
    4. NameNode在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行增刪改。
  2. 第二階段:Secondary NameNode工作
    1. Secondary NameNode詢問(wèn)NameNode是否需要CheckPoint。直接帶回NameNode是否檢查結(jié)果。
    2. Secondary NameNode請(qǐng)求執(zhí)行CheckPoint。
    3. NameNode滾動(dòng)正在寫的Edits日志。
    4. 將滾動(dòng)前的編輯日志和鏡像文件拷貝到Secondary NameNode。
    5. Secondary NameNode加載編輯日志和鏡像文件到內(nèi)存,并合并。
    6. 生成新的鏡像文件fsimage.chkpoint。
    7. 拷貝fsimage.chkpoint到NameNode。
    8. NameNode將fsimage.chkpoint重新命名成fsimage。

<font color=red>NN和2NN工作機(jī)制詳解:</font>

  • Fsimage:NameNode內(nèi)存中元數(shù)據(jù)序列化后形成的文件。

  • Edits:記錄客戶端更新元數(shù)據(jù)信息的每一步操作(可通過(guò)Edits運(yùn)算出元數(shù)據(jù))。

  • NameNode啟動(dòng)時(shí),先滾動(dòng)Edits并生成一個(gè)空的edits.inprogress,然后加載Edits和Fsimage到內(nèi)存中,此時(shí)NameNode內(nèi)存就持有最新的元數(shù)據(jù)信息。Client開(kāi)始對(duì)NameNode發(fā)送元數(shù)據(jù)的增刪改的請(qǐng)求,這些請(qǐng)求的操作首先會(huì)被記錄到edits.inprogress中(查詢?cè)獢?shù)據(jù)的操作不會(huì)被記錄在Edits中,因?yàn)椴樵儾僮鞑粫?huì)更改元數(shù)據(jù)信息),如果此時(shí)NameNode掛掉,重啟后會(huì)從Edits中讀取元數(shù)據(jù)的信息。然后,NameNode會(huì)在內(nèi)存中執(zhí)行元數(shù)據(jù)的增刪改的操作。

  • 由于Edits中記錄的操作會(huì)越來(lái)越多,Edits文件會(huì)越來(lái)越大,導(dǎo)致NameNode在啟動(dòng)加載Edits時(shí)會(huì)很慢,所以需要對(duì)Edits和Fsimage進(jìn)行合并(所謂合并,就是將Edits和Fsimage加載到內(nèi)存中,照著Edits中的操作一步步執(zhí)行,最終形成新的Fsimage)。SecondaryNameNode的作用就是幫助NameNode進(jìn)行Edits和Fsimage的合并工作。

  • SecondaryNameNode首先會(huì)詢問(wèn)NameNode是否需要CheckPoint(觸發(fā)CheckPoint需要滿足兩個(gè)條件中的任意一個(gè),定時(shí)時(shí)間到和Edits中數(shù)據(jù)寫滿了)。直接帶回NameNode是否檢查結(jié)果。SecondaryNameNode執(zhí)行CheckPoint操作,首先會(huì)讓NameNode滾動(dòng)Edits并生成一個(gè)空的edits.inprogress,滾動(dòng)Edits的目的是給Edits打個(gè)標(biāo)記,以后所有新的操作都寫入edits.inprogress,其他未合并的Edits和Fsimage會(huì)拷貝到SecondaryNameNode的本地,然后將拷貝的Edits和Fsimage加載到內(nèi)存中進(jìn)行合并,生成fsimage.chkpoint,然后將fsimage.chkpoint拷貝給NameNode,重命名為Fsimage后替換掉原來(lái)的Fsimage。NameNode在啟動(dòng)時(shí)就只需要加載之前未合并的Edits和Fsimage即可,因?yàn)楹喜⑦^(guò)的Edits中的元數(shù)據(jù)信息已經(jīng)被記錄在Fsimage中。

2. Fsimage和Edits解析

  • NameNode在執(zhí)行格式化之后,會(huì)在/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/current?錄下產(chǎn)?如下文件
    • Fsimage?件: 是namenode中關(guān)于元數(shù)據(jù)的鏡像,一般稱為檢查點(diǎn),這里包含了HDFS?件系統(tǒng)所有?錄以及?件相關(guān)信息(Block數(shù)量,副本數(shù)量,權(quán)限等信息)
    • Edits文件 : 存儲(chǔ)了客戶端對(duì)HDFS文件系統(tǒng)所有的更新操作記錄,Client對(duì)HDFS?件系統(tǒng)所有的更新操作都會(huì)被記錄到Edits?件中(不包括查詢操作)
    • seen_txid: 該?件是保存了一個(gè)數(shù)字,數(shù)字對(duì)應(yīng)著最后一個(gè)Edits?件名的數(shù)字
    • VERSION: 該?件記錄namenode的一些版本號(hào)信息,比如:CusterId,namespaceID等
  • NameNode啟動(dòng)時(shí)會(huì)將Fsimage?件加載到內(nèi)存中,同時(shí)也把之前未合并元數(shù)據(jù)的Edits?件加載,集合兩個(gè)文件中的元數(shù)據(jù)這樣保證了NameNode中的元數(shù)據(jù)是最新最全的。通俗點(diǎn)說(shuō)就是NameNode啟動(dòng)時(shí)把Fsimage和Edits?件進(jìn)?了合并。

2.1 Fsimage?件內(nèi)容

  1. 官方地址:https://hadoop.apache.org/docs/r2.9.2/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html

  2. 查看oiv和oev命令

    [[root@linux121 current]$ hdfs
    oiv            apply the offline fsimage viewer to an fsimage
    oev            apply the offline edits viewer to an edits file
    
  3. 基本語(yǔ)法

    hdfs oiv -p 文件類型 -i鏡像文件 -o 轉(zhuǎn)換后文件輸出路徑
    
  4. 案例實(shí)操

    [root@linux121 current]$ cd /opt/lagou/servers/hadoop2.9.2/data/tmp/dfs/name/current
    [root@linux121 current]$ hdfs oiv -p XML -i fsimage_0000000000000000265 -o /opt/lagou/servers/fsimage.xml
    [root@linux121 current]$ cat /opt/lagou/servers/fsimage.xml
    
  5. 查看文件

    <?xml version="1.0"?>
    <fsimage>
        <version>
            <layoutVersion>-63</layoutVersion>
            <onDiskVersion>1</onDiskVersion>
            <oivRevision>826afbeae31ca687bc2f8471dc841b66ed2c6704</oivRevision>
        </version>
        <NameSection>
            <namespaceId>722925838</namespaceId>
            <genstampV1>1000</genstampV1>
            <genstampV2>1049</genstampV2>
            <genstampV1Limit>0</genstampV1Limit>
            <lastAllocatedBlockId>1073741873</lastAllocatedBlockId>
            <txid>621</txid>
        </NameSection>
        <INodeSection>
            <lastInodeId>16487</lastInodeId>
            <numInodes>36</numInodes>
            <inode>
                <id>16385</id>
                <type>DIRECTORY</type>
                <name></name>
                <mtime>1604115316122</mtime>
                <permission>root:supergroup:0777</permission>
                <nsquota>9223372036854775807</nsquota>
                <dsquota>-1</dsquota>
            </inode>
            <inode>
                <id>16389</id>
                <type>DIRECTORY</type>
                <name>wcinput</name>
                <mtime>1604023034981</mtime>
                <permission>root:supergroup:0777</permission>
                <nsquota>-1</nsquota>
                <dsquota>-1</dsquota>
            </inode> 
          </INodeSection>
    </fsimage>
    

    問(wèn)題: Fsimage 中為什么沒(méi)有記錄塊所對(duì)應(yīng) DataNode ?

    答案:在集群?jiǎn)?dòng)后,NameNode 要求 DataNode 上報(bào)數(shù)據(jù)塊信息,并間隔一段時(shí)間后再次上報(bào)

2.2 Edits文件內(nèi)容

  1. 基本語(yǔ)法

    hdfs oev -p 文件類型 -i編輯日志 -o 轉(zhuǎn)換后文件輸出路徑
    
  2. 案例實(shí)操

    [root@linux121 current]$ hdfs oev -p XML -i edits_0000000000000000266-0000000000000000267 -o /opt/lagou/servers/hadoop-2.9.2/edits.xml
    [root@linux121 current]$ cat /opt/lagou/servers/hadoop-2.9.2/edits.xml
    
  3. 查看文件

    <?xml version="1.0" encoding="utf-8"?>
    
    <EDITS> 
      <EDITS_VERSION>-63</EDITS_VERSION>  
      <RECORD> 
        <OPCODE>OP_START_LOG_SEGMENT</OPCODE>  
        <DATA> 
          <TXID>113</TXID> 
        </DATA> 
      </RECORD>  
      <RECORD> 
        <OPCODE>OP_SET_PERMISSIONS</OPCODE>  
        <DATA> 
          <TXID>114</TXID>  
          <SRC>/wcoutput/_SUCCESS</SRC>  
          <MODE>493</MODE> 
        </DATA> 
      </RECORD>  
      <RECORD> 
        <OPCODE>OP_SET_PERMISSIONS</OPCODE>  
        <DATA> 
          <TXID>115</TXID>  
          <SRC>/wcoutput/part-r-00000</SRC>  
          <MODE>493</MODE> 
        </DATA> 
      </RECORD> 
    </EDITS>
    ...
    

    備注:Edits中只記錄了更新相關(guān)的操作,查詢或者下載文件并不會(huì)記錄在內(nèi)!!

    問(wèn)題: NameNode啟動(dòng)時(shí)如何確定加載哪些Edits?件呢?

    答案: 需要借助fsimage?件最后數(shù)字編碼,來(lái)確定哪些edits之前是沒(méi)有合并到fsimage中,啟動(dòng)時(shí)只需要加載那些未合并的edits?件即可。

3. checkpoint周期

  1. 通常情況下,SecondaryNameNode每隔一小時(shí)執(zhí)行一次。

    官方默認(rèn)配置文件:hdfs-default.xml

    <property>
      <name>dfs.namenode.checkpoint.period</name>
      <value>3600</value>
    </property>
    
  2. 一分鐘檢查一次操作次數(shù),3當(dāng)操作次數(shù)達(dá)到1百萬(wàn)時(shí),SecondaryNameNode執(zhí)行一次。

    <property>
      <name>dfs.namenode.checkpoint.txns</name>
      <value>1000000</value>
    <description>操作動(dòng)作次數(shù)</description>
    </property>
    
    <property>
      <name>dfs.namenode.checkpoint.check.period</name>
      <value>60</value>
    <description> 1分鐘檢查一次操作次數(shù)</description>
    </property >
    

4. NameNode故障處理

NameNode故障后,HDFS集群就無(wú)法正常工作,因?yàn)镠DFS文件系統(tǒng)的元數(shù)據(jù)需要由NameNode來(lái)管理維護(hù)并與Client交互,如果元數(shù)據(jù)出現(xiàn)損壞和丟失同樣會(huì)導(dǎo)致NameNode?法正常?作進(jìn)?HDFS?件系統(tǒng)?法正常對(duì)外提供服務(wù)。

如果元數(shù)據(jù)出現(xiàn)丟失損壞如何恢復(fù)呢?

  1. 搭建HDFS的HA(?可用)集群,解決NN的單點(diǎn)故障問(wèn)題!!(借助Zookeeper實(shí)現(xiàn)HA,一個(gè) Active的NameNode,一個(gè)是Standby的NameNode)

  2. 將SecondaryNameNode中數(shù)據(jù)拷貝到NameNode存儲(chǔ)數(shù)據(jù)的目錄

    • kill -9 NameNode進(jìn)程

    • 刪除NameNode存儲(chǔ)的數(shù)據(jù)(/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name)

      [root@linux121 hadoop-2.9.2]rm -rf /opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/*
      
    • 拷貝SecondaryNameNode中數(shù)據(jù)到原NameNode存儲(chǔ)數(shù)據(jù)目錄

      [root@linux121 hadoop-2.9.2]$ scp -r atguigu@hadoop104:/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/namesecondary/* ./name/
      
    • 重新啟動(dòng)NameNode

    [root@linux121 hadoop-2.9.2]$ sbin/hadoop-daemon.sh start namenode
    
  3. 使用-importCheckpoint選項(xiàng)啟動(dòng)NameNode守護(hù)進(jìn)程,從而將SecondaryNameNode中數(shù)據(jù)拷貝到NameNode目錄中。

    • 修改hdfs-site.xml中的

      <property>
        <name>dfs.namenode.checkpoint.period</name>
        <value>120</value>
      </property>
      
      <property>
        <name>dfs.namenode.name.dir</name>
        <value>/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name</value>
      </property>
      
      
    • kill -9 NameNode進(jìn)程

    • 刪除NameNode存儲(chǔ)的數(shù)據(jù)(/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name)

      [root@linux121 hadoop-2.9.2]rm -rf /opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/name/*
      
    • 如果SecondaryNameNode不和NameNode在一個(gè)主機(jī)節(jié)點(diǎn)上,需要將SecondaryNameNode存儲(chǔ)數(shù)據(jù)的目錄拷貝到NameNode存儲(chǔ)數(shù)據(jù)的平級(jí)目錄,并刪除in_use.lock文件

      [root@linux123 dfs]$ scp -r root@linux121:/opt/lagou/servers/hadoop-2.9.2/data/tmp/dfs/namesecondary ./
      
      [root@linux123 namesecondary]$ rm -rf in_use.lock
      
      [root@linux123 dfs]$ pwd
      /opt/lagou/servers/hadoop-2.9.2//data/tmp/dfs
      
      [root@linux123 dfs]$ ls
      data  name  namesecondary
      
      
    • 導(dǎo)入檢查點(diǎn)數(shù)據(jù)(等待一會(huì)ctrl+c結(jié)束掉)

      [root@linux121 hadoop-2.9.2]$ bin/hdfs namenode -importCheckpoint
      
    • 啟動(dòng)NameNode

      [root@linux121 hadoop-2.9.2]$ sbin/hadoop-daemon.sh start namenode
      

五、Hadoop的限額與歸檔以及集群安全模式

1. HDFS?件限額配置

HDFS文件的限額配置允許我們以?件?小或者文件個(gè)數(shù)來(lái)限制我們?cè)谀硞€(gè)目錄下上傳的文件數(shù)量或者文件內(nèi)容總量,以便達(dá)到我們類似百度網(wǎng)盤等限制每個(gè)?戶允許上傳的最大的?件的量

  1. 數(shù)量限額

    #創(chuàng)建hdfs?件夾
    hdfs dfs -mkdir -p /user/root/lagou
    
    # 給該?件夾下?設(shè)置最多上傳兩個(gè)文件,上傳?件,發(fā)現(xiàn)只能上傳一個(gè)文件
    hdfs dfsadmin -setQuota 2 /user/root/lagou 
    
    # 清除文件數(shù)量限制
    hdfs dfsadmin -clrQuota /user/root/lagou
    
  2. 空間?小限額

    # 限制空間?小4KB
    hdfs dfsadmin -setSpaceQuota 4k /user/root/lagou
    
    #上傳超過(guò)4Kb的?件?小上去提示文件超過(guò)限額
    hdfs dfs -put /export/softwares/xxx.tar.gz /user/root/lagou
    
    #清除空間限額
    hdfs dfsadmin -clrSpaceQuota /user/root/lagou
    
    #查看hdfs?件限額數(shù)量
    hdfs dfs -count -q -h /user/root/lagou
    

2. HDFS的安全模式

  1. 安全模式是HDFS所處的一種特殊狀態(tài),在這種狀態(tài)下,<font color=red>文件系統(tǒng)只接受讀數(shù)據(jù)請(qǐng)求,而不接受刪除、修改等變更請(qǐng)求</font>。在NameNode主節(jié)點(diǎn)啟動(dòng)時(shí),HDFS?先進(jìn)入安全模式,DataNode在啟動(dòng)的時(shí)候會(huì)向NameNode匯報(bào)可用的block等狀態(tài),當(dāng)整個(gè)系統(tǒng)達(dá)到安全標(biāo)準(zhǔn)時(shí),HDFS自動(dòng)離開(kāi)安全模式。如果HDFS出于安全模式下,則文件block不能進(jìn)行任何的副本復(fù)制操作,因此達(dá)到最?的副本數(shù)量要求是基于DataNode啟動(dòng)時(shí)的狀態(tài)來(lái)判定的,啟動(dòng)時(shí)不會(huì)再做任何復(fù)制(從?達(dá)到最?副本數(shù)量要求),HDFS集群剛啟動(dòng)的時(shí)候,默認(rèn)30S鐘的時(shí)間是出于安全期的,只有過(guò)了30S之后,集群脫離了了安全期,然后才可以對(duì)集群進(jìn)行操作。
  2. 相關(guān)命令:hdfs dfsadmin -safemode

3. Hadoop歸檔技術(shù)

  1. 主要解決HDFS集群存在?量?文件的問(wèn)題!!

    由于?量?文件會(huì)占?NameNode的內(nèi)存,因此對(duì)于HDFS來(lái)說(shuō)存儲(chǔ)?量?文件造成NameNode內(nèi)存資源的浪費(fèi)!

  2. Hadoop存檔?件HAR文件,是?個(gè)更高效的文件存檔工具,HAR?件是由?組文件通過(guò)archive?具創(chuàng)建?來(lái),在減少了NameNode的內(nèi)存使?的同時(shí),可以對(duì)文件進(jìn)行透明的訪問(wèn),通俗來(lái)說(shuō)就是HAR?件對(duì)NameNode來(lái)說(shuō)是?個(gè)?件減少了內(nèi)存的浪費(fèi),對(duì)于實(shí)際操作處理文件依然是一個(gè)?個(gè)獨(dú)立的文件。
  1. 案例

    1. 啟動(dòng)YARN集群

      [root@linux121 hadoop-2.9.2]$ start-yarn.sh
      
    2. 歸檔文件

      把/user/lagou/input?錄?面的所有?件歸檔成?個(gè)叫input.har的歸檔?件,并把歸檔后文件存儲(chǔ)到/user/lagou/output路徑下。

       [root@linux121 hadoop-2.9.2]$ bin/hadoop archive -archiveName input.har –p /user/root/input  /user/root/output
      
    3. 查看歸檔

      [root@linux121 hadoop-2.9.2]$ hadoop fs -lsr /user/root/output/input.har
      [root@linux121 hadoop-2.9.2]$ hadoop fs -lsr har:///user/root/output/input.har
      
    4. 解歸檔?件

      [root@linux121 hadoop-2.9.2]$ hadoop fs -cp har:///user/root/output/input.har/*  /user/root
      

六、DataNode

1. DataNode工作機(jī)制

DataNode工作機(jī)制:

  1. 一個(gè)數(shù)據(jù)塊在DataNode上以文件形式存儲(chǔ)在磁盤上,包括兩個(gè)文件,一個(gè)是數(shù)據(jù)本身,一個(gè)是元數(shù)據(jù)包括數(shù)據(jù)塊的長(zhǎng)度,塊數(shù)據(jù)的校驗(yàn)和,以及時(shí)間戳。
  2. DataNode啟動(dòng)后向NameNode注冊(cè),通過(guò)后,周期性(1小時(shí))的向NameNode上報(bào)所有的塊信息。
  3. 心跳是每3秒一次,心跳返回結(jié)果帶有NameNode給該DataNode的命令如復(fù)制塊數(shù)據(jù)到另一臺(tái)機(jī)器,或刪除某個(gè)數(shù)據(jù)塊。如果超過(guò)10分鐘沒(méi)有收到某個(gè)DataNode的心跳,則認(rèn)為該節(jié)點(diǎn)不可用。
  4. 集群運(yùn)行中可以安全加入和退出一些機(jī)器。

2. 數(shù)據(jù)完整性

  1. 思考:

    如果電腦磁盤里面存儲(chǔ)的數(shù)據(jù)是控制高鐵信號(hào)燈的紅燈信號(hào)(1)和綠燈信號(hào)(0),但是存儲(chǔ)該數(shù)據(jù)的磁盤壞了,一直顯示是綠燈,是否很危險(xiǎn)?同理DataNode節(jié)點(diǎn)上的數(shù)據(jù)損壞了,卻沒(méi)有發(fā)現(xiàn),是否也很危險(xiǎn),那么如何解決呢?

  2. DataNode節(jié)點(diǎn)保證數(shù)據(jù)完整性的方法:

    1. 當(dāng)DataNode讀取Block的時(shí)候,它會(huì)計(jì)算CheckSum。
    2. 如果計(jì)算后的CheckSum,與Block創(chuàng)建時(shí)值不一樣,說(shuō)明Block已經(jīng)損壞。
    3. Client讀取其他DataNode上的Block。
    4. DataNode在其文件創(chuàng)建后周期驗(yàn)證CheckSum,如下圖所示。
      image-20201130182018827.png

3. 掉線時(shí)限參數(shù)設(shè)置

  1. DataNode進(jìn)程死亡或者網(wǎng)絡(luò)故障造成DataNode無(wú)法與NameNode通信

  2. NameNode不會(huì)立即把該節(jié)點(diǎn)判定為死亡,要經(jīng)過(guò)一段時(shí)間,這段時(shí)間暫稱作超時(shí)時(shí)長(zhǎng)。

  3. HDFS默認(rèn)的超時(shí)時(shí)長(zhǎng)為10分鐘+30秒。

  4. 如果定義超時(shí)時(shí)間為TimeOut,則超時(shí)時(shí)長(zhǎng)的計(jì)算公式為:

    TimeOut  = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval。
    
    而默認(rèn)的dfs.namenode.heartbeat.recheck-interval 大小為5分鐘,dfs.heartbeat.interval默認(rèn)為3秒。
    

注意:

  • hdfs-site.xml 配置文件中的heartbeat.recheck.interval的單位為<font color=red>毫秒</font>,dfs.heartbeat.interval的單位為<font color=red>秒</font>

  • <property>
        <name>dfs.namenode.heartbeat.recheck-interval</name>
        <value>300000</value>
    </property>
    <property>
        <name>dfs.heartbeat.interval</name>
        <value>3</value>
    </property>
    

對(duì)大數(shù)據(jù)感興趣的小伙伴可以關(guān)注我的公眾號(hào):大數(shù)據(jù)學(xué)習(xí)寶典,在上面會(huì)定期更新學(xué)習(xí)筆記和一些心得!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容