Hadoop集羣中增加新節點

Hadoop集羣中增加新節點

向一個正在運行的Hadoop集羣中增加幾個新的Nodes

1. 新節點上部署java/hadoop程序,配置相應的環境變量

2. 新節點上增加用戶,從master上拷貝id_rsa.pub並配置authorized_keys

3. 新節點上設置host,需要有集羣中各節點的host對應

4. 新節點上建立相關的目錄,並修改屬主

5. master的slaves文件中增加上相的節點,master上增加相應的host

6. 在新節點上啓動datanode和tasktracker

/opt/sohuhadoop/hadoop/bin/hadoop-daemon.sh start datanode
/opt/sohuhadoop/hadoop/bin/hadoop-daemon.sh start tasktracker

7. 進行block塊的均衡

在hdfs-site.xml中增加設置balance的帶寬,默認只有1M:

<property> 
    <name>dfs.balance.bandwidthPerSec</name> 
    <value>10485760</value> 
    <description>
        Specifies the maximum bandwidth that each datanode can utilize for the balancing purpose in term of the number of bytes per second.
    </description> 
</property>

運行以下命令:

/opt/sohuhadoop/hadoop/bin/start-balancer.sh -threshold 3

均衡10個節點,移動400G數據,大概花費了3個小時

The cluster is balanced. Exiting…
Balancing took 2.9950980555555557 hours

我們現有的Hadoop集羣已經運行了一段時間了

由於集羣中的服務器分佈在2個不同的機房,受跨機房帶寬的限制

集羣中在2個機房之間的數據傳輸很慢

所以想把另一個機房的3臺服務器從Hadoop集羣中去掉

Hadoop提供了Decommission的特性,可以按照以下步驟來操作:

1. 在hadoop的conf目錄下生成一個excludes的文件,寫上需要remove的節點ip

    一個節點一行,注意要寫ip,不能寫Hostname,如:

10.15.10.41
10.15.10.42
10.15.10.43

2. 在hdfs-site.xml中增加配置:

<property>    
    <name>dfs.hosts.exclude</name>    
    <value>/opt/sohuhadoop/conf/excludes</value>    
    <final>true</final>
</property>

3. 複製以上2個文件到集羣各節點上

4. 執行hadoop dfsadmin -refreshNodes命令,它會在後臺進行Block塊的移動

    從移出的Nodes上移動到其它的Nodes上面

5. 通過以下2種方式查看Decommission的狀態:

    hadoop dfsadmin -report

    http://10.10.71.220:50070/dfsnodelist.jsp

    正在執行Decommission,會顯示:

    Decommission Status : Decommission in progress

    執行完畢後,會顯示:

    Decommission Status : Decommissioned

基於現有的Hadoop集羣,來搭建Hbase的環境

整個過程還是比較簡單的

1. 下載Hbase源碼,並解壓

cp hbase-0.20.6.tar.gz /opt/hadoop/
cd /opt/hadoop/
tar zxvf hbase-0.20.6.tar.gz
ln -s hbase-0.20.6 hbase

2.修改hbase-env.sh,加入java環境,並修改log位置

export JAVA_HOME=/opt/java/jdk
export HBASE_LOG_DIR=/opt/log/hbase
export HBASE_MANAGES_ZK=true

3. 修改hbase-site.xml,配置hbase

<property>
    <name>hbase.rootdir</name>
    <value>hdfs://zw-hadoop-master:9000/hbase</value>
    <description>The directory shared by region servers.</description>
</property>
<property>
            <name>hbase.cluster.distributed</name>
            <value>true</value>
            <description>The mode the cluster will be in. Possible values are
              false: standalone and pseudo-distributed setups with managed Zookeeper
              true: fully-distributed with unmanaged Zookeeper Quorum (see hbase-env.sh)
            </description>
    </property>
<property>  
    <name>hbase.master</name>  
    <value>hdfs://zw-hadoop-master:60000</value>  
</property> 
<property>
    <name>hbase.zookeeper.quorum</name>        
    <value>zw-hadoop-slave225,zw-hadoop-slave226,zw-hadoop-slave227</value>
    <description>Comma separated list of servers in the ZooKeeper Quorum.      For example, "host1.mydomain.com,host2.mydomain.com,host3.mydomain.com".      By default this is set to localhost for local and pseudo-distributed modes      of operation. For a fully-distributed setup, this should be set to a full      list of ZooKeeper quorum servers. If HBASE_MANAGES_ZK is set in hbase-env.sh      this is the list of servers which we will start/stop ZooKeeper on.      
    </description>
</property>
<property>
    <name>hbase.zookeeper.property.dataDir</name>
    <value>/opt/log/zookeeper</value>
    <description>Property from ZooKeeper's config zoo.cfg.
        The directory where the snapshot is stored.
    </description>
</property>

幾個配置的說明:

hbase.rootdir設置hbase在hdfs上的目錄,主機名爲hdfs的namenode節點所在的主機hbase.cluster.distributed設置爲true,表明是完全分佈式的hbase集羣hbase.master設置hbase的master主機名和端口hbase.zookeeper.quorum設置zookeeper的主機,官方推薦設置爲3,5,7比較好

4. 編輯regionservers文件,設置regionservers的服務器,和hadoop的slaves一樣即可

5. 啓動Hbase

/opt/sohuhadoop/hbase/bin/start-hbase.sh 
/opt/sohuhadoop/hbase/bin/stop-hbase.sh

Hbase默認只有一個Master,我們可以也啓動多個Master:

/opt/sohuhadoop/hbase/bin/hbase-daemon.sh start master

不過,其它的Master並不會工作,只有當主Master down掉後

其它的Master纔會選擇接管Master的工作

Hbase也有一個簡單的web界面,來查看其狀態

http://10.10.71.1:60010/master.jsp
http://10.10.71.1:60030/regionserver.jsp

http://10.10.71.1:60010/zk.jsp

Hadoop集羣中,NameNode節點存儲着HDFS上所有文件和目錄的元數據信息

如果NameNode掛了,也就意味着整個Hadoop集羣也就完了

所以,NameNode節點的備份很重要,可以從以下2個方面來備份NameNode節點

1. 在hdfs-site.xml中,配置多個name的dir到不同的磁盤分區上:

<property>
    <name>dfs.name.dir</name>
    <value>/pvdata/hadoopdata/name/,/opt/hadoopdata/name/</value>
</property>

2. 在另外的一臺服務器上配置Secondary NameNode:它是NameNode的一個備份

Secondary NameNode會定期合併fsimage和edits日誌,將edits日誌文件大小控制在一個限度下

合併的時機是由2個配置參數決定的:

fs.checkpoint.period,指定連續兩次檢查點的最大時間間隔, 默認值是1小時。
fs.checkpoint.size定義了edits日誌文件的最大值,一旦超過這個值會導致強制執行檢查點(即使沒到檢查點的最大時間間隔)。默認值是64MB。

Secondary NameNode的配置過程如下:

在conf/masters中指定第二名稱節點的主機名在core-site.xml中指定checkpoint的目錄

<property>
  <name>fs.checkpoint.dir</name>
  <value>/opt/hadoopdata/secondname,/pvdata/hadoopdata/secondname</value>
  <description>Determines where on the local filesystem the DFS secondary
      name node should store the temporary images to merge.
      If this is a comma-delimited list of directories then the image is
      replicated in all of the directories for redundancy.
  </description>
</property>

如果NameNode節點掛了,可以按照如下步驟來從Secondary NameNode來恢復:

在dfs.name.dir指定的位置建立一個空文件夾從Secondary NameNode上把secondname的目錄給scp到新的NameNode機器的fs.checkpoint.dir下使用hadoop/bin/hadoop namenode -importCheckpoint來啓動NameNode,主要不要執行format命令
使用hadoop fsck /user命令檢查文件Block的完整性

詳細的Secondary NameNode細節可參考Hadoop官方文檔:

http://hadoop.apache.org/common/docs/r0.20.2/hdfs_user_guide.html#Secondary+NameNode

這兩天在操作Hadoop集羣時,由於一個誤操作,製作了一個天大的悲劇

不小心把Hadoop集羣上的所有文件全部刪除了,具體情況是這樣的:

我用hadoop的超級帳戶要建立一個目錄,結果發現位置錯了

也是,想使用rmr刪掉那個目錄,可是不小心把命令寫成了

hadoop fs -rmr /user

於是,悲劇出現了,所有user目錄下的所有目錄和文件全都沒有了

當時我就慌神了,趕緊從web查看50070的服務

眼看着DFS Used空間從100多G不停的減少

後來才反應過來,趕緊停掉namenode節點,然後上網google辦法

後來,從secondname節點重新恢復了一個checkpoint

但絕大部分數據都已經丟失了,只恢復了一小部分數據,已經沒啥用了

幸好,原始log我們在其它服務器上還保留的有,只能重新分析再入Hadoop了

總結了一下幾點教訓:

首先一定要控制好hadoop上各用戶的權限,使各user只能操作自己的目錄儘量少用hadoop的超級用戶進行操作,可以減少誤操作hadoop的rm和rmr命令,設計的太BT了,連一個確認提示都沒有,直接就刪除了。看到有人給官方提了這個建議,但人家回覆說:已經有了trash機制了,所以不需要提示,真是無語….hadoop的trash功能:很遺憾,之前沒有配置trash,所以就直接給刪除了,經過這次誤操作,趕緊配置上trash,並設置保留時間爲7天。

在core-site.xml中增加如下配置,表明rm後會在trash中保留多少分鐘:

<property>
  <name>fs.trash.interval</name>
  <value>10080</value>
  <description>
      Number of minutes between trash checkpoints. If zero, the trash feature is disabled
  </description>
</property>

很遺憾的是,hadoop的這個默認值是0,就是直接刪除了,爲什麼要這麼設計呢?鬱悶….

經過簡單的測試,這個trash功能還是不錯的,當rm後,它會move到當前文件夾下的.Trash目錄下

如果你刪除一個文件或目錄多次,則hadoop會自動在name後加上數字序列號

這樣,如果你誤刪除後,就可以有選擇的恢復文件了

hadoop fs -mkdir /user/oplog/test
hadoop fs -put *.txt /user/oplog/test
hadoop fs -rmr /user/oplog/test
hadoop fs -ls /user/oplog/.Trash/Current/user/oplog
    drwxr-xr-x   – oplog oplog          0 2010-11-16 10:44 /user/oplog/.Trash/Current/user/oplog/test
hadoop fs -mv /user/oplog/.Trash/Current/user/oplog/test /user/oplog/
hadoop fs -ls /user/oplog/.Trash/Current/user/oplog
    drwxr-xr-x   – oplog oplog          0 2010-11-16 10:44 /user/oplog/.Trash/Current/user/oplog/test
    drwxr-xr-x   – oplog oplog          0 2010-11-16 10:47 /user/oplog/.Trash/Current/user/oplog/test.1

目前,我們郵件的一部分log已經遷移到Hadoop集羣上

並由Hive來執行相關的查詢

hadoop中默認的mapred.tasktracker.map.tasks.maximum設置是2

也即:每一個tasktracker同時運行的map任務數爲2

照此默認設置,查詢80天某用戶的操作日誌,耗時5mins, 45sec

經過測試,發現將mapred.tasktracker.map.tasks.maximum設置爲節點的cpu cores數目或者數目減1比較合適

此時的運行效率最高,大概花費3mins, 25sec

我們現在的機器都是8核的,所以最終配置如下:

<property>
    <name>mapred.tasktracker.map.tasks.maximum</name>
    <value>8</value>
    <description>The maximum number of map tasks that will be run
    simultaneously by a task tracker.
    </description>
</property>

而對於mapred.map.tasks(每個job的map任務數)值,hadoop默認值也爲2

可以在執行hive前,通過set mapred.map.tasks=24來設定

但由於使用hive,會操作多個input文件,所以hive默認會把map的任務數設置成輸入的文件數目

即使你通過set設置了數目,也不起作用…

如果在集羣裏面,可以直接使用hadoop的fs shell來操作集羣

往上面put/get文件,或者執行一些hive查詢

但如果要在hadoop集羣外面去操作hadoop和hive,那麼可以有2個辦法:

1.  寫Java程序,調用hadoop提供的一些API去完成

2. 在需要操作的服務器上搭建一個hadoop的環境

目前,我們採用的是第2種辦法,這種方式比較簡單

只需要將hadoop master上的hadoop相關目錄打個包

部署到對應的服務器上,並修改相應的環境變量和hosts就可以了

打包時,可以把一些無用的配置信息和腳本給去掉

但需要保留core-site.xml和hdfs-site.xm和mapred-site.xml這3個配置文件

12345678910111213 vi /etc/profile  export JAVA_HOME=/opt/java/jdk export HADOOP_CONF_DIR=/opt/sohuhadoop/conf  export HADOOP_HOME=/opt/sohuhadoop/hadoop  export HIVE_HOME=/opt/sohuhadoop/hive vi /etc/hosts  10.10.1.1 hadoop-master. hadoop-master

如果你的Hadoop集羣,是公用的,可能有很多其它部門的文件都存放在上面

那麼,就一定要考慮權限問題,給各種數據以不同的權限

Hadoop目前的權限,實現的比較簡單,類似於Shell的權限,是通過操作用戶名來控制的

它默認的超級用戶就是你啓動Hadoop時的用戶

一般,我們所有的服務器都默認是用root來登錄的

因爲,安裝Hadoop時一定要新建一個用戶來安裝,不要安裝在root下

然後,對於不同的log,再新建不同的用戶目錄來存放,如:

12345 hadoop fs -mkdir /user/test   hadoop fs -chmod -R 700 /user/test   hadoop fs -chown -R test:test /user/test

這樣,只有test這個用戶才能操作/user/test目錄,其它用戶都無權操作

如果,你su pplog,然後執行

1 hadoop fs -ls /user/test

你將會看到一個錯誤提示:

ls: could not get get listing for 'hdfs://zw-hadoop-master:9000/user/test' : org.apache.hadoop.security.AccessControlException: Permission denied: user=pplog, access=READ_EXECUTE, inode="test":test:test:rwx——

對於Hive來說,可以這麼來控制權限訪問

爲不同日誌的MetaStore在Mysql建立不同的數據庫爲不同的用戶建立單獨的conf目錄,如用戶test的hive conf目錄位於/opt/sohuhadoop/hive/conf/test下在單獨的test目錄下,修改hive-default.xml文件,配置相應的db啓動單獨的hiveserver實例,並監聽不同的端口:HIVE_PORT=10020 nohup hive –config $HIVE_HOME/conf/test –service hiveserver &在JDBC中連接自己對應的端口,如10020

上面的權限控制雖然有一定作用,但卻是還很弱,如果其它人知道了你的用戶名或者端口號

一樣可以去刪除你的文件,據說,將來Hadoop會對權限認證做一定改進,期待……

本機的環境如下:

Eclipse 3.6

Hadoop-0.20.2

Hive-0.5.0-dev

1. 安裝hadoop-0.20.2-eclipse-plugin的插件。注意:Hadoop目錄中的\hadoop-0.20.2\contrib \eclipse-plugin\hadoop-0.20.2-eclipse-plugin.jar在Eclipse3.6下有問題,無法在 Hadoop Server上運行,可以從http://code.google.com/p/hadoop-eclipse-plugin/下載

2. 選擇Map/Reduce視圖:window ->  open pers.. ->  other.. ->  map/reduce

3. 增加DFS Locations:點擊Map/Reduce Locations—> New Hadoop Loaction,填寫對應的host和port

12345678910 Map/Reduce Master: Host: 10.10.xx.xx Port: 9001 DFS Master: Host: 10.10.xx.xx(選中 User M/R Master host即可) Port: 9000 User name: root   更改Advance parameters 中的 hadoop.job.ugi, 默認是 DrWho,Tardis, 改成:root,Tardis。如果看不到選項,則使用Eclipse -clean重啓Eclipse 否則,可能會報錯org.apache.hadoop.security.AccessControlException

4. 設置本機的Host:

12345 10.10.xx.xx zw-hadoop-master. zw-hadoop-master   #注意後面需要還有一個zw-hadoop-master.,否則運行Map/Reduce時會報錯: java.lang.IllegalArgumentException: Wrong FS: hdfs://zw-hadoop-master:9000/user/root/oplog/out/_temporary/_attempt_201008051742_0135_m_000007_0, expected: hdfs://zw-hadoop-master.:9000 at org.apache.hadoop.fs.FileSystem.checkPath(FileSystem.java:352)

5. 新建一個Map/Reduce Project,新建Mapper,Reducer,Driver類,注意,自動生成的代碼是基於老版本的Hadoop,自己修改:

123456789101112131415161718192021222324252627282930313233343536373839404142 434445464748495051525354555657585960616263646566676869707172737475767778798081 packagecom.sohu.hadoop.test;   importjava.util.StringTokenizer;importorg.apache.hadoop.io.IntWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.mapreduce.Mapper;   publicclass MapperTest extends Mapper<Object, Text, Text, IntWritable>{privatefinalstatic IntWritable one =new IntWritable(1);   publicvoid map(Object key, Text value, Context context)throwsIOExceptionInterruptedException{String userid = value.toString().split("[|]")[2]; context.write(new Text(userid)new IntWritable(1));}}    packagecom.sohu.hadoop.test;   importjava.io.IOException;importorg.apache.hadoop.io.IntWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.mapreduce.Reducer;   publicclass ReducerTest extends Reducer<Text, IntWritable, Text, IntWritable>{   private IntWritable result =new IntWritable();   publicvoid reduce(Text key, Iterable<IntWritable> values, Context context)throwsIOExceptionInterruptedException{int sum =0;for(IntWritabl val : values){ sum += val.get();} result.set(sum); context.write(key, result);}}    packagecom.sohu.hadoop.test;   importorg.apache.hadoop.conf.Configuration;importorg.apache.hadoop.fs.Path;importorg.apache.hadoop.io.IntWritable;importorg.apache.hadoop.io.Text;importorg.apache.hadoop.io.compress.CompressionCodec;importorg.apache.hadoop.io.compress.GzipCodec;importorg.apache.hadoop.mapreduce.Job;importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;importorg.apache.hadoop.util.GenericOptionsParser;   publicclass DriverTest {publicstaticvoid main(String[] args)throwsException{ Configuration conf =new Configuration();String[] otherArgs =new GenericOptionsParser(conf, args) .getRemainingArgs();if(otherArgs.length!=2){System.err.println("Usage: DriverTest <in> <out>");System.exit(2);} Job job =new Job(conf, "Driver Test"); job.setJarByClass(DriverTest.class); job.setMapperClass(MapperTest.class); job.setCombinerClass(ReducerTest.class); job.setReducerClass(ReducerTest.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class);   conf.setBoolean("mapred.output.compress"true); conf.setClass("mapred.output.compression.codec", GzipCodec.class,CompressionCodec.class);   FileInputFormat.addInputPath(job, new Path(otherArgs[0])); FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));   System.exit(job.waitForCompletion(true)?0:1);}}

6. 在DriverTest上,點擊Run As —> Run on Hadoop,選擇對應的Hadoop Locaion即可

http://hi.baidu.com/eagoo/blog/item/4d8918b3b2a108b1d8335a10.html

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