2013年10月30日 星期三

[ 深入雲計算 ] Hadoop 的安裝和配置: Linux 配置 1 NameNode + 2 DataNode

Preface: 
為了要能跑後續的 Hadoop 範例, 我們要先準備好 Hadoop 的環境. 這邊安裝的平台是 Linux Ubuntu 11.x. NameNode 與 DataNode 配置如下: 
* NameNode: Hostname="ubuntun" ; IP=192.168.80.180; Mem=2G; Storage=10G
* DataNode1: Hostname="ubuntud1"; IP=192.168.80.191; Mem=512M; Storage=10G
* DataNode2: Hostname="ubuntud2"; IP=192.168.80.192; Mem=512M; Storage=10G

在只有一台機器下, 只能透過 VMWare 跑多個 OS. 這邊使用 VMWare Workstation 7.0.1 build-227600; OS 使用 ubuntu-11.10-server-i386.iso 安裝. 安裝 VM OS 的過程不會在下面進行說明, 所以底下列的步驟請自己完成: 
- 安裝 VMWare OS: 參考 這裡
- 在 OS 上要啟動 sshd 服務
- 在 OS 上要安裝 JDK: 參考 這裡
- NameNode 與 DataNodes 間的網絡要連得上.
- 將 NameNode, DataNodes 上面設成固定 IP: 參考 這裡
- 在 OS 上創建 Hadoop 專用的帳號, 下面的範例使用 "john" 為跑 Hadoop 的帳號.

設置 NameNode: 
Step1. 設置 Hostname 
我們的 NameNode 使用 IP=192.168.80.180; Hostname="ubuntun". 第一步我們要將 DataNode 的 Hostname 設置到 /etc/hosts: (紅色與棕色字體是註解!

上面的動作在兩個 DataNode 也要做類似的事, 千萬別忘記!!! 

Step2. 設置無密碼 SSH 登入 
詳細可見 [Linux 小學堂] SSH 免密碼登入, 這邊 NameNode 會做一次, 兩個 DataNode 就以此類推: 
# 你現在是登入在 NameNode, 並以要跑 Hadoop 的帳戶登入!!!!
$ ssh-keygen -t dsa -P "" # 產生 DSA 公鑰/私鑰
Generating public/private dsa key pair.
Enter file in which to save the key (/home/john/.ssh/id_dsa):
 # 按下 Enter
$ ls ~/.ssh
id_dsa id_dsa.pub ... # 產生的 dsa 檔案. .pub 結尾的是公鑰, 需要丟到其他想要無碼密登入的機器上!
$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys # 因為 Hadoop 會使用現在帳戶登入, 如果你不想每次啟動 Hadoop 就需要打密碼就...
$ scp /home/john/.ssh/id_dsa.pub john@ubuntud2:~/.ssh/id_dsa_180.pub # 將公鑰複製到 DataNode2 上面
$ ssh john@ubuntud2 # 第一次登入 DataNode2 需要密碼
$ cat ~/.ssh/id_dsa_180.pub >> ~/.ssh/authorized_keys # 現在在 DataNode2 上面
$ logout # 按下 Ctrl+D 登出
Connection to ubuntud2 closed.
$ ssh john@ubuntud2 # 此時再登入 DataNode2 就必須要密碼了. Ya

請確保 NameNode 登入到兩個 DataNode 都不需要密碼; 相同其他兩個 DataNode 登入到另外兩個 Node 也需要設定成不需要密碼. 

Step3. 設置 Hadoop 
接著要來布置 Hadoop 0.23 版本, 並做環境設定: 
# 你現在是在 NameNode!!!
$ wget http://ftp.unicamp.br/pub/apache/hadoop/common/had...op-0.23.9/hadoop-0.23.9.tar.gz # 下載 Hadoop
$ tar -xvf hadoop-0.23.9.tar.gz # 解壓縮
$ ln -s ./hadoop-0.23.9 hadoop # 建立連結, 你不想每次進到 hadoop 都打 "hadoop-0.23.9" 這一串字八...Orz. 另外也方便管理, 想想如果你有新版本 Hadoop 時...
$ sudo vi /etc/profile
...
# 加入下面兩行
export HADOOP_HOME="/home/john/hadoop-0.23.9"
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

$ . /etc/profile # 讓剛剛的設定生效
$ echo $HADOOP_HOME
/home/john/hadoop-0.23.9
$ sudo mkdir /home/hadoop/tmp # 建立 hadoop 暫存資料夾
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/tmp
$ sudo chmod 750 /home/hadoop # Set folder permissions
# 如果你的 NameNode 本地也有跑一個 DataNode, 則下面的設定是需要的!
$ sudo vi $HADOOP_HOME/etc/hadoop/core-site.xml # contains default values for core Hadoop properties.


# Create a copy of the template mapred-site.xml file 
$ sudo cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xml 

# Edit the copy we just created 
$ sudo vi $HADOOP_HOME/etc/hadoop/mapred-site.xml  --- 如果 NameNode local 沒有跑 DataNode, 此處略過!!! 




# By default, Hadoop will place DFS data node blocks in file://${hadoop.tmp.dir}/dfs/data (the property you have just configured in core-site.xml)
# 但你可以透過下面設定設置 HDFS 存放的位置, 方便管理!
$ sudo mkdir /home/hadoop/hdfs 
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/hdfs 
$ sudo chmod 750 /home/hadoop/hdfs
$ sudo vi $HADOOP_HOME/etc/hadoop/hdfs-site.xml # 添加下面的內容














# 上面的 dfs.replication 設定是說你要多少的副本數, 因為我們只有兩個 DataNode, 當然使用預設的 3 會出問題! 
$ sudo vi $HADOOP_HOME/etc/hadoop/slaves # 告訴 NameNode 有多少個 DataNode
  1. 192.168.80.191  
  2. 192.168.80.192  
# 如果 NameNode 處也要跑一個 DataNode, 則把 NameNode 的 IP 也加到上面, 此時就有 3 個 DataNode!
$ hdfs namenode -format # 這步對 NameNode 做初始化

目前已經完成大部分的設置, 接著要來看 DataNode 的設置. 

設置 DataNode: 
DataNode 有兩個, 看完下面就舉一反二搂. 
Step1. 設置 Hostname 
請參考 NameNode 的設置. 

Step2. 設置無密碼 SSH 登入 
請參考 NameNode 的設置. 

Step3. 設置 Hadoop 
接著要來布置 Hadoop 0.23 版本, 並做環境設定: 
# 你現在是在 DataNode!!!
$ wget http://ftp.unicamp.br/pub/apache/hadoop/common/had...op-0.23.9/hadoop-0.23.9.tar.gz # 下載 Hadoop
$ tar -xvf hadoop-0.23.9.tar.gz # 解壓縮
$ ln -s ./hadoop-0.23.9 hadoop # 建立連結, 你不想每次進到 hadoop 都打 "hadoop-0.23.9" 這一串字八...Orz. 另外也方便管理, 想想如果你有新版本 Hadoop 時...
$ sudo vi /etc/profile
...
# 加入下面兩行
export HADOOP_HOME="/home/john/hadoop-0.23.9"
export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH

$ . /etc/profile # 讓剛剛的設定生效
$ echo $HADOOP_HOME
/home/john/hadoop-0.23.9
$ sudo mkdir /home/hadoop/tmp # 建立 hadoop 暫存資料夾
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/tmp
$ sudo chmod 750 /home/hadoop # Set folder permissions
$ sudo vi $HADOOP_HOME/etc/hadoop/core-site.xml # contains default values for core Hadoop properties.












# 上面的 fs.defaultFS 要設置成 NameNode 的 IP. 因為 DataNode 會向 NameNode 發送 Heartbeat, 讓 NameNode 知道它還活著!


# Create a copy of the template mapred-site.xml file 
$ sudo cp $HADOOP_HOME/etc/hadoop/mapred-site.xml.template $HADOOP_HOME/etc/hadoop/mapred-site.xml 

mapred-site.xml – contains configuration information for MapReduce properties.
# Edit the copy we just created 

$ sudo vi $HADOOP_HOME/etc/hadoop/mapred-site.xml 










# 這邊設定的 Job Tracker 是用在 MapReduce 編程環境中, 在 MapReduce 中一個任務被稱為一個 Job, 透過 Job Tracker 分配 Task 給 DataNode 執行.


# By default, Hadoop will place DFS data node blocks in file://${hadoop.tmp.dir}/dfs/data (the property you have just configured in core-site.xml)
# 但你可以透過下面設定設置 HDFS 存放的位置, 方便管理!
hdfs-site.xml – contains server side configuration of your distributed file system.

$ sudo mkdir /home/hadoop/hdfs 
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/hdfs 
$ sudo chmod 750 /home/hadoop/hdfs 
$ sudo vi $HADOOP_HOME/etc/hadoop/hdfs-site.xml # 添加下面的內容














$ sudo vi hadoop/etc/hadoop/yarn-site.xml # 加入下面設定















到目前為止已經完成了對 DataNode 最基本的 Hadoop 設置. 

啟動 Hadoop Service: 
當 NameNode 與 DataNode 都設置完畢, 接下來便是啟動 Hadoop Services 並跑一個 word count 的範例: 
Step1: Check DataNode Log (Optional) 
請先登入一台 DataNode, (假設是 DataNode1), 並 tail follow data node 的 log: 
# 現在你在 DataNode1 並使用 "john" 帳號登入
$ tail -f hadoop/logs/hadoop-john-datanode-ubuntud1.log # log 的名稱根據你在的 datanode, 啟動服務的帳號有所不同.

Step2: 啟動 Hadoop 服務 
$ start-dfs.sh
Starting namenodes on [192.168.80.180]
192.168.80.180: starting namenode, logging to /home/john/hadoop-0.23.9/logs/hadoop-john-namenode-ubuntun.out
192.168.80.192: datanode running as process 3432. Stop it first.
192.168.80.191: starting datanode, logging to /home/john/hadoop-0.23.9/logs/hadoop-john-datanode-ubuntud1.out
Starting secondary namenodes [0.0.0.0]
0.0.0.0: starting secondarynamenode, logging to /home/john/hadoop-0.23.9/logs/hadoop-john-secondarynamenode-ubuntun.out

$ start-yarn.sh
starting yarn daemons
starting resourcemanager, logging to /home/john/hadoop-0.23.9/logs/yarn-john-resourcemanager-ubuntun.out
192.168.80.191: starting nodemanager, logging to /home/john/hadoop-0.23.9/logs/yarn-john-nodemanager-ubuntud1.out
192.168.80.192: starting nodemanager, logging to /home/john/hadoop-0.23.9/logs/yarn-john-nodemanager-ubuntu.out

$ jps # 確認該有的 services 都有起來
6459 Jps
6125 SecondaryNameNode
6205 ResourceManager
5939 NameNode

$ ssh 192.168.80.191 # 登入 DataNode1
$ jps
1822 DataNode - 確定 DataNode 服務有起來!!! 
2145 Jps
1234 NodeManager
 
確定 NodeManager 服務有起來!!! 
$ logout # Ctrl+D 登出 DataNode1, 回到 NameNode
Connection to 192.168.80.191 closed.
$ ssh 192.168.80.192 # 登入 DataNode2
$ jps
3432 DataNode 
確定 DataNode 服務有起來!!! 
5235 Jps
1108 NodeManager
 
確定 NodeManager 服務有起來!!!  

Step3 跑 Word count 測試程式 
接著我們要來跑一個 word count 的測試程式, 確定整個 Hadoop 服務運行正常. 
# 現在我們在 NameNode! /home/john 下
# The –p option make parent directories as needed. In practice, all folders in the mkdir path are created. 
$ mkdir -p ./examples/jverne 
$ cd ./examples/jverne 
$ wget http://www.textfiles.com/etext/FICTION/center_earth # 下載 word count 使用的檔案 
$ hdfs dfs -copyFromLocal ./examples / # 將 "./examples" 下的檔案目錄加到 hdfs 空間的 "/" 路徑下
$ hdfs dfs -ls /examples/jverne # 確定剛剛下載的檔案 "acenter_earth" 有進入 hdfs 檔案系統
Found 1 items
-rw-r--r-- 1 john supergroup 489319 2013-10-29 23:55 /examples/jverne/acenter_earth

# 開始來跑 Word Count 的 MapReduce 程式
$ hadoop jar $HADOOP_HOME/share/hadoop/mapreduce/hadoop-mapreduce-examples-0.23.9.jar wordcount /examples/jverne /examples/jverne/output
...
13/10/30 00:38:02 INFO mapreduce.Job: Job job_local1049373244_0001 completed successfully
13/10/30 00:38:02 INFO mapreduce.Job: Counters: 32
...

$ hdfs dfs -cat /examples/jverne/output/part-r-00000 # 顯示 Word count 的結果
...
yourselves, 1
youthful 1
zeal 1
zero! 1
zigzag 2
zigzags 1
zoophytes 1
 

關閉 Hadoop Service: 
如果要關閉 Hadoop 的服務可以使用下面命令: 
$ stop-dfs.sh
Stopping namenodes on [192.168.80.180]
192.168.80.180: stopping namenode
192.168.80.192: stopping datanode
192.168.80.191: stopping datanode
Stopping secondary namenodes [0.0.0.0]
0.0.0.0: stopping secondarynamenode

$ stop-yarn.sh
stopping yarn daemons
stopping resourcemanager
192.168.80.192: stopping nodemanager
192.168.80.191: stopping nodemanager
no proxyserver to stop

$ jps
14796 Jps

Supplement: 
[ 文章收集 ] HADOOP-0.23.9 SINGLE NODE SETUP ON UBUNTU 13.04 
Hadoop Shell Commands

2013年10月29日 星期二

[ 文章收集 ] HADOOP-0.23.9 SINGLE NODE SETUP ON UBUNTU 13.04

來源自 這裡
Preface:
In this post I will explain you how to install Hadoop in a brand new Linux distribution. This post is based on Michael G. Noll post Running Hadoop on Ubuntu Linux (Single-Node Cluster) which is still very handful but is somewhat outdated. We assume that you already have Ubuntu 13.04 installed and running. If not, you can download it here. After you have your Ubuntu 13.04 installed, we are ready to get Hadoop running.

STEP 1: Install Java
Since Ubuntu no longer come with Java, the first thing we have to do is install it. For the sake of simplicity, I will not go through this step by step. The post HOW TO INSTALL ORACLE JAVA 7 UPDATE 25 ON UBUNTU 13.04 LINUX has already done it so brilliantly.

STEP 2: Install SSH
As we are installing Hadoop in a clean version of Ubuntu 13.04, we also should have SSH server installed. A distributed Hadoop cluster requires SSH because is through SSH that Hadoop manage its nodes, e.g. starting and stopping slave nodes. The following command will do that.
$ sudo apt-get install openssh-server

STEP 3: Create a dedicated user
A new user is not required but in a large-scale environment I strongly recommend that you create a separate user account dedicated exclusively to Hadoop. This allows you to restrict the permissions to the mimimum needed by Hadoop. This account does not need to have extra privileges such as sudo privileges. It only needs to have read and write access to some directories in order to perform Hadoop tasks.

Now let’s create a dedicated user to Hadoop:
$ sudo addgroup hadoopgroup
$ sudo adduser --ingroup hadoopgroup hadoop

STEP 4: Configuring passphraseless SSH
To avoid entering passphrase every time Hadoop interacts with its nodes, let’s create an RSA keypair to manage authentication. The authorized_keys file holds public keys that are allowed to authenticate into the account the key is added to.
$ su - hadoop # 切換到 hadoop 帳號

# Creates an RSA keypair
# The -P "" specifies that an empty password should be used

$ ssh-keygen -t rsa -P ""

# Write the public key file for the generated RSA key into the authorized_key file
$ cat $HOME/.ssh/id_rsa.pub >> $HOME/.ssh/authorized_keys
$ exit

STEP 5: Downloading Hadoop
To download the last stable version, go to Hadoop Releases and check the last release. Inside Hadoop Releases page go to Download a release now! link in order to find a mirror site for your download. Now, just copy the link to the hadoop-0.23.9.tar.gz file (version being used in this post). It will be used in the second command line bellow to download hadoop-0.23.9.tar.gz straight to the desired folder.
$ cd /usr/local
$ sudo wget http://ftp.unicamp.br/pub/apache/hadoop/common/had...op-0.23.9/hadoop-0.23.9.tar.gz

# Extract hadoop-0.23.9 files
$ sudo tar xzf hadoop-0.23.9.tar.gz

# Remove hadoop-0.23.9.tar.gz file we download
$ sudo rm hadoop-0.23.9.tar.gz 

# Create a symbolic link to make things easier, but it is not required.
$ sudo ln -s hadoop-0.23.9 hadoop

# The next command gives ownership of hadoop-0.23.9 directory, files
# and sub-directories to the hadoop user.

sudo chown -R hadoop:hadoopgroup hadoop-0.23.9

STEP 6: Setting up JAVA_HOME for Hadoop
Now that you have Java installed let’s configure it for Hadoop. In previous versions of Hadoop the file conf/hadoop-env.sh come for setting environment variables. Hadoop 0.23.9 don’t have this file in it. In such a case, we will manually create it inside $HADOOP_HOME/etc/hadoop folder and set the JAVA_HOME variable.

Firstly, let's check where you installed java:
$ echo $JAVA_HOME
/usr/lib/jvm/jdk1.7.0_25 # Where your JDK home directory

Now let’s create hadoop-env.sh file:
$ sudo vi /usr/local/hadoop/etc/hadoop/hadoop-env.sh

and add the following line:
export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_25

STEP 7: Disabling IPv6
Given the fact that Apache Hadoop is not currently supported on IPv6 networks (see Hadoop and IPv6) we will disable IPv6 in Java by editing hadoop-env.sh again.
$ sudo vi /usr/local/hadoop/etc/hadoop/hadoop-env.sh

Add the following line at the bottom of the file:
HADOOP_OPTS=-Djava.net.preferIPv4Stack=true

I am not sure if also disable IPv6 on Ubuntu 13.04 is really necessary (It worked without this step for me in test environments) but just in case, you can do it adding the following lines at the end of sysctl.conf file.
$ sudo vi /etc/sysctl.conf

Add below lines in the end:
# IPv6 configuration
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

Reload configuration for sysctl.conf
$ sudo sysctl -p

Check IPv6 is disabled typing
$ cat /proc/sys/net/ipv6/conf/all/disable_ipv6

Response:
0 – mean that IPv6 is enabled.
1 – mean that IPv6 is disable. It is what we expect.

STEP 8: Configuring HDFS
The Hadoop Distributed File System (HDFS) is a reliable distributed file system designed to run on ordinary hardware and to store very large amounts of data (terabytes or even petabytes). HDFS is highly fault-tolerant because from a pratical standpoint it was built upon the premise that hardware failure is the norm rather than the exception (see HDFS Architecture Guide). Thus, failure detection, distributed replication and quick recovery are in its core architecture.

The configuration settings are a set of key-value pairs of the format:

The main configurations are stored in the 3 files bellow:
* core-site.xml – contains default values for core Hadoop properties.
* mapred-site.xml – contains configuration information for MapReduce properties.
* hdfs-site.xml – contains server side configuration of your distributed file system.

First, let’s create a temporary directory for Hadoop
$ sudo mkdir /home/hadoop/tmp
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/tmp

# Set folder permissions
$ sudo chmod 750 /home/hadoop

and now set core-site.xml properties
$ sudo vi /usr/local/hadoop/etc/hadoop/core-site.xml

Updated to below content:


hadoop.tmp.dir - A base for other temporary directories.

fs.defaultFS - The name of the default file system. A URI whose scheme and authority determine the FileSystem implementation. The uri’s scheme determines the config property (fs.SCHEME.impl) naming the FileSystem implementation class. The uri’s authority is used to determine the host, port, etc. for a filesystem.

If you have any questions about core-site.xml configuration options, see here for more details.

As we are configuring a single node, we can edit mapred-site.xml file and config it as follow:
# Create a copy of the template mapred-site.xml file
$ sudo cp /usr/local/hadoop/etc/hadoop/mapred-site.xml.template /usr/local/hadoop/etc/hadoop/mapred-site.xml

# Edit the copy we just created
$ sudo vi /usr/local/hadoop/etc/hadoop/mapred-site.xml

Update to below content:


mapreduce.jobtracker.address - The host and port that the MapReduce job tracker runs at. If “local”, then jobs are run in-process as a single map and reduce task.

If you have any questions about core-site.xml configuration options, see here for more details.

By default, Hadoop will place DFS data node blocks in file://${hadoop.tmp.dir}/dfs/data (the property you have just configured in core-site.xml). This is fine while still in development or evaluation, but you probably should override this default value in a production system.

It’s a little bit of work, but you’re going to have to do it anyway. So we can just create them now
$ sudo mkdir /home/hadoop/hdfs
$ sudo chown -R hadoop:hadoopgroup /home/hadoop/hdfs
$ sudo chmod 750 /home/hadoop/hdfs

Open hdfs-site.xml for editing
$ sudo vi /usr/local/hadoop/etc/hadoop/hdfs-site.xml

Update the content as below:


dfs.replication - Default block replication. The actual number of replications can be specified when the file is created. The default value 3 is used if replication is not specified in create time.

dfs.datanode.data.dir - Determines where on the local filesystem an DFS data node should store its blocks. If this is a comma-delimited list of directories, then data will be stored in all named directories, typically on different devices. Directories that do not exist are ignored.

If you have any questions about hdfs-site.xml configuration option, see here.

STEP 9: Formating NameNode
Before start adding files to the HDFS we must format it. The command bellow will do it for us.
$ su - hadoop # switch to account "hadoop"
$ /usr/local/hadoop/bin/hdfs namenode -format

STEP 10: Starting the services
Now that we have formatted HDFS, use the following commands to launch hadoop
# Switch to account "hadoop" first!
$ /usr/local/hadoop/sbin/start-dfs.sh
$ /usr/local/hadoop/sbin/start-yarn.sh

Given the fact that Hadoop is written in the Java programming language, we can so use the Java Process Status tool (JPS) to check which processes are currently running in the JVM.
$ jps
# Initiated by start-dfs.sh
5848 Jps
5795 SecondaryNameNode
5375 NameNode
5567 DataNode

# Initiated by start-yarn.sh
5915 ResourceManager
6101 NodeManager

STEP 11: Running job test
To make sure all was configured correctly we will use the wordcount example that come with Hadoop. It reads text files from a specified folder and lists in another file the number of times each word occur. First, let’s create a folder for our examples and download the plain text book A JOURNEY TO THE CENTER OF THE EARTH by Jules Verne inside this folder.
# The –p option make parent directories as needed. In practice, all folders in the mkdir path are created.
$ mkdir -p /usr/local/hadoop/examples/jverne
$ cd /usr/local/hadoop/examples/jverne
$ wget http://www.textfiles.com/etext/FICTION/center_earth

# Copy the downloaded file to HDFS
$ cd /usr/local/hadoop
$ ./bin/hdfs dfs -copyFromLocal ./examples /

Check if the file was copied
$ ./bin/hdfs dfs -ls /examples/jverne
Found 1 items
-rw-r--r-- 1 hadoop supergroup 489319 2013-08-02 20:40 /examples/jverne/center_earth

If you have any questions regarding Hadoop Shell Commands, see Hadoop Shell Commands

So, let’s run the sample itself!
$ ./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-0.23.9.jar wordcount /examples/jverne /examples/jverne/output
# To print out the results
$ ./bin/hdfs dfs -cat /examples/jverne/output/part-r-00000
...
youthful 1
zeal 1
zero! 1
zigzag 2
zigzags 1

STEP 12: Stopping all services
In order to stop the services use:
# if you are already using account "hadoop"
$ /usr/local/hadoop/sbin/stop-dfs.sh
$ /usr/local/hadoop/sbin/stop-yarn.sh


Supplement:
Hadoop 解除 "Name node is in safe mode"
在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结束。安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块...


2013年10月27日 星期日

[ 深入雲計算 ] Hadoop 的體系結構

Preface: 
Hadoop 是 Apache 下的一個項目, 它並不是一個用於儲存的分布式文件系統而已, 而是設計用來在通用計算設備組成的大型叢集上執行分布式應用的框架. 由 HDFS, MapReduce, HBase, Hive 和 ZooKeeper 等成員的組成, 其中 HDFS 和 MapReduce 是 Hadoop 中兩個最基礎, 最重要的成員, 它們提供了互補性服務並在核心層上提供更高層的服務. Hadoop 項目結構如下: 
 

- Core/Common 
從 Hadoop 0.2 版開始, Hadoop Core 項目更名為 Common. 它是 Hadoop 其他子項目提供支持的常用工具, 主要包括 FileSystem, RPC 和串行操作 library. 它們為在廉價的硬件上搭建計算環境並提供基本的服務, 並且為運行在該平台上的軟件開發提供了所需要的 API.

- Avro 
Avro 是用於數據序列化的系統. 它提供了豐富的數據結構類型, 快速可壓縮的二進制數據格式, 存儲持久性數據的文件集, 遠程調用 RPC 的功能和簡單的動態語言集成功能. 其中代碼生成器既不需要讀/寫文件數據, 也不需要使用或實現 RPC 協議, 它只是一個可選的對靜態語言的實現.


HDFS 的體系結構: 
Hadoop 分布式文件系統 HDFS 可以部署在廉價硬體之上, 能夠高容錯, 可靠性的提供存儲海量數據 (TB 甚至是 PB 級). 它可以和 MapReduce 編成模型很好的結合, 以為能夠為應用程序提供高吞吐量的數據訪問, 並適用於大數據應用程序. 

HDFS 的設計目標 
1. 檢測及快速恢復硬體故障: 整個 HDFS 系統由成千上百存儲文件的服務器組成, 如此多的服務器意味故障會常發生, 因此故障的檢測與快速恢復是 HDFS 的第一個核心目標 
2. Stream 的數據訪問: HDFS 使應用程序能 Stream 的訪問它們的數據集. HDFS 被設計成適合進行批量處理而不是用戶交互式的處理, 重視數據吞吐量而不是數據訪問的反應數度. 
3. 簡化一致性模型: 大部分的 HDFS 程序操作文件時需要一次性寫入, 多次讀取. 一個文件一旦經過創建, 寫入與關閉後就不太需要修改, 從而簡化一致性問題並提高數據吞吐量. 
4. 移動計算的代價比移動數據的代價低: 一個應用請求的計算, 離它操作的數據越近效能就越好. 這在數據達到海量級別時更是如此. 將計算移動到數據比數據移動到計算處更高效. 
5. 超大規模數據集: HDFS 的一般企業文件大小可能在 TB 或是 PB 級. 
6. 異構軟硬體平台間的可移植姓: 這個特性便於 HDFS 作為大規模數據應用平台的推廣. 

HDFS 結構模型 
HDFS 是一個主從 (Master/Slave) 結構模型. 從最終用戶的角度來看, 它就像是傳統的文件系統一樣, 可以透過目錄路徑對文件執行 CRUD (Create/Read/Update/Delete) 操作. 一個 HDFS 叢集是由一個 NameNode 和若干的 DataNode 組成. NameNode 主節點是主服務器, 管理文件系統的命名空間和客戶端對文件的方問操作; DataNode 是叢集中的一般節點, 負責節點數據的存儲. 客戶端通過 NameNode 向 DataNode 節點交互訪問文件系統, 聯系 NameNode 獲取文件, 而文件的 I/O 操作則是直接和 DataNode 進行交互作用. HDFS 允許用戶以文件形式存儲數據, 架構如下: 
 

假設客戶端要訪問一個文件, 首先會從 NameNode 中獲取組成該文件數據塊所在位置列表, 即知道數據塊存儲在那些 DataNode 上; 然後客戶端直接從 DataNode 上讀取文件數據. 在這一過程中 NameNode 不參與文件的傳輸. NameNode 與 DataNode 都可以設計成在廉價的 Linux 主機上面運行, HDFS 採用 Java 語言開發, 因此可以佈署在大範圍的機器上. 一個典型的案例是一台機器跑一個單獨的 NameNode 節點, 叢集中的其他機器則各跑一個 DataNode 實例. 

NameNode 是 HDFS 的守護程序, 它主要負責記錄大數據文件如何被分割成數據塊, 被分割後的數據塊分別是存儲到那些 DataNode 數據節點上. NameNode 的主要功能是對內存 I/O 進行集中管理. NameNode 節點是單一的, 這樣就可以大大簡化系統的結構. NameNode 也負責管理與保管所有 HDFS 元數據, 因而用戶文件數據的 讀/寫 就可以直接在 DataNode 上而不需要透過 NameNode. 在一般狀況下, 如果是 DataNode 所在的服務器出現故障, Hadoop 叢集依舊可以正常運轉, 或者快速重啟. 但是如果是 NameNode 出現故障, 整個 Hadoop 的服務將因此而中止

文件系統的命名空間 NameSpace 
HDFS 支持傳統的 階層架構文件組織, 用戶可以創建目錄, 並在目錄中創建, 刪除, 移動和重新命名文件. 但是 HDFS 不支持用戶磁碟配額與訪問權限的控制, 也不支援軟/硬鏈接. NameNode 負責維護文件系統的名稱空間, 任何對文件系統名稱空間或屬性的修改都將被 NameNode 記錄下來, 文件副本的數目稱為文件副本係數, 這個設定也是記錄在 NameNode. 

數據複製與存放 
HDFS 是在一個大叢集中跨機器可靠的存儲超大文件. 它將每個文件存儲成一系列的數據塊, 數據按 64 MB 分成大小等同的一個個數據塊, 除了最後一個, 所有的數據塊大小都是相同的. 
1. 數據的複製 
文件的所有數據塊都會有副本, 這樣可以提高數據的容錯性, 應用程序可以指定某個文件的副本數目. 數據塊的副本係數可以在文件創建時候指定也可以在日後進行修改. HDFS 中的文件都是一次性寫入的, 並在任何時候只能有一個寫入者.

NameNode 管理者數據的複製, 採用週期性地從叢集中的每個 DataNode 接收 Heart bean 訊號和塊狀報告 (Blockreport). 如果收到的心跳報告就表明該 DataNode 節點是正常運作; 如果沒有收到 Heartbeat 訊號, 則說明該 DataNode 節點發生異常. 數據塊狀態報告中包含了一個 DataNode 節點上所有數據塊的列表訊息:
 

2. 副本的存放是 HDFS 可靠性和性能的關鍵 
優化的副本存放策略是 HDFS 區分其他大部分分布式文件系統的重要特性. HDFS 採用一種 Rack-aware 的策略來改進 HDFS 數據的可靠性, 可用性與網絡頻寬的利用率. 一個 Rack-aware 的過程就是 NameNode 可以確定每個 DataNode 所屬的 Rack-ID. 一個簡單但沒有優化的策略就是將副本存放在不同的 Rack 上, 這樣可以有效防止整個 Rack 失效時數據的丟失, 並且允許讀數據的時候充分利用多個 Rack 的頻寬. 這種策略就是將副本均勻的分佈在叢集中, 有利於負載的平衡. 但是這個策略也有缺點, 即一個寫操作需要把數據傳送到多個 Rack 而增加了寫的代價.

在大多數情況下, 數據塊的副本係數是 3, HDFS 的存放策略是將一個副本存放在本機節點上, 一個副本放在同一個 Rack-ID 的另一個節點上, 最後一個副本放在不同 Rack-ID 的節點上. 這種策略減少了 Rack 間的數據傳輸, 提高了寫操作的效率. Rack 的錯誤遠遠比節點的錯誤少, 所以這個策略不會影響到數據的可靠性和可用性. 與此同時, 因為數據只放在兩個 (少於 3 個) 不同的 Rack 上, 所以此策略減少了讀取數據時所需要的網絡傳輸量.

3. 副本選擇 
為了降低整體的頻寬消耗與讀取延時, HDFS 會盡量讓讀取程序讀取離它最近的副本. 如果在讀取程序的同一個 Rack 上有一個副本, 那就讀取該副本. 如果一個 HDFS 叢集跨越多個數據中心, 那麼客戶端也將首先讀取本地數據中心的副本.

4. 安全模式 
NameNode 啟動後會進入安全模式的特殊狀態, 在處於安全模式狀態中的 NameNode 是不會複製數據塊. NameNode 接收所有的 DataNode 的 Heartbean 訊號和狀態報告, 塊的狀態報告中包含該 DataNode 中所有的數據塊列表訊息, 每個數據塊都有一個最小的副本數. 當 NameNode 檢測了某個數據塊的副本並達到這個數據塊最少副本數值, 就說明該數據塊是安全的; 在某百分比 (百分比透過參數設定配置) 的數據塊通過 NameNode 檢測確定是安全後, 這時候會加一個額外的 30 秒等待時間, NameNode 就會退出安全模式. NameNode 接下來確定那些數據塊的副本數沒有達到指定的數目, 並把這些數據塊的副本複製到其他的 DataNode 節點上.

文件系統元數據的持久化 
NameNode 節點上保存著 HDFS 的命名空間, 在對任何文件系統的元數據進行創建, 修改, 刪除等操作時, NameNode 會採用 Editlog 的事務日誌文件記錄下來. 整個 HDFS 的文件系統的命名空間, 包含數據塊的映射, 文件屬性, 數據塊的副本訊息都會存儲在這個 FsImage 文件中. 而透過這個 Editlog, 系統在重開機後就能回復到關機前的狀態. 

HDFS 的通信協議 
HDFS 通訊協議是建立在 TCP/IP 網絡協議之上. 客戶端透過 TCP 端口連接到 NameNode, 然後使用 ClientProtocol 協議與 NameNode 節點進行資訊交換. 在 DataNode 上採用 DataNodeProtocol 協議來與 NameNode 主節點進行資訊交換. 遠程調用 RPC 模型被抽象出來並封裝成 ClientProtocol 和 DataProtocol 協議. 一般情況下 NameNode 節點不會主動發起 RPC 請求 而是 接收來自客戶端或是 DataNode 的 RPC 請求. 

HDFS 的 Robust 
HDFS 的可靠性主要表現在即使出現錯誤情況下, 也要保證能夠進行數據存儲. 常見的 3 種錯誤狀況是 NameNode 故障, DataNode 故障 與 網路割裂 (Network Partitions). 
1. 磁碟數據錯誤 
每個 DataNode 節點都會週期性的向 NameNode 發送 Heartbeat. 網路故障可能導致一部分的 DataNode 和 NameNode 失去聯繫. NameNode 透過接收 Heartbean 來檢測這樣的情況, 把近期那些不在發送 Heartbeat 的 DataNode 標記起來, 並不在給它們分配新的 I/O 請求. 存儲在那些 DataNode 節點上的所有數據將不在有效. DataNode 出現這種狀況會導致數據塊副本系數低於設定值, 這時 NameNode 不斷的檢測這些需要複製的數據塊並啟動增加副本. 除了網絡問題造成 DataNode 失效, 如 副本遭到破壞, DataNode 上的硬碟錯誤, 或者文件的副本係數增大都會造成 NameNode 啟動複製數據塊副本的動作!

2. 叢集均衡 
HDFS 分布式文件系統支持數據均衡策略. 如果某個 DataNode 節點上的空閒空間低於某個特定臨界點, 系統就會自動地將數據從這個 DataNode 移動到其他較空閒的 DataNode, 這就是 HDFS 的叢集均衡策略. 當某個文件的請求突然增加, 這時就需要啟動一個計劃創建該文件新的副本, 並且同時重新對叢集進行負載平衡. 但是目前這個均衡策略還沒有實作, 等待日後版本支援.

3. 數據完整性 
如果從某個 DataNode 獲取的數據塊是毀損的, 原因可能是由 DataNode 自身的存儲設備錯誤或是網絡數據傳輸錯誤造成. 針對這種狀況, HDFS 客戶端可以對 HDFS 文件內容進行 Checksum 檢查. 在客戶端創建一個新的 HDFS 文件時, 計算這個文件每個數據塊的校驗結果作為一個獨立隱藏文件並與原始文件保存在同一個 HDFS 名字空間下. 一旦客戶端獲取文件內容, 它就開始檢驗從 DataNode 獲取的數據塊與當初建立的校驗結果是否匹配. 如果不匹配, 客戶端可以選擇從其他 DataNode 獲取該數據塊的副本.

4. 元數據磁碟錯誤 
FsImage 和 Ediglog 是 HDFS 的核心數據結構. FsImge 保存數據塊的文件映射, 文件屬性, 數據塊的副本等訊息. Ediglog 則是事務日誌文件, 保存的是元數據進行創建, 修改, 刪除等操作. 如果這麼重要的文件損壞, 就會導致 HDFS 實例都將失效. 解決這個問題的方法是: NameNode 配置成支持多個 FsImage 和 Editlog 的副本, 對 FsImage 或 Editlog 的修改都會同步到它們的副本上. 這麼多的副本的同步將會降低 NameNode 處理命名空間事務的效率, 這個代價相對於損壞了 FsImage 和 Editlog 帶來的破壞性影響是可以接受的. HDFS 的應用是非元數據密集的, 當 NameNode 重新啟動時, 它會選取最近的, 完整的 FsImage 和 Editlog 使用.

NameNode 是 HDFS 叢集中的 Single Point of Failure 所在. 如果 NameNode 機器故障是需要手工恢復的. 目前自動重啟或在另一台機器上做 NameNode 故障轉移的功能還沒實現.

5. 快照 
快照支持某一特定時刻數據的複製備份. 利用快照, 可以讓 HDFS 在數據損壞時恢復到一個已知正確的時間點. HDFS 目前還不支持快照功能, 但計畫在未來版本支援.

HDFS 的數據組織 
1. 數據塊 
HDFS 被設計成支持大容量的文件, 處理大規模的數據運用. 這些應用都是只寫入一次, 讀取多次, 並且讀取速度應能滿足 Streaming 讀取的要求. 一個典型的數據塊大小是 64MB. 因而 HDFS 中的文件是按照 64MB 被劃分成不同的數據塊, 每個塊盡可能的儲存在不同的 DataNode.

2. 數據塊的存放 
客戶端創建文件的請求會先將文件數據緩存到本地的一個臨時文件中, 並沒有立即發送給 NameNode. 應用程序的寫操作被透明地重新定位到這個臨時文件中, 當臨時文件累計超過一個數據塊的大小時, 客戶端才會聯繫 NameNode, NameNode 將文件名插入到 HDFS 文件層次結構中, 並且分配一個數據塊給它, NameNode 返回 DataNode 的標示符和目標數據塊給用戶端, 接著客戶端將這塊數據塊從本地臨時文件上傳到指定的 DataNode 上. 如果在文件關閉時臨時文件還有剩餘, 則沒有上傳的的數據塊也會傳輸到指定的 DataNode 上, 然後客戶端會告訴 NameNode 該文件已經關閉, 這時 NameNode 才把文件創建的操作提交到日誌 Editlog 文件中存儲. 如果該文件在文件關閉前, NameNode 出現故障, 那該文件就會丟失.

在上述方法中, HDFS 在進行文件傳輸時充分考慮了應用程序中需要進行文件的 Stream 寫入, 採用客戶端的緩存, 這樣可以避免由於網路速度的堵塞造成不好的寫入效率

3. 數據塊流水線複製 
客戶端向 HDFS 文件系統寫入數據的過程為:
1. 開始時寫到本地的臨時文件中, 也就是客戶端得緩存中, 當本地臨時文件大小累積到一個數據塊 64MB 大小時, 客戶端就會從 NameNode 節點中獲取一個 DataNode 列表訊息用來存儲數據塊.
2. 接著客戶端向 DataNode 節點傳輸數據, 假設數據塊的副本為 3, 第一個 DataNode 會一小部分一小部分 (大概 4KB) 地接收數據. 而接收到的每一部分數據都會寫入到本地倉儲.
3. 在同時數據也依據 Data Node 列表向第二個 DataNode 節點傳輸副本.
4. 同時在第二個 DataNode 收到數據後, 也同時向第三個 DataNode 節點傳輸副本.

HDFS 的可訪問性 
應用程序可以通過多種方式來訪問 HDFS 
方式一: HDFS 提供 JavaAPI 接口供用戶訪問
方式二: HDFS 提供 C 語言封裝的 API 給用戶提供訪問
方式三: HDFS 還提供了瀏覽器方式提供用戶訪問.
方式四: HDFS 正在開發 WebDAV 協議供用戶訪問.

HDFS 的存儲空間回收 
1. 文件的刪除和恢復 
當用戶或應用程序要刪除某個文件, 這個文件並沒有立刻從 HDFS 文件系統刪除. 實際情況如下: HDFS 首先將這個要刪除的文件進行重命名並轉移到 /trash 目錄. 只要該文件還在 /trash 目錄中, 就表明該文件還沒有徹底刪除, 該文件還是可以恢復的. 該文件在 /trash 目錄的保存時間可以透過配置設定, 當這個時間超過, NameNode 就會從名字空間中刪除該文件, 文件刪除後與該文件相關的數據塊將被釋放. 默認策略是刪除文件在 /trash 目錄中的保存時間是 6 hrs, 超過 6 hrs 將自動刪除文件.

2. 減少副本數 
重新設置一個文件的副本係數, 副本係數減少, 這時 NameNode 會選擇多餘的副本進行刪除. 下次 Heartbeat 檢測將訊息除遞給 DataNode 節點, DataNode 根據訊息內容刪除相應的數據塊, 釋放空間使得叢集中的可用空間加大.

MapReduce 的體系結構: 
MapReduce 是 Hadoop 的主要核心組件之一. Hadoop Map/Reduce 是一個使用簡易的軟體框架, 基於它寫出來的應用程序能夠運行在由上千個節點組成的大型叢集上, 並以一種可靠容錯的方式並行處理 TB 級別的數據集. 採用 MapReduce 架構實現的程序能夠在由大量的普通配置的計算機構成的叢集中實現並行化操作. MapReduce 系統在運行過程中只關心數據如何分割, 如何調度, 以及集群中計算機如何對錯誤進行處理, 管理著計算機之間的通信. 採用 MapReduce 架構可以使那些沒有進行過併行計算和分布式計算的開發人員能充分利用分布式系統的豐富資源進行併行式, 分布式的開發. 

MapReduce 框架由一個單獨的 master JobTracker 和叢集節點上的 slave TaskTracker 共同組成. master 負責調度一個作業中的所有任務, 把這些任務分布在不同的 slave 上. master 監控 slave 節點上這些任務的執行情況, 並重新執行失敗的任務, 而 slave 僅負責執行由 master 指派的任務. 

MapReduce 是一種編成模式 
MapReduce 是一種編成模式, 一種雲計算的核心計算方式並採用分布式運算計算模式, 也是簡化的分布式編成模式. 
1 MapReduce 主要解決問題 
MapReduce 致力於解決大規模數據處理的問題. 因此 MapReduce 在設計之初就考慮了數據的局部性原理, 利用局部性原理將整個問題分而治之 (有點像 MergeSort). 數據在處理之前已經分布到各個節點上, 處理時每個節點先就近讀取本地存儲的數據來進行 Map 處理, 將 Map 處理後的數據再進行合併 (combine), 排序 (shuffle and sort) 然後再分發到 Reduce 節點. 在數據傳輸過程中, 為了避免大量的數據傳輸, 提高數據傳輸效率, 採用無共享式架構的好處就是配合複製 (replication) 策略, 為叢集帶來良好的容錯能力, 當一部分的節點出現故障對叢集的正常工作不會造成太大的影響.

2. MapReduce 編成模式的核心思想 
MapReduce 編成模式的主要思想是自動分割要執行的問題 (程序) 並拆解成 Map (映射) 和 Reduce (簡化) 的方式. 在數據被分割後通過 Map 函數的程序將數據映射成不同的區塊, 分配給計算機群處理, 達到分布式運算的效果. 在通過 Reduce 函數的程序將結果彙整從而輸出開發者的結果.

簡單來說 Map 函數是把一組數據一對一的映射到另一組數據中. 映射的規則是由一個函數來指定, 如一組數據 [1,2,3,4] 乘與 3 的映射就變成 [3,6,9,12]. Reduce 函數的作用就是對這一組數據進行 "歸約". 歸約的規則也是由一個函數指定, 如規則為對 [3,6,9,12] 進行求和得到的結果為 30. 總的來說, Map 函數是要把任務分解成多個小任務, Reduce 函數負責把分解後的各個任務處理的結果進行匯總. 對於其他複雜的問題, 如工作調度, 分布是存儲, 容錯處理, 負載均衡, 網絡通訊, 則由 MapReduce 框架來負責處理.

3. MapReduce 與分布式文件系統 HDFS 的關係 
通常 Map/Reduce 框架和分布式文件系統 HDFS 是運行在同一組相同的節點上. 換句話說計算節點與存儲節點通常再一起. 採用這種配置的優勢是在框架中的那些數據可以被高效的調度運用而使得整個叢集網絡得到高效的運用.

一個 Map/Reduce 作業 (job) 會把輸入的數據劃分成多個獨立的數據塊, 這個工作由 Map 任務 (task) 採用並行的方式處理. 框架會對 Map 的輸出結果進行排序, 通過 Map 函數處理後, 把處理的結果輸入給 Reduce 任務. 通常作業的輸入與輸出都會被存儲在文件系統中. 框架負責任務的調度與監控, 以及重新執行失敗的任務.

Map/Reduce 
MapReduce 處理大規模數據其核心就是 Map/Reduce 函數. 這兩個函數的具體功能由用戶根據自己的需求設計實現, 只要能夠按照用戶自定義的規則, 將輸入的 轉換成另一個或一批 的輸出. 在 Map 階段, MapReduce 框架將任務的輸入數據分割成固定大小的數據片段 (splits), 隨後將每個 split 進一步分解成一批鍵值對 . Hadoop 為每一個 split 創建一個 Map 任務用於執行用戶自定義的 Map 函數, 並將對應的數據塊 split 中的 作為輸出, 得到了計算的中間結果 . 接著將中間結果按 k2 進行排序, 並將 key 值相同的 value 放在一起形成一個新列表 元組. 最後根據 key 值範圍將這些元組進行分組以對應不同的 Reduce 任務. 

在 Reduce 階段, Reduce 任務從不同的 Map 接收來的數據整合在一起並進行排序, 然後調用用戶自定義的 Reduce 函數, 對輸入的 進行相應的處理, 得到鍵值對 並輸出到 HDFS 上. 既然 MapReduce 框架為每個 split 創建一個 Map, 那麼誰來確認 Reduce 任務的數目? 答案是用戶, 用戶必須確認 Reduce 數量. Mapred-site.xml 配置文件中有一個表示 Reduce 任務數目的屬性 Mapred.Reduce.tasks, 該屬性默認值為 1, 開發人員可以通過 job.setNumReduceTasks() 方法重新設置該值. 

MapReduce 將處理大數據的過程拆解成 Map 與 Reduce 的過程如下圖: 
 

Map/Reduce 範例: 
接著我們要了解 Map/Reduce 最好的方法就是來看一個簡單的範例. 考慮你有一堆 Words, 你希望知道每個 Word 出現的次數, 如果放在 Map/Reduce 的流程中, 看起來會像下面的圖: 
 

Supplement: 
[ Python 文章收集 ] python內置函數 map/reduce/filter

[ Py DS ] Ch3 - Data Manipulation with Pandas (Part5)

Source From  Here   Pivot Tables   We have seen how the  GroupBy  abstraction lets us explore relationships within a dataset. A pivot ta...