網上有很多Hadoop HA集羣安裝的資料,我當時安裝也是參考了官方文檔和這些資料才安裝成功的。由於使用的環境和軟件版本可能有所不同,且因工作環境網絡所限無法連接外網,加之記錄一下自己的安裝過程,不枉花費時間來研究Hadoop環境的搭建,故作此文章。
一、集羣架構表
IP地址 |
主機名 |
角色 |
端口 |
192.168.52.2 |
namenode |
NameNode,JournalNode,ZKFC, ResourceManager,MapReduce歷史服務器 |
hdfs-site(http://namenode:50070) yarn-site(http://namenode:8088) |
192.168.52.3 |
datanode1 |
NameNode,JournalNode,ZKFC,DataNode,ZooKepper |
hdfs-site(http://datanode1:50070) |
192.168.52.4 |
datanode2 |
ResourceManager,JournalNode,DataNode,ZooKepper |
yarn-site(http://namenode:8088) |
192.168.52.5 |
datanode3 |
DataNode,ZooKepper |
注:ZKFC並不依賴ZooKeeper,所以無須在namenode上安裝ZooKeeper。
二、操作系統環境及軟件版本(都是當時的最新版本)
我安裝的是1臺虛擬機,克隆了3個,具體安裝過程在此不加贅述。
1、CentOS 7.5.1804 ,最小化安裝
2、Hadoop 2.9.2
3、JDK8(最開始裝的JDK11,屢試不行,去官網查版本支持,發現不支持JAVA 11,於是下的JDK8)
4、ZooKeeper-3.4.13
5、ntpdate或者CentOS 7默認的chrony時間同步,二選一
6、psmisc(很重要,fuser指令所需的包,後面會詳細說明)
cat /etc/redhat-release
hadoop -version
java -version
alternatives --config java (配置java多版本環境)
yum install psmisc
三、安裝過程
1、配置主機名
1.1 分別在4臺服務器上用root賬戶執行:
hostnamectl set-hostname namenode
hostnamectl set-hostname datanode1
hostnamectl set-hostname datanode2
hostnamectl set-hostname datanode3
1.2 在4臺服務器上用root用戶執行(亦可在namenode上修改,然後scp複製到其他主機上):
vi /etc/hosts
然後在文本末尾插入如下4行信息
192.168.52.2 namenode
192.168.52.3 datanode1
192.168.52.4 datanode2
192.168.52.5 datanode3
192.168.52.1 win #這行最好也加上,方便本機windows與4臺虛擬機的相互訪問
2、關閉SELINUX
因爲CentOS的所有訪問權限都是有SELinux來管理的,爲了簡化安裝過程避免權限導致的問題,先將其關閉,以後根據需要再進行重新管理。
執行如下指令關閉:
setenforce 0 #臨時設置SELINUX狀態
vi /etc/selinux/config # 編輯 config 文件將 SELINUX=enforcing 修改爲 SELINUX=disabled(重啓生效)
查看執行結果:
getenforce #查看當前SELINUX狀態,permissive或disabled代表SELINUX處於關閉狀態
3、關閉防火牆
同樣是爲了簡化安裝,避免防火牆策略帶來的影響。
先查看防火牆狀態:
[hadoop@namenode hadoop]$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) #disabled表示非開機啓動
Active: inactive (dead) #inactive表示當前未激活,active表示已激活
Docs: man:firewalld(1)
4、新建hadoop賬戶
由於Hadoop 集羣中的各節點默認會使用當前的賬號SSH免密碼登錄其它節點,所以需要在每個節點中創建一個相同的供 Hadoop 集羣專用的賬戶,本例中使用的賬戶爲 hadoop 。
useradd hadoop #創建賬戶 passwd hadoop #設置密碼
5、配置ssh互信(root、hadoop)
5.1 開啓 sshd 祕鑰認證
編輯每一臺服務器的 /etc/ssh/sshd_config 文件,去掉下面這3行前的 “#” 註釋。
執行:
vi /etc/ssh/sshd_config
刪除行首"#",取消註釋:
# RSAAuthentication yes
# PubkeyAuthentication yes
# AuthorizedKeysFile .ssh/authorized_keys
然後重啓sshd服務:
systemctl restart sshd
5.2 配置root賬戶的ssh互信
5.2.1 生成公鑰和私鑰
在4臺服務器上執行,一直按回車默認即可:
ssh-keygen -t rsa
執行完後會在hadoop用戶的家目錄(/home/hadoop)中生成一個.ssh文件夾,裏面有兩個文件,其中id_rsa是私鑰,id_rsa.pub是公鑰。
在namenode服務器上以下執行:
5.2.2 將4臺服務器公鑰文件的內容追加輸入到authorized_keys文件
(1) 先將namenode的公鑰內容插入到authorized_keys文件
cat /home/root/.ssh/id_rsa.pub >> /home/root/.ssh/authorized_keys
(2) 通過ssh輸入密碼再將三臺datanode的公鑰內容插入到authorized_keys文件
ssh hadoop@datanode1 cat /home/root/.ssh/id_rsa.pub >> /home/root/.ssh/authorized_keys
ssh hadoop@datanode2 cat /home/root/.ssh/id_rsa.pub >> /home/root/.ssh/authorized_keys
ssh hadoop@datanode3 cat /home/root/.ssh/id_rsa.pub >> /home/root/.ssh/authorized_keys
5.2.3 ssh連接namenode自己,以在/home/root/.ssh/known_hosts生成自己的那條記錄
ssh hadoop cat /home/root/.ssh/id_rsa.pub >> /home/root/.ssh/authorized_keys
5.2.4 將authorized_keys和known_hosts通過scp複製到三臺datanode服務器上
scp /home/root/.ssh/authorized_keys datanode1:/home/root/.ssh/
scp /home/root/.ssh/authorized_keys datanode2:/home/root/.ssh/
scp /home/root/.ssh/authorized_keys datanode3:/home/root/.ssh/
scp /home/root/.ssh/known_hosts datanode1:/home/root/.ssh/
scp /home/root/.ssh/known_hosts datanode2:/home/root/.ssh/
scp /home/root/.ssh/known_hosts datanode3:/home/root/.ssh/
5.2.5 修改ssh目錄和authorized_keys的權限
chmod -R 700 /home/root/.ssh chmod 600 /home/root/.ssh/authorized_keys
5.2.6 測試一下,不需要輸入密碼就能登錄則成功,注意下命令行中的主機名哦
ssh root@datanode1 ssh root@datanode2 ssh root@datanode3
5.3 同理,配置hadoop賬戶的ssh互信
用hadoopz賬戶登錄,生成公、私鑰:
ssh-keygen -t rsa
其他步驟按照5.2的順序來,只要把root替換成hadoop就可以了。
6、 用root用戶給hadoop用戶授予sudo權限
執行如下指令:
visudo
在文末添加如下內容,目的是爲了授予hadoop用戶組所有權限,可使用sudo指令執行一些只有root用戶才能執行的指令。
%hadoop ALL=(ALL) ALL
7、安裝JDK
從下面網站下載Oracle JDK8的tar.gz包,第一個網站可以下載8u202版本,第二個可以下載8u192版本,Oracle官方說了2019年1月以後將不支持Java 8的公開版更新。
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
ftp、rz或通過虛擬機共享文件夾上傳到服務器,找到安裝包所在目錄,解壓安裝即可,
tar -zxf java8.tar.gz -C 要解壓到的文件路徑 #想要看安裝過程輸出信息的可以加個v參數,即-zxvf
8、配置時間同步,避免服務器間時間不一致帶來的影響
注意:ntp配置後,要延遲一陣纔開始時間同步,所以用ntpstat -p指令查看是否配置成功時,不要以爲輸出的結果不對就是沒配置正確,最好等一段時間再看。
9、安裝ZooKeeper
這個也沒什麼說的,下載,解壓,配置。在ZooKeeper服務器比如datanode1上安裝配置好後,然後scp整個ZooKeeper目錄即可。
下載地址:
https://www.apache.org/dyn/closer.cgi/zookeeper/
到ZooKeeper服務器上,解壓指令:
tar -zxf zookeeper.tar.gz -C 要解壓到的文件路徑
配置:
到ZooKeeper的安裝目錄下的conf子目錄下新建zoo.cfg:
cp zoo_sample.cfg zoo.cfg
配置zoo.cfg:
vi zoo.cfg
把原來的dataDir那行註釋掉,新加如下兩行:
dataDir=/hadoop/software/zookeeper-3.4.13/data
dataLogDir=/hadoop/software/zookeeper-3.4.13/logs
server.1=datanode1:2888:3888
server.2=datanode2:2888:3888
server.3=datanode3:2888:3888
新建兩個目錄——data目錄和logs目錄,對應zoo.cfg中的配置,並在data目錄下新建myid文件,內容對應zoo.cfg中的server單詞後的數字,如果是複製的文件別忘了改哦!
至此ZooKeeper就配好了,是不是很簡單?
10、安裝、配置Hadoop
安裝hadoop難點無非就是配置問題,在遇到問題時確保配置正確,結合log文件查找原因。
注意:下面所有指令都是以hadoop用戶登錄執行的:
10.1 安裝Hadoop
下載地址:
下載好tar.gz包,解壓(建議不要下source源碼版本的,需要各種包和docker包,很煩),注意四臺服務器上都要安裝哦!
tar -zxf hadoop.tar.gz -C hadoop的安裝目錄
10.2 配置hadoop的環境變量和全局環境變量
可以分別配置/etc/profile和/home/hadoop/.bash_profile,這樣權限方面更安全一點,但我嫌麻煩,索性都配到/etc/profile裏了。
vi /etc/profile
在文末加入如下內容:
# Configure JAVA
export JAVA_HOME=/software/jdk1.8.0_202
export JAVA_BIN=$JAVA_HOME/bin
export JAVA_LIB=$JAVA_HOME/lib
export CLASSPATH=.:$JAVA_LIB/tools.jar:$JAVA_LIB/dt.jar
# Configure Hadoop
export HADOOP_HOME=/hadoop/hadoop-2.9.2
export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop
# Configure Zookeeper
export ZOOKEEPER_HOME=/hadoop/software/zookeeper-3.4.13
# Configure PATH export PATH=$PATH:$HOME/.local/bin:$HOME/bin:$JAVA_BIN:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$ZOOKEEPER_HOME/bin
進入到配置文件所在目錄:
cd /hadoop/hadoop-2.9.2/etc/hadoop
10.3 在配置hdfs時用到的配置文件是hadoop-env.sh、core-site.xml和hdfs-site.xml,具體配置如下:
10.3.1 配置hadoop-env.sh
將其中的export JAVA_HOME行替換爲JAVA_HOME的絕對路徑:
export JAVA_HOME=/software/jdk1.8.0_202
根據自己的實際環境配置。注意,我開始覺得沒必要修改,因爲JAVA_HOME全局變量已經在/etc/profile中聲明瞭,且測試shell腳本echo出的變量值也對,運行Hadoop卻報錯,看樣必須要設置成絕對路徑。
10.3.2 配置core-site.xml,在<configuration>標籤內加入(如果裏面有內容,則替換)如下內容:
<property>
<!-- hdfs默認文件系統名 -->
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<!-- 序列文件的緩衝區大小 -->
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>
<!-- 臨時文件目錄-->
<property>
<name>hadoop.tmp.dir</name>
<value>file:/hadoop/hadoop-2.9.2/tmp_ha</value>
</property>
<!-- 指定ZKFC故障自動切換轉移 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>namenode:2181,datanode1:2181</value>
</property>
10.3.3 配置hdfs-site.xml
<!-- reducer獲取數據的方式 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!--啓用ResourceManager ha-->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!--啓用ResourceManager ha自動切換-->
<property>
<name>yarn.resourcemanager.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!--聲明兩臺ResourceManager的地址-->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>rmCluster</value>
</property>
<!--定義兩臺ResourceManager的rm-id-->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!--定義rm-id爲rm1的ResourceManager的主機名-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>namenode</value>
</property>
<!--定義rm-id爲rm2的ResourceManager的主機名-->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>datanode2</value>
</property>
<!--指定zookeeper集羣的地址-->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>datanode1:2181,datanode2:2181,datanode3:2181</value>
</property>
<!--啓用自動恢復-->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!--指定ResourceManager的狀態信息存儲在zookeeper集羣-->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
至此,hdfs HA就配置完了。
10.4 在配置yarn ResourceManager時用到的配置文件是yarn-env.sh、yarn-site.xml
10.4.1 配置yarn-env.sh
將其中的export JAVA_HOME行替換爲JAVA_HOME的絕對路徑:
export JAVA_HOME=/software/jdk1.8.0_202
10.4.2 配置yarn-site.xml
<!-- reducer獲取數據的方式 -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!--啓用ResourceManager ha-->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!--啓用ResourceManager ha自動切換-->
<property>
<name>yarn.resourcemanager.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!--聲明兩臺ResourceManager的地址-->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>rmCluster</value>
</property>
<!--定義兩臺ResourceManager的rm-id-->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!--定義rm-id爲rm1的ResourceManager的主機名-->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>namenode</value>
</property>
<!--定義rm-id爲rm2的ResourceManager的主機名-->
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>datanode2</value>
</property>
<!--指定zookeeper集羣的地址-->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>datanode1:2181,datanode2:2181,datanode3:2181</value>
</property>
<!--啓用自動恢復-->
<property>
<name>yarn.resourcemanager.recovery.enabled</name>
<value>true</value>
</property>
<!--指定ResourceManager的狀態信息存儲在zookeeper集羣-->
<property>
<name>yarn.resourcemanager.store.class</name>
<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property>
至此,yarn HA就配置完了。
10.5 複製配置到其他3臺服務器
10.5.1 爲了省事,可以先配好一臺服務器,比如namenode,然後再用scp指令複製hadoop配置文件到其他機器上。
在其餘三臺服務器上分別用hadoop用戶執行:
scp -r namenode:/hadoop/hadoop-2.9.2/etc/hadoop /hadoop/hadoop-2.9.2/etc/hadoop
也可以反過來,只在namenode服務器上執行:
scp -r /hadoop/hadoop-2.9.2/etc/hadoop datanode1:/hadoop/hadoop-2.9.2/etc/hadoop
scp -r /hadoop/hadoop-2.9.2/etc/hadoop datanode1:/hadoop/hadoop-2.9.2/etc/hadoop
scp -r /hadoop/hadoop-2.9.2/etc/hadoop datanode1:/hadoop/hadoop-2.9.2/etc/hadoop
10.5.2 建議依據服務器在集羣中的角色做個性化配置
如果只是安裝個Hadoop HA集羣玩玩,可以按10.5.1那麼做;可如果想深入瞭解Hadoop的配置參數,建議結合官方文檔,對不同角色的服務器做個性化配置,少配一些不必要的參數。
11、啓動Hadoop HA集羣
(1)在任意ZooKeeper節點上執行:
hdfs zkfc -formatZK
(2)啓動ZKFC (ZookeeperFailoverController是用來監控NameNode狀態,協助實現主備NameNode切換的,所以僅僅在主備NameNode節點上啓動就行)
在namenode、datanode1上分別執行:
hadoop-daemon.sh start zkfc
用jps指令查看執行結果:
(3)啓動用於主備NameNode之間同步元數據信息的共享存儲系統JournalNode。在集羣中各個節點上執行。
兩個NameNode爲了數據同步,會通過一組稱作JournalNodes的獨立進程進行相互通信。當active狀態的NameNode的命名空間有任何修改時,會告知大部分的JournalNodes進程。standby狀態的NameNode有能力讀取JournalNodes中的變更信息,並且一直監控Edit log的變化,把變化應用於自己的命名空間。standby可以確保在集羣出錯時,命名空間狀態已經完全同步了。
按如上所說,只在NameNode上啓動JournalNode即可,可是JournalNode機制有額外的限制,需要N-1/2個節點且至少有3個節點,因此必須要在其他服務器上加一個JournalNode節點。
分別在namenode、datanode1、datanode2三臺JournalNode服務器上執行:
hadoop-daemon.sh start journalnode
用jps指令查看執行結果:
(4)格式化並啓動主NameNode
在namenode上執行:
hdfs namenode -format
用jps指令查看執行結果:
(5)在備NameNode上同步主NameNode的元數據信息
在datanode1上執行:
hdfs namenode -bootstrapStandby
如果安裝過程中出現問題,多次執行會有報錯,需要關掉服務或殺死進程,清空報錯提示的目錄。
(6)啓動備NameNode
在datanode1上執行:
hadoop-daemon.sh start namenode
用jps指令查看執行結果:
(7)主NameNode上啓動DataNode
在namenode上,啓動所有datanode
hadoop-daemons.sh start datanode
所有節點啓動完成後,驗證主備切換。
在瀏覽器中打開
http://namenode:50070/dfshealth.html#tab-overview
http://datanode1:50070/dfshealth.html#tab-overview
查看狀態
然後,在主NameNode(主機名namenode)上執行:
ps -ef|grep namenode-namenode #正常只要ps -ef|grep namenode即可,因爲我的主機名也叫namenode,所以需要改動一下
找到進程號後,
kill -9 剛剛找到的進程號
然後查看
http://datanode1:50070/dfshealth.html#tab-overview
無需查看namenode的網頁,想也知道進程被殺了根本打不開。
發現datanode1的狀態由standby變爲active,則驗證成功。
最後,不放心的話可以在namenode上啓動NameNode。可以看到,狀態由active變爲standby。
至此,hdfs HA就驗證完了。
注:
1)這裏也可以用hdfs haadmin指令查看NameNode狀態
hdfs haadmin -getServiceState nn2 #nn1、nn2爲上面定義的NameNode節點名
hdfs haadmin -getServiceState nn1 #報錯正常,因爲進程被kill了,還沒啓動
2)在驗證時也可以通過hdfs haadmin指令來進行主備切換,但這樣並不能驗證HA主備切換真的配置成功了。我最開始配置錯誤,這樣操作仍然可以驗證成功,可kill進程就無法驗證成功了,證明配置存在問題。
hdfs haadmin -failover nn1 nn2
(8)在主ResourceManager(namenode)、備(datanode2)上啓動Yarn
yarn-daemon.sh start resourcemanager
打開
http://namenode:8088/cluster/cluster
http://datanode2:8088/cluster/cluster
關掉resourcemanager服務,或者kill掉該進程後,驗證主備切換。
yarn-daemon.sh stop resourcemanager
此時,主ResourceManager網頁無法訪問。再次在namenode上啓動ResourceManager服務:
yarn-daemon.sh start resourcemanager
可以看到
至此,Yarn HA就驗證完了。
12、遇到的問題
(1)好多年沒關注Linux版本變更了,只是偶爾用到一些常用指令,在安裝CentOS 7時,發現好多指令都不能用了,比如SysV服務變成了systemd服務,導致chkconfig、service指令某些功能不能用了,系統建議用原生的systemctl指令。不禁感慨現在知識迭代太快了。
(2)因爲工作地點網絡環境所限,需要做額外工作。剛開始想配reposever連到阿里雲或者教育網作爲yum源,屢試不行,應該是殺毒軟件和網絡策略限制了,網絡不通。我記得以前直接用iso文件作爲yum源就行,我4臺服務器,只需要一臺做yum源,其他3臺用它當yum源,於是就按這個思路配置yum源。這樣,整個集羣就是純內網Hadoop集羣了。
(3)在配置ntp同步時,我打算用namenode作爲集羣ntp服務器,其他三臺datanode同步其時間,而namenode的時間由本機windows同步過去。其實可以用VMware Workstation自帶的時間同步。可我就是想試試windows ntp服務,於是又研究了一下,安裝了個njinx和ntp,最終實現同步。
但在驗證時驗證過早,總以爲配置有問題,因爲幾年前裝過ntp服務,大致知道怎麼配,可怎麼也找不到哪兒配置錯了。最後偶然發現ntpstat -p居然同步了,證明配置沒問題,搜了下資料才發現ntp第一次同步會有一定的延遲。
(4)在配置hdfs HA時,將ssh驗證那塊的私鑰當成公鑰了,以爲是ssh互信呢,給改成authorized_keys了,後來看log才找到原因。
(5)改完ssh後,發現kill進程主備切換還是失敗,查看log和hadoop java源碼才發現調用的是fuser指令,而CentOS 7最小化安裝默認是不安裝fuser對應的軟件包的。於是:
yum install psmisc
安裝好後,再次驗證,果然成功了!你說這有多坑吧,所以建議想省心的還是完整安裝操作系統吧,省着少這包那包的。
總結,架構整體挺簡單,但因涉及到的方面比較多,再加上環境原因,導致在配yum源、ntp時間同步和驗證hdfs HA時多花了些時間。在hadoop配置方面,多看看官方文檔,挺簡單的,但也不能盡信之,因爲這個文檔好像很久沒更新了,連支持的jdk都是7,聽說java是3個版本一個大版本,所以jdk 6、7、8應該差異不大。