Hadoop高可用集群


Hadoop高可用集群

由於一個HDFS集群由一個NameNode節點和多個DataNode節點組成,一旦NameNode節點宕機,那么HDFS將不能進行文件的上傳與下載。 

由於一個Yarn集群由一個ResourceManager節點和多個NodeManager節點組成,一旦ResourceManager節點宕機,那么YARN集群將不能進行資源的調度。

Hadoop各個模塊剖析:https://www.cnblogs.com/funyoung/p/9889719.html

Hadoop集群管理:https://www.cnblogs.com/funyoung/p/9920828.html

 

1.搭建HDFS的高可用集群

由於一個HDFS集群由一個NameNode節點和多個DataNode節點組成,一旦NameNode節點宕機,那么HDFS將不能進行文件的上傳與下載。

Hadoop依賴Zookeeper實現HDFS集群的高可用,由狀態為Active的NameNode節點對外提供服務,而狀態為StandBy的NameNode節點則負責數據的同步,一旦狀態為Active的NameNode節點宕機,則狀態為StandBy的NameNode節點將會切換為Active狀態對外提供服務。

 

 

 

 

 

 

 

 

 

 

 

 

 

Hadoop提供了NameService進程,其是NameNode的代理,客戶端直接訪問的是NameService,NameService會將請求轉發給狀態為Active的NameNode。

當啟動HDFS時,DataNode節點會同時向兩個NameNode節點進行注冊。

 

關於NameService如何進行狀態轉移

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

 

關於NameNode之間的數據如何進行同步

Hadoop提供了JournalNode用於存放NameNode中的編輯日志,當狀態為Active的NameNode節點執行任何名稱空間上的修改時,它都會將修改保存到JournalNode集群中,而狀態為StandBy的NameNode節點會實時的從JournalNode集群中進行同步。

 

1.1 修改配置

 

1.安裝並配置Zookeeper集群

 

2.配置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的可視化管理界面的地址 -->  
  <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中的備份數(小於等於DataNode) -->  
  <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>

 

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

<configuration> 
  <!-- Hadoop工作目錄,用於存放Hadoop運行時產生的臨時數據 -->
  <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

 

1.2 啟動HDFS高可用集群

 

1.分別啟動JournalNode

 

 

 

 

 

 

 

 

 

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

 

 

 

 

 

 

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

 

 

4.啟動第二個NameNode

 

 

 

 

5.啟動Zookeeper集群

 

 

 

 

 

 

 

 

 

 

 

 

 

6.格式化Zookeeper

 

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

 

7.重啟HDFS集群

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

當HDFS高可用集群啟動后,可以分別訪問NameNode的可視化管理界面查看NameNode的狀態狀態,http://192.168.1.80:50070http://192.168.1.81:50070

 

img

img

 

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

 

 

 

 

此時訪問NameNode可視化管理界面,可以查看到主機名為hadoop1的NameNode節點其狀態從StandBy切換成Active。

 

img

 

1.3 JAVA操作HDFS高可用集群

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

/**
 * @Auther: ZHUANGHAOTANG
 * @Date: 2018/11/6 11:49
 * @Description:
 */
public class HDFSUtils {
​
    private static Logger logger = LoggerFactory.getLogger(HDFSUtils.class);
​
    /**
     * NameNode Service
     */
    private static final String NAMESERVER_URL = "hdfs://mycluster:8020";
​
    /**
     * NameNode服務列表
     */
    private static final String[] NAMENODE_URLS = {"192.168.1.80:8020", "192.168.1.81:8020"};
​
    /**
     * HDFS文件系統連接對象
     */
    private static FileSystem fs = null;
​
    static {
        Configuration conf = new Configuration();
        //指定默認連接的NameNode,使用NameService的地址
        conf.set("fs.defaultFS", NAMESERVER_URL);
        //指定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", NAMENODE_URLS[0]);
        conf.set("dfs.namenode.rpc-address.mycluster.nn2", NAMENODE_URLS[1]);
        //配置NameNode失敗自動切換的方式
        conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
        try {
            fs = FileSystem.get(URI.create(NAMESERVER_URL), conf);
        } catch (IOException e) {
            logger.info("初始化HDFS連接失敗:{}", e);
        }
    }
​
    /**
     * 創建目錄
     */
    public static void mkdir(String dir) throws Exception {
        dir = NAMESERVER_URL + dir;
        if (!fs.exists(new Path(dir))) {
            fs.mkdirs(new Path(dir));
        }
    }
​
    /**
     * 刪除目錄或文件
     */
    public static void delete(String dir) throws Exception {
        dir = NAMESERVER_URL + dir;
        fs.delete(new Path(dir), true);
    }
​
    /**
     * 遍歷指定路徑下的目錄和文件
     */
    public static List<String> listAll(String dir) throws Exception {
        List<String> names = new ArrayList<>();
        dir = NAMESERVER_URL + dir;
        FileStatus[] files = fs.listStatus(new Path(dir));
        for (FileStatus file : files) {
            if (file.isFile()) { //文件
                names.add(file.getPath().toString());
            } else if (file.isDirectory()) { //目錄
                names.add(file.getPath().toString());
            } else if (file.isSymlink()) { //軟或硬鏈接
                names.add(file.getPath().toString());
            }
        }
        return names;
    }
​
    /**
     * 上傳當前服務器的文件到HDFS中
     */
    public static void uploadLocalFileToHDFS(String localFile, String hdfsFile) throws Exception {
        hdfsFile = NAMESERVER_URL + hdfsFile;
        Path src = new Path(localFile);
        Path dst = new Path(hdfsFile);
        fs.copyFromLocalFile(src, dst);
    }
​
    /**
     * 通過流上傳文件
     */
    public static void uploadFile(String hdfsPath, InputStream inputStream) throws Exception {
        hdfsPath = NAMESERVER_URL + hdfsPath;
        FSDataOutputStream os = fs.create(new Path(hdfsPath));
        BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
        byte[] data = new byte[1024];
        int len;
        while ((len = bufferedInputStream.read(data)) != -1) {
            if (len == data.length) {
                os.write(data);
            } else { //最后一次讀取
                byte[] lastData = new byte[len];
                System.arraycopy(data, 0, lastData, 0, len);
                os.write(lastData);
            }
        }
        inputStream.close();
        bufferedInputStream.close();
        os.close();
    }
​
    /**
     * 從HDFS中下載文件
     */
    public static byte[] readFile(String hdfsFile) throws Exception {
        hdfsFile = NAMESERVER_URL + hdfsFile;
        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();
            return data;
        } else {
            throw new Exception("File Not Found In HDFS");
        }
    }
​
}

 

 

2.搭建YARN高可用集群

由於一個Yarn集群由一個ResourceManager節點和多個NodeManager節點組成,一旦ResourceManager節點宕機,那么YARN集群將不能進行資源的調度。

 

 

 

 

 

 

 

 

 

Hadoop依賴Zookeeper實現YARN集群的高可用,首先啟動兩個ResourceManager,且由狀態為Active的ResourceManager節點對外提供服務,而狀態為StandBy的ResourceManager節點則負責數據的同步,一旦狀態為Active的ResourceManager節點宕機,則狀態為StandBy的ResourceManager節點將會切換為Active狀態,對外提供服務。

 

2.1 修改配置

 

1.安裝並配置Zookeeper集群

 

2.配置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使用的存儲方式(實現類)

#保存在ZK當中
org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore
​
#保存在HDFS中
org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore
​
#保存在本地
org.apache.hadoop.yarn.server.resourcemanager.recovery.LeveldbRMStateStore 

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

 

2.2 啟動YARN高可用集群

 

1.在ResourceManager節點中啟動YARN集群

 

 

 

 

 

 

 

 

 

2.手動啟動另一個ResourceManager

img

 

3.當啟動YARN高可用集群后,可以分別訪問ResourceManager的可視化管理界面,http://192.168.1.80:8088http://192.168.1.81:8088

當訪問狀態為StandBy的ResourceManager時,將會將請求重定向到狀態為Active的ResourceManager的可視化管理界面。

 

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

 

 

 

 

 

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM