Hadoop高可用集羣

若HDFS集羣中只配置了一個NameNode,那麼當該NameNode所在的節點宕機,則整個HDFS就不能進行文件的上傳和下載。

若YARN集羣中只配置了一個ResourceManager,那麼當該ResourceManager所在的節點宕機,則整個YARN就不能進行任務的計算。

*Hadoop依賴Zookeeper進行各個模塊的HA配置,其中狀態爲Active的節點對外提供服務,而狀態爲StandBy的節點則只負責數據的同步,在必要時提供快速故障轉移。

2.HDFS HA集羣

2.1 模型

當有兩個NameNode時,提供哪個NameNode地址給客戶端?

 

1.Hadoop提供了NameService進程,其是NameNode的代理,維護NameNode列表並存儲NameNode的狀態,客戶端直接訪問的是NameService,NameService會將請求轉發給當前狀態爲Active的NameNode。

2.當啓動HDFS時,DataNode將同時向兩個NameNode進行註冊。

怎樣發現NameNode無法提供服務以及如何進行NameNode間狀態的切換?

 

1.Hadoop提供了FailoverControllerActive和FailoverControllerStandBy兩個進程用於NameNode的生命監控。

2.FailoverControllerActive和FailoverControllerStandBy會分別監控對應狀態的NameNode,若NameNode無異常則定期向Zookeeper集羣發送心跳,若在一定時間內Zookeeper集羣沒收到FailoverControllerActive發送的心跳,則認爲此時狀態爲Active的NameNode已經無法對外提供服務,因此將狀態爲StandBy的NameNode切換爲Active狀態。

NameNode之間的數據如何進行同步和共享?

1.Hadoop提供了JournalNode用於存放NameNode中的編輯日誌。

2.當激活的NameNode執行任何名稱空間上的修改時,它將修改的記錄保存到JournalNode集羣中,備用的NameNode能夠實時監控JournalNode集羣中日誌的變化,當監控到日誌發生改變時會將其同步到本地。

*當狀態爲Active的NameNode無法對外提供服務時,Zookeeper將會自動的將處於StandBy狀態的NameNode切換成Active。

2.2 HDFS HA高可用集羣搭建

1.配置HDFS(hdfs-site.xml)

<configuration>

<!-- 指定NameService的名稱 -->

<property>

<name>dfs.nameservices</name>

<value>mycluster</value>

</property>

<!-- 指定NameService下兩個NameNode的名稱 -->

<property>

<name>dfs.ha.namenodes.mycluster</name>

<value>nn1,nn2</value>

</property>

<!-- 分別指定NameNode的RPC通訊地址 -->

<property>

<name>dfs.namenode.rpc-address.mycluster.nn1</name>

<value>192.168.1.80:8020</value>

</property>

<property>

<name>dfs.namenode.rpc-address.mycluster.nn2</name>

<value>192.168.1.81:8020</value>

</property>

<!-- 分別指定NameNode的Web監控頁面地址 -->

<property>

<name>dfs.namenode.http-address.mycluster.nn1</name>

<value>192.168.1.80:50070</value>

</property>

<property>

<name>dfs.namenode.http-address.mycluster.nn2</name>

<value>192.168.1.81:50070</value>

</property>

<!-- 指定NameNode編輯日誌存儲在JournalNode集羣中的目錄-->

<property>

<name>dfs.namenode.shared.edits.dir</name>

<value>qjournal://192.168.1.80:8485;192.168.1.81:8485;192.168.1.82:8485/mycluster</value>

</property>

<!-- 指定JournalNode集羣存放日誌的目錄-->

<property>

<name>dfs.journalnode.edits.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/journalnode</value>

</property>

<!-- 配置NameNode失敗自動切換的方式-->

<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</value>

</property>

<!-- 由於使用SSH,那麼需要指定密鑰的位置-->

<property>

<name>dfs.ha.fencing.ssh.private-key-files</name>

<value>/root/.ssh/id_rsa</value>

</property>

<!-- 開啓失敗故障自動轉移-->

<property>

<name>dfs.ha.automatic-failover.enabled</name>

<value>true</value>

</property>

<!-- 配置Zookeeper地址-->

<property>

<name>ha.zookeeper.quorum</name>

<value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>

</property>

<!-- 文件在HDFS中的備份數(小於等於NameNode) -->

<property>

<name>dfs.replication</name>

<value>3</value>

</property>

<!-- 關閉HDFS的訪問權限 -->

<property>

<name>dfs.permissions.enabled</name>

<value>false</value>

</property>

<!-- 指定一個配置文件,使NameNode過濾配置文件中指定的host -->

<property>

<name>dfs.hosts.exclude</name>

<value>/usr/hadoop/hadoop-2.9.0/etc/hadoop/hdfs.exclude</value>

</property>

</configuration>

*指定NameNode的RPC通訊地址是爲了接收FailoverControllerActive和FailoverControllerStandBy以及DataNode發送的心跳。

2.配置Hadoop公共屬性(core-site.xml)

<configuration>

<!-- Hadoop工作目錄,用於存放Hadoop運行時NameNode、DataNode產生的數據 -->

<property>

<name>hadoop.tmp.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/data</value>

</property>

<!-- 默認NameNode,使用NameService的名稱 -->

<property>

<name>fs.defaultFS</name>

<value>hdfs://mycluster</value>

</property>

<!-- 開啓Hadoop的回收站機制,當刪除HDFS中的文件時,文件將會被移動到回收站(/usr/<username>/.Trash),在指定的時間過後再對其進行刪除,此機制可以防止文件被誤刪除 -->

<property>

<name>fs.trash.interval</name>

<!-- 單位是分鐘 -->

<value>1440</value>

</property>

</configuration>

*在HDFS HA集羣中,StandBy的NameNode會對namespace進行checkpoint操作,因此就不需要在HA集羣中運行SecondaryNameNode、CheckpintNode、BackupNode。

2.啓動HDFS HA高可用集羣

1.分別啓動JournalNode

 

 

 

2.格式化第一個NameNode並啓動

 

 

3.第二個NameNode同步第一個NameNode的信息

 

4.啓動第二個NameNode

 

5.啓動Zookeeper集羣

 

 

 

6.格式化Zookeeper

 

*當格式化ZK後,ZK中將會多了hadoop-ha節點。

7.重啓HDFS集羣

 

 

當HDFS HA集羣啓動完畢後,可以分別訪問NameNode管理頁面查看當前NameNode的狀態

 

 

*可以查看到主機名爲hadoop1的NamNode其狀態爲StandBy,而主機名爲hadoop2的NameNode其狀態爲Active。

8.模擬NameNode宕機,手動殺死進程。

 

此時訪問NameNode管理頁面,可見主機名爲hadoop1的NameNode其狀態從原本的StandBy切換成Active。

 

2.3 JAVA操作HDFS HA集羣

*由於在HDFS HA集羣中存在兩個NameNode,且服務端暴露的是NameService,因此在通過JAVA連接HDFS HA集羣時需要使用Configuration實例進行相關的配置。

/**

* @Auther: ZHUANGHAOTANG

* @Date: 2018/11/6 11:49

* @Description:

*/

public class HDFSUtils {

/**

* HDFS NamenNode URL

*/

private static final String NAMENODE_URL = "hdfs://mycluster:8020";

/**

* 配置項

*/

private static Configuration conf = null;

static {

conf = new Configuration();

//指定默認連接的NameNode,使用NameService的名稱

conf.set("fs.defaultFS", "hdfs://mycluster");

//指定NameService的名稱

conf.set("dfs.nameservices", "mycluster");

//指定NameService下的NameNode列表

conf.set("dfs.ha.namenodes.mycluster", "nn1,nn2");

//分別指定NameNode的RPC通訊地址

conf.set("dfs.namenode.rpc-address.mycluster.nn1", "hadoop1:8020");

conf.set("dfs.namenode.rpc-address.mycluster.nn2", "hadoop2:8020");

//配置NameNode失敗自動切換的方式

conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");

}

/**

* 創建目錄

*/

public static void mkdir(String dir) throws Exception {

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

if (!fs.exists(new Path(dir))) {

fs.mkdirs(new Path(dir));

}

fs.close();

}

/**

* 刪除目錄或文件

*/

public static void delete(String dir) throws Exception {

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

fs.delete(new Path(dir), true);

fs.close();

}

/**

* 遍歷指定路徑下的目錄和文件

*/

public static List<String> listAll(String dir) throws Exception {

List<String> names = new ArrayList<>();

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(dir), conf);

FileStatus[] files = fs.listStatus(new Path(dir));

for (int i = 0, len = files.length; i < len; i++) {

if (files[i].isFile()) { //文件

names.add(files[i].getPath().toString());

} else if (files[i].isDirectory()) { //目錄

names.add(files[i].getPath().toString());

} else if (files[i].isSymlink()) { //軟或硬鏈接

names.add(files[i].getPath().toString());

}

}

fs.close();

return names;

}

/**

* 上傳當前服務器的文件到HDFS中

*/

public static void uploadLocalFileToHDFS(String localFile, String hdfsFile) throws Exception {

if (StringUtils.isBlank(localFile) || StringUtils.isBlank(hdfsFile)) {

throw new Exception("Parameter Is NULL");

}

hdfsFile = NAMENODE_URL + hdfsFile;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

Path src = new Path(localFile);

Path dst = new Path(hdfsFile);

fs.copyFromLocalFile(src, dst);

fs.close();

}

/**

* 通過流上傳文件

*/

public static void uploadFile(String hdfsPath, InputStream inputStream) throws Exception {

if (StringUtils.isBlank(hdfsPath)) {

throw new Exception("Parameter Is NULL");

}

hdfsPath = NAMENODE_URL + hdfsPath;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

FSDataOutputStream os = fs.create(new Path(hdfsPath));

BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

byte[] data = new byte[1024];

while (bufferedInputStream.read(data) != -1) {

os.write(data);

}

os.close();

fs.close();

}

/**

* 從HDFS中下載文件

*/

public static byte[] readFile(String hdfsFile) throws Exception {

if (StringUtils.isBlank(hdfsFile)) {

throw new Exception("Parameter Is NULL");

}

hdfsFile = NAMENODE_URL + hdfsFile;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

Path path = new Path(hdfsFile);

if (fs.exists(path)) {

FSDataInputStream is = fs.open(path);

FileStatus stat = fs.getFileStatus(path);

byte[] data = new byte[(int) stat.getLen()];

is.readFully(0, data);

is.close();

fs.close();

return data;

} else {

throw new Exception("File Not Found In HDFS");

}

}

}

2.YARN HA集羣

2.1 模型

 

*啓動兩個ResourceManager後分別向Zookeeper註冊,通過Zookeeper管理他們的狀態,一旦狀態爲Active的ResourceManager無法正常提供服務,Zookeeper將會立即將狀態爲StandBy的ResourceManager切換爲Active。

2.2 YARN HA高可用集羣搭建

1.配置YARN(yarn-site.xml)

<configuration>

<!-- 配置Reduce取數據的方式是shuffle(隨機) -->

<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>864000</value>

</property>

<!-- 設置yarn的內存大小,單位是MB -->

<property>

<name>yarn.nodemanager.resource.memory-mb</name>

<value>8192</value>

</property>

<!-- 設置yarn的CPU核數 -->

<property>

<name>yarn.nodemanager.resource.cpu-vcores</name>

<value>8</value>

</property>

<!-- YARN HA配置 -->

<!-- 開啓yarn ha -->

<property>

<name>yarn.resourcemanager.ha.enabled</name>

<value>true</value>

</property>

<!-- 指定yarn ha的名稱 -->

<property>

<name>yarn.resourcemanager.cluster-id</name>

<value>cluster1</value>

</property>

<!-- 分別指定兩個ResourceManager的名稱 -->

<property>

<name>yarn.resourcemanager.ha.rm-ids</name>

<value>rm1,rm2</value>

</property>

<!-- 分別指定兩個ResourceManager的地址 -->

<property>

<name>yarn.resourcemanager.hostname.rm1</name>

<value>192.168.1.80</value>

</property>

<property>

<name>yarn.resourcemanager.hostname.rm2</name>

<value>192.168.1.81</value>

</property>

<!-- 分別指定兩個ResourceManager的Web訪問地址 -->

<property>

<name>yarn.resourcemanager.webapp.address.rm1</name>

<value>192.168.1.80:8088</value>

</property>

<property>

<name>yarn.resourcemanager.webapp.address.rm2</name>

<value>192.168.1.81:8088</value>

</property>

<!-- 配置使用的Zookeeper集羣 -->

<property>

<name>yarn.resourcemanager.zk-address</name>

<value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>

</property>

<!-- ResourceManager Restart配置 -->

<!-- 啓用ResourceManager的restart功能,當ResourceManager重啓時將會保存運行時信息到指定的位置,重啓成功後再進行讀取 -->

<property>

<name>yarn.resourcemanager.recovery.enabled</name>

<value>true</value>

</property>

<!-- ResourceManager Restart使用的存儲方式(實現類) -->

<property>

<name>yarn.resourcemanager.store.class</name>

<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>

</property>

<!-- ResourceManager重啓時數據保存在Zookeeper中的目錄 -->

<property>

<name>yarn.resourcemanager.zk-state-store.parent-path</name>

<value>/rmstore</value>

</property>

<!-- NodeManager Restart配置 -->

<!-- 啓用NodeManager的restart功能,當NodeManager重啓時將會保存運行時信息到指定的位置,重啓成功後再進行讀取 -->

<property>

<name>yarn.nodemanager.recovery.enabled</name>

<value>true</value>

</property>

<!-- NodeManager重啓時數據保存在本地的目錄 -->

<property>

<name>yarn.nodemanager.recovery.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/data/rsnodemanager</value>

</property>

<!-- 配置NodeManager的RPC通訊端口 -->

<property>

<name>yarn.nodemanager.address</name>

<value>0.0.0.0:45454</value>

</property>

</configuration>

ResourceManager Restart使用的存儲方式(實現類)

1.ResourceManager運行時的數據保存在ZK中:org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore

2.ResourceManager運行時的數據保存在HDFS中:org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore

3.ResourceManager運行時的數據保存在本地:org.apache.hadoop.yarn.server.resourcemanager.recovery.LeveldbRMStateStore

*使用不同的存儲方式將需要額外的配置項,可參考官網,http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/ResourceManagerRestart.html

2.啓動YARN HA高可用集羣

1.在ResourceManager所在節點中啓動YARN集羣

 

2.手動啓動另一個ResourceManager

 

*當啓動YARN HA集羣后,可以分別訪問ResourceManager管理頁面,http://192.168.1.80:8088、http://192.168.1.81:8088。

訪問狀態爲StandBy的ResourceManager時,會將請求重定向到狀態爲Active的ResourceManager的管理頁面。

3.模擬ResourceManager宕機,手動殺死進程

 

*Zookeeper在一定時間內無法接收到狀態爲Active的ResourceManager發送的心跳時,將會立即將狀態爲StandBy的ResourceManager切換爲Active。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章