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)throwsIOException, InterruptedException{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)throwsIOException, InterruptedException{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
|