1. Hadoop安裝過程中常見問題
一、啟動namenode服務後,web頁面依然無法訪問
1、啟動namenode服務,
指令:start-all.sh
'''
[root@hadoop1 hadoop-3.2.1]# start-all.sh
Starting namenodes on [hadoop1]
Starting datanodes
Starting secondary namenodes [hadoop1]
Starting resourcemanager
Starting nodemanagers
ERROR: Refusing to run as root: roo account is not found. Aborting.
'''
2、查看namenode服務是否啟動,
'''
[root@hadoop1 hadoop-3.2.1]# jps
8130 Jps
7494 ResourceManager
6871 NameNode
7244 SecondaryNameNode
'''
3、查看後台監聽埠
'''
[root@hadoop1 hadoop-3.2.1]# netstat -nltp |grep 6871
tcp 0 0 192.168.43.250:9000 0.0.0.0:* LISTEN 6871/java
tcp 0 0 0.0.0.0:9870 0.0.0.0:* LISTEN 態態 6871/java
'''
4、查看web是否可以訪問,發現web頁面無法訪問
5、檢查防火牆設置,可以看帆燃源到hadoop1伺服器已經禁用了除本機外的其他多有服務訪問,
[root@hadoop1 hadoop-3.2.1]# service iptables status
表格:filter
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
3 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
5 REJECT all -- 0.0.0.0/0 0.0.0.0/段野0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
6、關閉防火牆,並把防火牆設置為開啟不啟動
centos6:
關閉防火牆:service iptables stop
設置開啟不啟動防火牆:chkconfig iptables off
centos7:
關閉防火牆:systemctl stop firewalld.service
設置開啟不啟動防火牆:systemctl disable firewalld.service
7、檢查web已經可以正常顯示
8、如果上面的操作依然無法訪問的話,需要查看一下主機的hosts文件 是否有配置域名映射
二、開啟datanode指令時出現waring
[root@hadoop1 hadoop-3.2.1]# hadoop-daemon.sh start datanode
WARNING: Use of this script to start HDFS daemons is deprecated.
WARNING: Attempting to execute replacement "hdfs --daemon start" instead.
主要是2.7版本的hadoop已經把hadoop命令改為hdfs命令了,所以嘗試使用
指令:hdfs --daemon start datanode
'''
[root@hadoop2 hadoop-3.2.1]# hdfs --daemon start datanode
[root@hadoop2 hadoop-3.2.1]# jps
4064 Jps
4033 DataNode
2922 ResourceManager
'''
三、使用root配置的hadoop並啟動會出現報錯
錯誤:
Starting namenodes on [master]
ERROR: Attempting to operate on hdfs namenode as root
ERROR: but there is no HDFS_NAMENODE_USER defined. Aborting operation.
Starting datanodes
ERROR: Attempting to operate on hdfs datanode as root
ERROR: but there is no HDFS_DATANODE_USER defined. Aborting operation.
Starting secondary namenodes [slave1]
ERROR: Attempting to operate on hdfs secondarynamenode as root
ERROR: but there is no HDFS_SECONDARYNAMENODE_USER defined. Aborting operation.
原因分析:由於root沒有start-dfs.sh和 stop-dfs.sh腳本的執行許可權,在這兩個腳本的開頭加上如下參數,給root賦予執行許可權即可:
HDFS_DATANODE_USER=root
HADOOP_SECURE_DN_USER=hdfs /* 後續版本這邊需要修改為 HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
start-yarn.sh,stop-yarn.sh頂部也需添加以下
YARN_RESOURCEMANAGER_USER=root
HADOOP_SECURE_DN_USER=yarn /* 後續版本這邊需要修改為 HDFS_DATANODE_SECURE_USER=hdfs
YARN_NODEMANAGER_USER=root
4、hdfs運行指令時出現warn警告提示:
2019-11-13 00:07:58,517 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
該警告信息主要是由於是依賴庫的問題
我們對靜態庫查看下依賴:看下依賴是否都正常:
通過指令 ldd libhadoop.so.1.0.0
'''
./libhadoop.so.1.0.0: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./libhadoop.so.1.0.0)
linux-vdso.so.1 => (0x00007fff369ff000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f3caa7ea000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3caa455000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3caac1b000)
'''
可以看到是glibc 版本的問題:
我們再確認下:
GLIBC_2.14找不到,現在檢查系統的glibc庫, ldd --version 即可檢查。
輸入命令:
'''
ldd --version
ldd (GNU libc) 2.12
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for ing conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
'''
還可以直接確認下glibc 目前支持的版本:
通過如下查詢方法:
'''
strings /lib64/libc.so.6|grep GLIBC
GLIBC_2.2.5
GLIBC_2.2.6
GLIBC_2.3
GLIBC_2.3.2
GLIBC_2.3.3
GLIBC_2.3.4
GLIBC_2.4
GLIBC_2.5
GLIBC_2.6
GLIBC_2.7
GLIBC_2.8
GLIBC_2.9
GLIBC_2.10
GLIBC_2.11
GLIBC_2.12
GLIBC_PRIVATE
'''
可以看到目前只支持到 2.12
解決辦法有兩個
1、升級 glibc 庫
2、屏蔽hadoop提示這個告警
直接在log4j日誌中去除告警信息。在$HADOOP_HOME/etc/hadoop/log4j.properties文件中添加
log4j.logger.org.apache.hadoop.util.NativeCodeLoader=ERROR
2. web調用hdfs出現找不到Configuration這個類(hadoop2.6)
有時襪歷候通過IDE引伏好臘入的jar包並沒有一缺滑起編譯到Bin目錄去,我用intellijIdea遇到過好幾次。
3. Python使用hdfs存放文件時報Proxy error: 502 Server dropped connection解決方案
Python3 使用hdfs分布式文件儲存系統
from pyhdfs import *
client = HdfsClient(hosts="testhdfs.org, 50070",
user_name="web_crawler") # 創建一個連接
client.get_home_directory() # 獲取hdfs根路徑
client.listdir(PATH) # 獲取hdfs指定路徑下的文件列表
client._from_local(file_path, hdfs_path, overwrite=True) # 把本地文件拷貝到伺服器,不支持文件夾;overwrite=True表示存在則覆蓋
client.delete(PATH, recursive=True) # 刪除指定文件
hdfs_path必須包含文件名及其後綴,不握殲然不會成功
如果連接
HdfsClient
報錯
Traceback (most recent call last):
File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 2963, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "
client.get_home_directory()
File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\pyhdfs.py", line 565, in get_home_directory
return _json(self._get('/', 'GETHOMEDIRECTORY', **kwargs))['Path']
File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\pyhdfs.py", line 391, in _get
return self._request('get', *args, **kwargs)
伍皮並 File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\pyhdfs.py", line 377, in _request
_check_response(response, expected_status)
File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\pyhdfs.py", line 799, in _check_response
腔跡 remote_exception = _json(response)['RemoteException']
File "C:\Users\billl\AppData\Local\Continuum\anaconda3\lib\site-packages\pyhdfs.py", line 793, in _json
"Expected JSON. Is WebHDFS enabled? Got {!r}".format(response.text))
pyhdfs.HdfsException: Expected JSON. Is WebHDFS enabled? Got '\n\n\n\n
502 Server dropped connection
\n
The following error occurred while trying to access http://%2050070:50070/webhdfs/v1/?user.name=web_crawler&op=GETHOMEDIRECTORY :
\n 502 Server dropped connection
\n
Generated Fri, 21 Dec 2018 02:03:18 GMT by Polipo on .\n\r\n'
則一般是訪問認證錯誤,可能原因是賬戶密碼不正確或者無許可權,或者本地網路不在可訪問名單中
4. namenode正處於safemode狀態,怎麼處理
dfs.cluster.administrators
hdfs
dfs.block.access.token.enable
true
dfs.datanode.failed.volumes.tolerated
0
dfs.replication.max
50
dfs.datanode..reserved
1073741824
dfs.blockreport.initialDelay
120
dfs.datanode.data.dir
file:///data/hadoop/hdfs/dn
dfs.client.read.shortcircuit
true
dfs.datanode.max.transfer.threads
4096
dfs.namenode.http-address
hadoop01:50070
dfs.client.read.shortcircuit.streams.cache.size
4096
<!-- 在客戶端讀冊尺轎取前會創建一個FileinputStreamCache,就是由前兩個參數控制大小和過期時間,
dfs.client.read.shortcircuit.streams.cache.size和dfs.client.read.shortcircuit.streams.cache.expiry.ms -->
dfs.namenode.avoid.write.stale.datanode
true
<!-- 表明是否要避免寫為「過時」的心跳州肆消息尚未收到的NameNode超過指定的時間間隔數據節點。寫操困亮作將避免使用陳舊的數據節點,除非多數據節點的配置比例
(dfs.namenode.write.stale.datanode.ratio)被標記為失效。見dfs.namenode.avoid.read.stale.datanode為讀取一個類似的設置。 -->
dfs.namenode.avoid.read.stale.datanode
true
dfs.namenode.stale.datanode.interval
30000
<!--dfs.client.read.shortcircuit.streams.cache.size和dfs.client.read.shortcircuit.streams.cache.expiry.ms
以及dfs.client.read.shortcircuit.skip.checksum和dfs.client.read.shortcircuit.buffer.size.其中,
在客戶端讀取前會創建一個FileinputStreamCache,就是由前兩個參數控制大小和過期時間的,其中key就是Datanode+block;
後兩個參數就是決定是否跳過校驗以及校驗的塊大小.-->
dfs.permissions.enabled
true
dfs.datanode.ipc.address
0.0.0.0:8010
dfs.namenode.name.dir
file:///data/hadoop/hdfs/nn
dfs.journalnode.http-address
0.0.0.0:8480
dfs.heartbeat.interval
3
dfs.datanode.data.dir.perm
750
fs.permissions.umask-mode
022
dfs.datanode.balance.bandwidthPerSec
6250000
dfs.namenode.accesstime.precision
0
dfs.namenode.write.stale.datanode.ratio
1.0f
dfs.namenode.checkpoint.dir
file:///data/hadoop/hdfs/snn
dfs.journalnode.edits.dir
/grid/0/hdfs/journal
dfs.blocksize
134217728
<!-- 2.X 版本默認值:134217728 說明: 這個就是hdfs里一個文件塊的大小了,默認128M;太大的話會有較少map同時計算,
太小的話也浪費可用map個數資源,而且文件太小namenode就浪費內存多。對於較大集群,可設為256MB,根據需要進行設置。-->
dfs.replication
3
dfs.block.local-path-access.user
hbase
dfs.datanode.address
0.0.0.0:50010
dfs.datanode.http.address
0.0.0.0:50075
dfs.https.namenode.https-address
c6401.ambari.apache.org:50470
dfs.webhdfs.enabled
true
dfs.namenode.handler.count
100
dfs.namenode.secondary.http-address
hadoop02:50090
dfs.permissions.superusergroup
hdfs
dfs.namenode.safemode.threshold-pct
1.0f
dfs.domain.socket.path
/var/lib/hadoop-hdfs/dn_socket
5. hadoop集群搭好 為什麼hdfs埠500070打不開
1、啟動hadoop後,要看哪些界面或功能之前,建議先用jps或是netstat -ano看下相應的埠是否已經開啟了,如果埠沒開啟,是肯定看不了相應的界面的。 試下看吧。
6. hadoop web界面顯示blocksize為0
當向HDFS上大卜寫文件時,槐山可以通過設置dfs.blocksize配置項來設置文件的block size,這導致HDFS上不同文件滾明穗的block size是不同的。
7. HDFS 許可權管理
HDFS Permissions Guide
HDFS 實現了文件和目錄的許可權模型,很多跟POSIX模型共享。 每個文件、目錄都關聯到用戶、組。文件、目錄對於擁有者、組中的其他用戶、其他用戶有著不同的許可權設置。對於文件,讀取需要 r 許可權,寫入/追加需要 w 許可權。對於目錄,列出目錄內容需要 r 許可權,創建、刪除文件或目錄需要 w 許可權,訪問目錄子項需要 x 許可權。
與POSIX模型不同,因為沒有可執行文件,所以文件沒有 setuid or setgid bits。對於目錄,也沒有 setuid or setgid bits作為簡化。粘滯位 sticky bit 可以被作用於目錄,放置除superuser、目錄所有者、文件所有者之外的任何用戶刪除、移動目錄內的文件。粘滯位 sticky bit 對於文件不生效。 文件或目錄的許可權我們稱為 mod 。一般來說,mdoe的展示使用Unix風格,比如描述的8進制數使用。當創建一個文件/目錄後,它的所有者即為客戶端進程的用戶,它的組是父目錄的組(BSD規則)。
HDFS 還支持POSIX ACLs (Access Control Lists),給指定用戶、組配置更新顆粒度的規則來加強許可權管理。ACLs稍後會詳細介紹。
每個訪問HDFS的客戶端進程身份都有兩部分組成:用戶名,組列表。無論什麼時候,HDFS都必須會客戶端進程訪問的文件或目錄foo做許可權檢查,
如果許可權校驗失敗,客戶端操作失敗。
自 Hadoop 0.22 起,Hadoop 支持兩種不同的操作模式來判斷用戶的身份,通過 hadoop.security.authentication 屬性指定:
不管是哪種模式,正型橡用戶身份機制都是HDFS的外部機制。HDFS中沒有用於創建用戶、建立組、處理用戶憑據的規定。
一旦username被判定,如上,groups list將由group mapping service 判斷,配置在 hadoop.security.group.mapping 屬性。參見 Hadoop Groups Mapping 獲取更多內容。
每次HDFS操作都需要用戶擁有指定許可權(讀,寫,執行的組合),通過文件的 ownership,group membership or 其他許可權進行授權。 一個操作會進行路徑多個組件的許可權檢查,而不僅是最後一個組件。另外,一些操作依賴於路徑owner的檢租悔查。
所有的操作都需要遍歷訪問(traversal access)。遍歷訪問需要對路徑上的所有存在的組件擁有執行舉旁許可權,最終路徑組件除外。比如,任一訪問 /foo/bar/baz 的操作,調用者需要擁有 /, /foo and /foo/bar 的可執行許可權。
[1] 如果調用使用overwrite配置,並且該路徑已經存在文件,那麼 create 操作只需要對最終路徑組件擁有寫許可權即可。
[2] 如果設置了 sticky bit ,對父目錄寫許可權的檢查操作,同樣也會檢查ownership。
[3] 調用 setOwner 來改變文件的擁有著需要 HDFS super-user 訪問許可權。變更組不需要HDFS super-user 訪問許可權,但是調用者必須是文件的擁有者並且是指定組的成員。
每個文件、目錄操作都會將完全路徑發送給NameNode,對每個操作都會沿著path進行許可權檢查。客戶端框架隱式的將用戶身份與到NameNode的連接關聯,減少對現有客戶端API的改動的需求。常見一種情況,當某文件的一個操作已經成功完成了,再操作的時候會失敗,因為該路徑上的文件、目錄已經不存在了。舉個例子,當客戶端第一次開始讀取一個文件,它向NameNode發出第一個請求,以發現文件的第一個塊的位置。第二個請求查找其他的塊可能會失敗。另一方面,刪除一個文件並不會撤回客戶端對該文件的訪問,該客戶端已經知道該文件的塊。通過添加許可權,客戶端對文件的訪問可以在請求之間被撤回。同樣,變更許可權不會撤回客戶端的訪問,該客戶端已經知道文件的塊。
如果許可權檢查失敗,所有使用路徑參數的方法都會拋出 AccessControlException 。
新方法:
新文件、目錄的mode受umask設置限制,umask設置是配置項。
當使用現有方法 create(path, …) (不帶許可權參數),新文件的 mode 是 0666 & ^umask 。
當使用新方法 create(path, permission, …) (帶許可權參數 P) ,新文件的 mode 是 P & ^umask & 0666 。
當使用現有方法 mkdirs(path) (不帶許可權參數)創建一個新目錄, 新目錄的 mode 是 0777 & ^umask 。
當使用新方法 mkdirs(path, permission) (帶許可權參數 P), 新目錄的 mode 是 P & ^umask & 0777 。
新操作:
誰啟動NameNode,誰就是super-user。 super-user可以執行任意操作,許可權校驗從不失敗。HDFS super-user 不必是NameNode 主機上的super-user,也不是說集群內的說有主機都需要有這個super-user。
如果在個人電腦上實驗運行HDFS,為方便起見無須任何配置該用戶即成為安裝的super-user。
另外,管理員還可以通過配置參數標識一個特定組。該組內的成員也是super-users。
默認,web server的身份是一個可配置項。即,NameNode不知道真實用戶的身份,但是web server以管理員選定的用戶的身份(用戶/組)行動。 除非選擇的身份匹配super-user,部分命名空間是不可以被web server訪問的。
除了傳統的POSIX許可權模型,HDFS還支持POSIX ACLs (Access Control Lists)。ACLs 對於實現區分用戶、組的自然組織層次結構的許可權需求非常有用。ACL提供了一個方法,可以給指定用戶、組設置不同的許可權,而不僅僅是文件的擁有著和所屬組。
默認,ACLs的支持是關閉的,並且NameNode不允許創建ACLs。要開啟ACLs的支持,在NameNode配置內設置 dfs.namenode.acls.enabled 為 true。
一個ACL由一系列ACL entries組成。每條ACL entry 命名了特定用戶/組,並授於/拒絕 讀、寫、執行 許可權。比如:
ACL entries 由 type ,可選的 name 和 permission 組成。為了便於展示,『:』 用作分隔符。 在這個範例內,文件的owner有read-write許可權,文件的group有read-execute許可權,others有讀取許可權。因此,等同於設置文件的許可權為654。
另外,有2個擴展ACL entries給用戶 bruce 和組 sales,並全部賦予所有許可權。 mask 是一個特殊的ACL entry,過濾給所有命名的user entries 和命名的group entries 以及非命名的group entry的許可權。 在範例內, mask 僅有寫許可權,並且我們可以看到幾個ACL entries的有效許可權被相應的過濾了。
每個ACL都必要要有一個 mask 。如果在設置ACL的時候用戶沒有提供 mask ,那麼會通過計算來自動插入,計算將被過濾的所有entries的許可權的並集。
在擁有ACL的文件上運行 chmod 實際上改變了 mask 的許可權。既然 mask 作為過濾器,這有效的約束了所有擴展ACLs的許可權,而不僅是變更group entry並且可能會丟失其他擴展ACL entries。
模型還有效區分了 「access ACL」 和 「default ACL」 。
「access ACL」 ,定義許可權檢查期間強制執行的規則; 「default ACL」 ,定義新子文件或子目錄創建期間自動接受的規則。
比如:
只有目錄可以擁有默認 ACL。當一個新文件或者子目錄創建,它會自動的拷貝父級的默認ACL作為自己的ACL。新子目錄還將其作為默認 ACL。這樣,當新目錄創建時,默認 ACL 會被復制到該文件系統數的任意深度層。
新子級的ACL的確切許可權值將由mode參數進行過濾。考慮到默認umask 是 022,則新目錄是755,新文件是644。mode參數給unnamed user (file owner), the mask and other過濾過濾拷貝過來的許可權值。 使用這個特定範例ACL,並創建一個mod 755的子目錄,該mode過濾器對最終結果沒有影響。但是,如果我們考慮創建一個mode 644 的文件,mode過濾器會導致新文件的ACL接受unnamed user(file owner)的讀寫許可權,mask的讀許可權,以及其他的讀許可權。 該mask意味著named user bruce 和 named group sales 的有效許可權是只讀。
注意,拷貝發生在創建新文件或子目錄的時候。對父級默認ACL的後續修改不會影響存在的子級。
默認 ACL 必須擁有所有必要的ACL entries,包括unnamed user (file owner), unnamed group (file group) and other entries。當設置默認ACL的時候,如果用戶沒有指定其中某個entry,那麼entries會自動插入,通過拷貝訪問ACL相應的許可權、如果沒有訪問ACL則拷貝permission bits來實現。默認ACL必須擁有mask。如上所屬,如果沒有指定會自動插入一個計算的值。
對擁有ACL的文件,許可權的檢查演算法變更為:
最佳實踐依賴傳統的許可權位來實現大多數許可權需求,並定義較少數量的ACL來加強,用一些異常規則來擴充許可權位。與只有許可權位的文件相比,具有ACL的文件在NameNode中會增加內存開銷。
新方法:
public void modifyAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
public void removeAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
public void public void removeDefaultAcl(Path path) throws IOException;
public void removeAcl(Path path) throws IOException;
public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException;
public AclStatus getAclStatus(Path path) throws IOException;
參考 File System Shell 文檔獲取命令的全部內容。
如果是,則使用這里描述的許可權系統。如果否,關閉許可權檢查,但是其他行為不變。從一個參數值切換到其他值不會改變mode、文件或目錄的owner or group。無論許可權是開還是關, chmod 、 chgrp 、 chown and setfacl 總是會檢查許可權。 這些功能僅在許可權上下文有用,因此不存在向後兼容問題。此外,這允許管理員可靠的設置所有者和許可權,在打開常規許可權檢查前。
web server使用的用戶名。設置為super-user允許所有客戶端看到任何內容。改為其他未使用的身份允許web客戶端僅可以查看"other"許可權可見的內容。其他將其他組添加到逗號分隔列表內。
super-users 的組。
當創建文件和目錄時使用的 umask 。對於配置文件,可以使用十進制值 18。
集群的管理員被配置為ACL。這控制誰可以訪問HDFS默認的servlets 等。
設置為true,開啟HDFS ACLs (Access Control Lists)的支持。默認,ACLs是關閉的。當ACLs關閉的時候,NameNode拒絕所有設置ACL的企圖。 .
設置為true,開啟 POSIX風格的ACL繼承。默認開啟。當它被啟動時,並且create請求來自於兼容客戶端,NameNode會從父目錄應用默認ACL來創建mode並忽視客戶端umask。如果沒有默認ACL,它將應用客戶端umask。
8. hadoop的web管理界面打不開怎麼辦
在虛擬機上安裝了Hadoop,安裝情況如下:
192.168.220.129 master
192.168.220.130 slave1
192.168.220.131 slave2
配置好各個ip後,在虛擬系統中可以訪問,http://192/168.220.129:50070 ,但是在筆記本的window上不能訪問
使用命令查看如下:
9. HDFS客戶端無法及時addBlock和關閉文件問題分析
現網運行過程中,某些高負載集群的 NN 頻繁列印下面的 「block is COMMITTED but not COMPLETE" 日誌,且客戶端經常會關閉文件失敗,導致業務異常退出,如下所示:
這實際是一個 block 無法及時到達 COMPLETE 狀態的問題,在 HDFS 中,一個 block 只有達到最小副本數之後,才能變為 COMPLETE 狀態。HDFS 默認的最小副本數是1,也就是說,NameNode 收到至少1個 DataNode 的上宴帆報之後,這個 block 才能達到 COMPLETE 狀態,表示這個 block 已經正式寫入完畢,其內容此時已成功固化到磁碟。
如果一個文件的 block 不能及時達到 COMPLETE 狀態,則會導致
這兩個集群是負載較高的兩個集群,共同點是 NameNode 都會頻繁的列印上面那種 「block is COMMITTED but not COMPLETE」 日誌,但這兩個集群又有所不同:
以那個導致客戶端出錯的 block 為例(block ID 為:blk_16141305305),可以看到,客戶端有5次重試,加上第一次的正常操作,一共嘗試了6次 addBlock(或 completeFile),但全部未成功,這將直接導致客戶端寫文件失敗(或關閉文件失敗):
這個 block 涉及到兩個 DN,以9.179.163.164 這個 DN 為例,可以看到,DN IO 線程在 16:46:16 寫完 block 觸發增量上報之後,一直過了45s 到了16:47:01,DN 心跳線程才開始真正向 NN 發送增量上報 RPC 消息,這很不正常,正常情況應該是立即發送才對(另外結合上面的 NN 日誌可以看到,DN 發送增量上報 IBR 之後,就被 NN 同時在16:47:01處理完畢,可見此時 NN 沒有問題):
進一步分析 DN 的 IBR 上報記錄,可以看到:心跳線程在 16:46:07 到 16:47:01 之間,這54s之內,根本沒有進行任何 IBR 上報,這也導致 16:47:01一下子積攢了很多 block,那麼問題很清楚了,在這長達54s 的時間內,DN 心跳線程到底在干什麼?
DN 心跳線程循環執行 BPServiceActor.offerService() 函數,在這個函數里,它循環做下面的事情:
現在的問題集中在:DN 在處理這次 IBR 之前,一共54s 內,到底在幹嘛?
首先想到的就是 jstack,但是現在是事後分析,已經沒法再 jstack 了。好在這個問題集群其實一直在持續性的出現這種文件不能及時關閉的問題,所以,現在再 jstack,也來的及,具體步驟:
這次倒是比較順利的拿到了結果:
既然找到了原因,那麼解決起來就比較容易了,通過上面的分析,核心的原因還是 FsDatasetImpl.datasetLock 這把全局互斥鎖實在是太難搶了,導致心跳線程在 getStorageReports() 時長時間等這把鎖(最終是 getDfsUsed() )。但實際上,心跳線程此時其實不需要這把鎖,因為它拿到鎖之後,要訪問的數據結構是一個 ConcurrentHashMap,要歷祥灶知道 ConcurrentHashMap 本身即是一肢扮個支持並發讀寫的結構,訪問它根本不需要額外再加什麼鎖。
到底為止,改法其實出來了,DN 心跳線程在 getDfsUsed() 時,不用加 FsDatasetImpl.datasetLock 這把全局互斥鎖。
歷盡千辛萬苦,終於找到了原因,但是當我要去改的時候,發現 hdfs 3.x 已經改了這個地方(改動的目的是解決另外一個問題,但卻順帶著也解決了我們這次的問題),所以 backport 就可以了,具體 jira 為:HDFS-7060 Avoid taking locks when sending heartbeats from the DataNode
從這個問題的分析過程,也可以看出,像 NameNode 和 DataNode 這種高並發、大吞吐的多線程任務,在功能方面,可以不斷的增加新特性,但在性能方面,最終的瓶頸往往會落到某個全局鎖上(或者雖然不是全局但范圍特別廣的鎖),這時候爭鎖才是導致多線程無法完全發揮潛力、整體吞吐量下降的阿克琉斯之踵。更加難受的是,爭鎖的困境往往很難通過小修小補解決,而是需要架構層面的重構,這又進一步加大了優化的成本。典型的比如 HDFS NN 和 DN 中的兩把全局鎖,對整體性能的影已經是一個曠日持久的問題,但直到現在,也依然沒有得到解決:
DN 心跳線程爭鎖是一個老生常談的問題,除了上面已經合入的 HDFS-7060 之外,社區還有其他幾個 Patch 也需要合入:
10. HDFS文件
Hadoop支持的文件系統知培由很多(見下圖),HDFS只是其中一種實現。Java抽象類 org.apache.hadoop.fs.FileSystem 定義了Hadoop中一個文件系統的客戶端介面,並且該抽象類有幾個具體實現。Hadoop一般使用URI(下圖)方案來選取合適的文件系統實例進行交互。
特別的,HDFS文件系統的操作可以使用 FsSystem shell 、客戶端(http rest api、Java api、C api等)。
FsSystem shell 的用法基本同本地shell類似,命令可參考 FsSystem shell
Hadoop是用Java寫的,通過Java Api( FileSystem 類)可以調用大部分Hadoop文件系統的交互操作。更詳細的介紹可參考 hadoop Filesystem 。
非Java開發的應用可以使用由WebHDFS協議提供的HTTP REST API,但是HTTP比原生的Java客戶端要慢,所以不到萬不得已盡量不要使用HTTP傳輸特大數據。通過HTTP來訪問HDFS有兩種方法:
兩種如圖
在第一種情況中,namenode和datanode內嵌的web服務作為WebHDFS的端節點運行(是否啟用WebHDFS可通過dfs.webhdfs.enabled設置,默認為true)。文件元數據在namenode上,文件讀寫操作首先被發往namenode,有namenode發送一個HTTP重定向至某個客戶端,指示以流的方式傳輸文件數據的目的或源datanode。
第二種方法依靠一個或多個獨立代理伺服器通過HTTP訪問HDFS。所有集群的網路通信都需要通過代理,因此客戶端從來不直接訪問namenode或datanode。使用代理後可以使用更嚴格的防火牆策略和帶寬策略。
HttpFs代理提供和WebHDFS相同的HTTP介面,這樣客戶端能夠通過webhdfs URI訪問搭晌唯介面。HttpFS代理啟動獨立於namenode和datanode的守護進程,使用httpfs.sh 腳本,默認在一個不同的埠上監聽(14000)。
下圖描述了
讀文件時客戶端與 HDFS 中的 namenode, datanode 之間的數據流動。
對上圖的解釋如下:
在讀取過程中, 如果 FSDataInputStream 在和一個 datanode 進行交流時出現了一個錯誤,他就去試一試下一個最接近的塊,他當然也會記住剛才發生錯誤的 datanode 以至於之後不會再在這個 datanode 上進行沒必要的嘗試。 DFSInputStream 也會在 datanode 上傳輸出的數據上核查檢查數(checknums).如果損壞的塊被發現了, DFSInputStream 就試圖從另一個擁有備份的 datanode 中去讀取備份塊中的數據。
在這個設計中一個重要的方面就是客戶端直接從 datanode 上檢索數據,並通過 namenode 指導來得到每一個塊的最佳 datanode。這種設計允許 HDFS 擴展大量的並發客戶謹液端,因為數據傳輸只是集群上的所有 datanode 展開的。期間,namenode 僅僅只需要服務於獲取塊位置的請求(塊位置信息是存放在內存中,所以效率很高)。如果不這樣設計,隨著客戶端數據量的增長,數據服務就會很快成為一個瓶頸。
我們知道,相對於客戶端(之後就是 maprece task 了),塊的位置有以下可能性:
我們認為他們對於客戶端的帶寬遞減,距離遞增(括弧中表示距離)。示意圖如下:
如果集群中的機器都在同一個機架上,我們無需其他配置,若集群比較復雜,由於hadoop無法自動發現網路拓撲,所以需要額外配置網路拓撲。
基本讀取程序,將文件內容輸出到console
FileSystemCat
隨機讀取
展開原碼
下圖描述了寫文件時客戶端與 HDFS 中的 namenode, datanode 之間的數據流動。
對上圖的解釋如下:
如果在任何一個 datanode 在寫入數據的時候失敗了,接下來所做的一切對客戶端都是透明的:首先, pipeline 被關閉,在確認隊列中的剩下的包會被添加進數據隊列的起始位置上,以至於在失敗的節點下游的任 何節點都不會丟失任何的包。然後與 namenode 聯系後,當前在一個好的 datanode 會聯系 namenode, 給失敗節點上還未寫完的塊生成一個新的標識ID, 以至於如果這個失敗的 datanode 不久後恢復了,這個不完整的塊將會被刪除。失敗節點會從 pipeline 中移除,然後剩下兩個好的 datanode 會組成一個的新的 pipeline ,剩下的 這些塊的包(也就是剛才放在數據隊列隊首的包)會繼續寫進 pipeline 中好的 datanode 中。最後,namenode 注意到塊備份數小於規定的備份數,他就安排在另一個節點上創建完成備份,直接從已有的塊中復制就可以。然後一直到滿足了備份數( dfs.replication )。如果有多個節點的寫入失敗了,如果滿足了最小備份數的設置( dfs.namenode.repliction.min ),寫入也將會成功,然後剩下的備份會被集群非同步的執行備份,直到滿足了備份數( dfs.replication )。
創建目錄
文件壓縮有兩大好處:
Hadoop 對於壓縮格式的是自動識別。如果我們壓縮的文件有相應壓縮格式的擴展名(比如 lzo,gz,bzip2 等)。Hadoop 會根據壓縮格式的擴展名自動選擇相對應的解碼器來解壓數據,此過程完全是 Hadoop 自動處理,我們只需要確保輸入的壓縮文件有擴展名。
Hadoop中有多種壓縮格式、演算法和工具,下圖列出了常用的壓縮方法。
表中的「是否可切分」表示對應的壓縮演算法是否支持切分,也就是說是否可以搜索數據流的任意位置並進一步往下讀取數據,可切分的壓縮格式尤其適合MapRece。
所有的壓縮演算法都需要權衡空間/時間:壓縮和解壓縮速度更快,其代價通常是只能節省少量的空間。不同的壓縮工具有不同的特性:
更詳細的比較如下
1.壓縮性能比較
2.優缺點
另外使用hadoop原生(native)類庫比其他java實現有更快的壓縮和解壓縮速度。特徵比較如下:
使用容器文件格式結合壓縮演算法也能更好的提高效率。順序文件、Arvo文件、ORCFiles、Parqurt文件同時支持壓縮和切分。
壓縮舉例(Java)
壓縮
解壓縮
六、文件序列化
序列化是指將結構化數據轉換為位元組流以便在網路上傳輸或寫到磁碟進行永久存儲。反序列化獅子將位元組流轉換回結構化對象的逆過程。
序列化用於分布式數據處理的兩大領域:進程間通信和永久存儲。
對序列化的要求時是格式緊湊(高效使用存儲空間)、快速(讀寫效率高)、可擴展(可以透明地讀取老格式數據)且可以互操作(可以使用不同的語言讀寫數據)。
Hadoop使用的是自己的序列化格式 Writable ,它絕對緊湊、速度快,但不太容易用java以外的語言進行擴展或使用。
當然,用戶也可以使用其他序列化框架或者自定義序列化方式,如 Avro 框架。
Hadoop內部還使用了 Apache Thrift 和 Protocal Buffers 來實現RPC和數據交換。