前文
- 一、CentOS7 hadoop3.3.1安裝(單機分布式、偽分布式、分布式
- 二、JAVA API實現HDFS
- 三、MapReduce編程實例
- 四、Zookeeper3.7安裝
- 五、Zookeeper的Shell操作
- 六、Java API操作zookeeper節點
Hadoop3.3.1 HA 高可用集群的搭建
(基於Zookeeper,NameNode高可用+Yarn高可用)
QJM 的 NameNode HA
用Quorum Journal Manager或常規共享存儲
QJM的NameNode HA
Hadoop HA模式搭建(高可用)
1、集群規划
一共三台虛擬機,分別為master、worker1、worker2;
namenode三台上都有,resourcemanager在worker1,woker2上。
| master | woker1 | worker2 | |
|---|---|---|---|
| NameNode | yes | yes | yes |
| DataNode | no | yes | yes |
| JournalNode | yes | yes | yes |
| NodeManager | no | yes | yes |
| ResourceManager | no | yes | yes |
| Zookeeper | yes | yes | yes |
| ZKFC | yes | yes | yes |
因為沒有重新創建虛擬機,是在原本的基礎上修改。所以名稱還是hadoop1,hadoop2,hadoop3
hadoop1 = master
hadoop2 = worker1
hadoop3 = worker2
2、Zookeeper集群搭建:
3、修改Hadoop集群配置文件
修改 vim core-site.xml
vim core-site.xml
core-site.xml:
<configuration>
<!-- HDFS主入口,mycluster僅是作為集群的邏輯名稱,可隨意更改但務必與
hdfs-site.xml中dfs.nameservices值保持一致-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
<!-- 默認的hadoop.tmp.dir指向的是/tmp目錄,將導致namenode與datanode>數據全都保存在易失目錄中,此處進行修改-->
<property>
<name>hadoop.tmp.dir</name>
<value>/export/servers/data/hadoop/tmp</value>
</property>
<!--用戶角色配置,不配置此項會導致web頁面報錯-->
<property>
<name>hadoop.http.staticuser.user</name>
<value>root</value>
</property>
<!--zookeeper集群地址,這里可配置單台,如是集群以逗號進行分隔-->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop1:2181,hadoop2:2181,hadoop3:2181</value>
</property>
<!-- hadoop鏈接zookeeper的超時時長設置 -->
<property>
<name>ha.zookeeper.session-timeout.ms</name>
<value>1000</value>
<description>ms</description>
</property>
</configuration>
上面指定 zookeeper 地址中的Hadoop1,hadoop2,hadoop3換成你自己機器的主機名(要先配置好主機名與 IP 的映射)或者 ip
修改 hadoop-env.sh
vim hadoop-env.sh
hadoop-env.sh
在使用集群管理腳本的時候,由於使用ssh進行遠程登錄時不會讀取/etc/profile文件中的環境變量配置,所以使用ssh的時候java命令不會生效,因此需要在配置文件中顯式配置jdk的絕對路徑(如果各個節點的jdk路徑不一樣的話那hadoop-env.sh中應改成本機的JAVA_HOME)。
hadoop 3.x中對角色權限進行了嚴格限制,相比於hadoop 2.x要額外對角色的所屬用戶進行規定。
此處僅為搭建HDFS集群,如果涉及到YARN等內容的話應一並修改對應yarn-env.sh等文件中的配置
在腳本末尾添加以下內容:
export JAVA_HOME=/opt/jdk1.8.0_241
export HDFS_NAMENODE_USER="root"
export HDFS_DATANODE_USER="root"
export HDFS_ZKFC_USER="root"
export HDFS_JOURNALNODE_USER="root"
修改 hdfs-site.xml
vim hdfs-site.xml
hdfs-site.xml
<configuration>
<!-- 指定副本數 -->
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<!-- 配置namenode和datanode的工作目錄-數據存儲目錄 -->
<property>
<name>dfs.namenode.name.dir</name>
<value>/export/servers/data/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/export/servers/data/hadoop/tmp/dfs/data</value>
</property>
<!-- 啟用webhdfs -->
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
<!--指定hdfs的nameservice為cluster1,需要和core-site.xml中的保持一致
dfs.ha.namenodes.[nameservice id]為在nameservice中的每一個NameNode設置唯一標示符。
配置一個逗號分隔的NameNode ID列表。這將是被DataNode識別為所有的NameNode。
例如,如果使用"cluster1"作為nameservice ID,並且使用"nn1"和"nn2"作為NameNodes標示符
-->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<!-- cluster下面有3個NameNode,分別是nn1,nn2,nn3-->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2,nn3</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>hadoop1:9000</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>hadoop1:9870</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>hadoop2:9000</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>hadoop2:9870</value>
</property>
<!-- nn3的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn3</name>
<value>hadoop3:9000</value>
</property>
<!-- nn3的http通信地址 -->
<property>
<name>dfs.namenode.http-address.mycluster.nn3</name>
<value>hadoop3:9870</value>
</property>
<!-- 指定NameNode的edits元數據的共享存儲位置。也就是JournalNode列表
該url的配置格式:qjournal://host1:port1;host2:port2;host3:port3/journalId
journalId推薦使用nameservice,默認端口號是:8485 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop1:8485;hadoop2:8485;hadoop3:8485/mycluster</value>
</property>
<!-- 指定JournalNode在本地磁H的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/export/servers/data/hadoop/tmp/journaldata</value>
</property>
<!-- 開啟NameNode失敗自動切換 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 配置失敗自動切換實現方式 -->
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔離機制方法,多個機制用換行分割,即每個機制暫用一行 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔離機制時需要ssh免登陸 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔離機制超時時間 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
<property>
<name>ha.failover-controller.cli-check.rpc-timeout.ms</name>
<value>60000</value>
</property>
<!--指定輔助名稱節點-->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop3:9868</value>
</property>
</configuration>
要創建journaldata文件夾
workers
在hadoop 2.x中這個文件叫slaves,配置所有datanode的主機地址,只需要把所有的datanode主機名填進去就好了
hadoop1
hadoop2
hadoop3
Yarn高可用
vim mapred-site.xml
修改 mapred-site.xml
<configuration>
<!-- 指定mr框架為yarn方式 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<!-- 配置 MapReduce JobHistory Server 地址 ,默認端口10020 -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>hadoop1:10020</value>
</property>
<!-- 配置 MapReduce JobHistory Server web ui 地址, 默認端口19888 -->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop1:19888</value>
</property>
</configuration>
vim yarn-site.xml
修改 yarn-site.xml
<configuration>
<!-- 開啟RM高可用 -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 指定RM的cluster id -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yrc</value>
</property>
<!-- 指定RM的名字 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- 分別指定RM的地址 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop2</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop3</value>
</property>
<!-- 指定zk集群地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop1:2181,hadoop2:2181,hadoop2:2181</value>
</property>
<!--Reducer獲取數據的方式-->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<!--日志聚集功能開啟-->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<!--日志保留時間設置1天-->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>86400</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>
</configuration>
都修改好了,就分發給其他集群節點
(在hadoop/etc路徑下)
scp /export/servers/hadoop-3.3.1/etc/hadoop/* hadoop2:/export/servers/hadoop-3.3.1/etc/hadoop/
scp /export/servers/hadoop-3.3.1/etc/hadoop/* hadoop3:/export/servers/hadoop-3.3.1/etc/hadoop/
啟動zookeeper集群
在每台機器上啟動:
zkServer.sh start
zkServer.sh status

格式化namenode、zkfc
首先,在所有虛擬機上啟動journalnode:
hdfs --daemon start journalnode

都啟動完畢之后,在master(hadoop1)節點上,格式化namenode
hadoop namenode -format
因為之前搭建過完全分布式,所以格式化一次namenode
但是,集群中的datanode,namenode與/current/VERSION/中的
CuluserID有關所以再次格式化,並啟動,其他兩個節點同步格式化好的namenode並不沖突
formatZK同理
然后單獨啟動namenode:
hdfs namenode

然后,在另外兩台機器上,同步格式化好的namenode:
hdfs namenode -bootstrapStandby
應該能從master上看到傳輸信息。
傳輸完成后,在master節點上,格式化zkfc:
hdfs zkfc -formatZK
啟動hdfs
在master節點上,先啟動dfs:
start-dfs.sh
然后啟動yarn:
start-yarn.sh
啟動mapreduce任務歷史服務器:
mapred --daemon start historyserver
可以看到各個節點的進程啟動情況:

如果datanode未啟動
是版本號不一致產生的問題,那么我們就單獨解決版本號的問題,將你格式化之后的NameNode的VERSION文件找到,然后將里面的clusterID進行復制,再找到DataNode的VERSION文件,將里面的clusterID進行替換,保存之后重啟
嘗試HA模式
首先看看各個namenode主機狀態:
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
hdfs haadmin -getServiceState nn3

可以看到,有兩個standby,一個active。
在active的master節點上,kill掉namenode進程:
此時再次查看節點

可以看到,nn1已經切換為active,Hadoop 高可用集群基本搭建完成。
