基於外部ZooKeeper的GlusterFS作爲分佈式文件系統的完全分佈式HBase集羣安裝指南 頂 原

(WJW)基於外部ZooKeeper的GlusterFS作爲分佈式文件系統的完全分佈式HBase集羣安裝指南


[X] 前提條件

  • 服務器列表:

192.168.1.84 hbase84 #hbase-master

192.168.1.85 hbase85 #hbase-regionserver,zookeeper

192.168.1.86 hbase86 #hbase-regionserver,zookeeper

192.168.1.87 hbase87 #hbase-regionserver,zookeeper

  • JDK

建議安裝Sun的JDK1.7版本! 安裝完畢並配置java環境變量,在/etc/profile末尾添加如下代碼:
export JAVA_HOME=/usr/java/default
export PATH=$JAVA_HOME/bin:$PATH
保存退出即可,然後執行source /etc/profile生效.在命令行執行java -version 如下代表JAVA安裝成功.

  • ssh

需要配置各個節點的免密碼登錄!
首先在自己機器上使用ssh-keygen -t rsa
會要求輸入密碼(必須爲空),回車幾次,然後會在HOME目錄下生成.ssh文件夾,
裏面有私鑰和公鑰,公鑰爲id_rsa.pub,(現在你需要將你的公鑰拷貝到服務器上,如果你的系統有ssh-copy-id命令,拷貝會很簡單:$ ssh-copy-id 用戶名@服務器名)
否則,你需要手動將你的私鑰拷貝的服務器上的~/.ssh/authorized_keys文件中!

  • NTP

集羣的時鐘要保證基本的一致.稍有不一致是可以容忍的,但是很大的不一致會 造成奇怪的行爲. 運行 NTP 或者其他什麼東西來同步你的時間.
如果你查詢的時候或者是遇到奇怪的故障,可以檢查一下系統時間是否正確!

echo "server 192.168.0.2" >> /etc/ntp.conf  
chkconfig ntpd on  
service ntpd restart  
ntpq -p  
  • ulimit和nproc

HBase是數據庫,會在同一時間使用很多的文件句柄.大多數linux系統使用的默認值1024是不能滿足的,修改/etc/security/limits.conf文件爲:

      *               soft    nproc   16384
      *               hard    nproc   16384  
      *               soft    nofile  65536  
      *               hard    nofile  65536  
  • ZooKeeper
  1. 先把ZooKeeper安裝在hbase85,hbase86,hbase873個節點上
  2. 啓動hbase85,hbase86,hbase87上的ZooKeeper!

/opt/app/zookeeper/bin/zkServer.sh start

  • HBase還需要一個正在運行的分佈式文件系統:HDFS,或者GlusterFS

本指南使用GlusterFS作爲分佈式文件系統!
每個節點的掛載目錄爲:/mnt/gfs_v3/hbase
GlusterFS是Scale-Out存儲解決方案Gluster的核心,它是一個開源的分佈式文件系統,具有強大的橫向擴展能力,通過擴展能夠支持數PB存儲容量和處理數千客戶端.
GlusterFS藉助TCP/IP或InfiniBand RDMA網絡將物理分佈的存儲資源聚集在一起,使用單一全局命名空間來管理數據.
GlusterFS基於可堆疊的用戶空間設計,可爲各種不同的數據負載提供優異的性能.


[X] 修改 192.168.1.84,192.168.1.85,192.168.1.86,192.168.1.87etc/hosts文件,在文件最後添加:

192.168.1.84 hbase84
192.168.1.85 hbase85
192.168.1.86 hbase86
192.168.1.87 hbase87

[X] 拷貝hbase-0.98.8-hadoop2-bin.tar.gz到各個hbase84的/opt目錄下,然後執行:

cd /opt
tar zxvf ./hbase-0.98.8-hadoop2-bin.tar.gz
mv hbase-0.98.8-hadoop2  /opt/hbase

[X] 源碼編譯安裝Hadoop的native庫:

#YUM安裝依賴庫
yum install autoconfautomake libtool cmake zlib-devel
yum install ncurses-devel
yum install openssl-devel
yum install gcc*

下載並安裝配置:protobuf
cd /tmp
wget http://protobuf.googlecode.com/files/protobuf-2.5.0.tar.gz
tar -zxvf protobuf-2.5.0.tar.gz
cd protobuf-2.5.0
./configure
make
make install 
ldconfig
rm -rf /tmp/protobuf-2.5.0/

#下載並配置:findbugs
http://sourceforge.net/projects/findbugs/files/findbugs/2.0.2/findbugs-2.0.2.tar.gz/download
解壓:tar -zxvf ./findbugs-2.0.2.tar.gz
配置環境變量FINDBUGS_HOME: export FINDBUGS_HOME=/path to your extract directory  #例如: export FINDBUGS_HOME=/opt/findbugs-2.0.2

#Build native libraries using maven
編輯`hadoop-common-project/hadoop-auth/pom.xml`文件,添加上
    <dependency>
       <groupId>org.mortbay.jetty</groupId>
      <artifactId>jetty-util</artifactId>
      <scope>test</scope>
    </dependency>
編輯`hadoop-common-project/hadoop-auth/pom.xml`文件,在<artifactId>maven-site-plugin</artifactId>後添加一行:<version>3.3</version>
編輯`pom.xml`文件,把<artifactId>maven-site-plugin</artifactId>後面的:<version>3.0</version>改成:<version>3.3</version>

mvn package -Pdist,native,docs -DskipTests -Dtar
生成好的文件是:/opt/hadoop-2.2.0-src/hadoop-dist/target/hadoop-2.2.0.tar.gz

把hadoop-2.2.0.tar.gz裏的lib/native目錄下的文件複製到hbase的lib/native目錄下,然後執行:

cd /opt/hbase/lib/native
ln -fs libhadoop.so.1.0.0 libhadoop.so
ln -fs libhdfs.so.0.0.0 libhdfs.so

[X] 修改/opt/hbase/conf/hbase-env.sh文件,在文件最後添加:

export JAVA_HOME=/usr/java/default
export PATH=$JAVA_HOME/bin:$PATH

export HBASE_PID_DIR=/var/hbase/pids
export JAVA_LIBRARY_PATH=${HBASE_HOME}/lib/native
export HBASE_MANAGES_ZK=false
export HBASE_HEAPSIZE=3000

[X] 修改/opt/hbase/conf/hbase-site.xml文件,改成:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>
  <property>
    <name>hbase.master.port</name>
    <value>60000</value>
  </property>

  <property>
    <name>hbase.rootdir</name>
    <value>file:///mnt/gfs_v3/hbase</value>
    <!-- <value>hdfs://m1:9000/hbase</value>  -->
  </property>
  
  <property>
    <name>hbase.zookeeper.quorum</name>
    <value>192.168.1.85,192.168.1.86,192.168.1.87</value>
  </property>
  <property>
    <name>hbase.zookeeper.property.clientPort</name>
    <value>2181</value>
  </property>
  <property>
    <name>zookeeper.znode.parent</name>
    <value>/hbase</value>
  </property>
  
  
  <!-- 優化參數  -->
  <property>
    <name>hbase.regionserver.handler.count</name>
    <value>50</value>
  </property>
  <property>
    <name>hbase.hregion.max.filesize</name>
    <value>268435456</value>
  </property>
  
</configuration>

[X] 修改/opt/hbase/conf/regionservers文件,配置HBase集羣中的從結點Region Server,如下所示:

hbase85
hbase86
hbase87

[X] 爲腳本文件添加可執行權限

chmod -R +x /opt/hbase/bin/*
chmod -R +x /opt/hbase/conf/*.sh

[X] 啓動hbase集羣

[1] 把配置好的hbase複製到其他節點:

執行如下操作即可

ssh hbase84
ssh hbase85
ssh hbase86
ssh hbase87
scp -r /opt/hbase/ root@hbase85:/opt/
scp -r /opt/hbase/ root@hbase86:/opt/
scp -r /opt/hbase/ root@hbase87:/opt/

[2] 在hbase84節點上執行:

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

[X] 停止hbase集羣

在hbase84節點上執行:

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

[X] 附錄:

腳本使用小結:

  1. 開啓集羣,start-hbase.sh
  2. 關閉集羣,stop-hbase.sh
  3. 開啓/關閉所有的regionserver、zookeeper, hbase-daemons.sh start/stop regionserver/zookeeper
  4. 開啓/關閉單個regionserver、zookeeper, hbase-daemon.sh start/stop regionserver/zookeeper
  5. 開啓/關閉master, hbase-daemon.sh start/stop master, 是否成爲active master取決於當前是否有active master
  6. rolling-restart.sh 可以用來挨個滾動重啓
  7. graceful_stop.sh move服務器上的所有region後,再stop/restart該服務器,可以用來進行版本的熱升級

幾個細節:

  1. hbase-daemon.sh start master 與 hbase-daemon.sh start master --backup,這2個命令的作用一樣的,是否成爲backup或active是由master的內部邏輯來控制的
  2. stop-hbase.sh 不會調用hbase-daemons.sh stop regionserver 來關閉regionserver, 但是會調用hbase-daemons.sh stop zookeeper/master-backup來關閉zk和backup master,關閉regionserver實際調用的是hbaseAdmin的shutdown接口
  3. 通過$HBASE_HOME/bin/hbase stop master關閉的是整個集羣而非單個master,只關閉單個master的話使用$HBASE_HOME/bin/hbase-daemon.sh stop master
  4. $HBASE_HOME/bin/hbase stop regionserver/zookeeper 不能這麼調,調了也會出錯,也沒有路徑會調用這個命令,但是可以通過$HBASE_HOME/bin/hbase start regionserver/zookeeper 來啓動rs或者zk,hbase-daemon.sh調用的就是這個命令

HTable一些基本概念

Row key

行主鍵, HBase不支持條件查詢和Order by等查詢,讀取記錄只能按Row key(及其range)或全表掃描,因此Row key需要根據業務來設計以利用其存儲排序特性(Table按Row key字典序排序如1,10,100,11,2)提高性能.

避免使用遞增的數字或時間做爲rowkey.

如果rowkey是整型,用二進制的方式比用string來存儲更節約空間

合理的控制rowkey的長度,儘可能短,因爲rowkey的數據也會存在每個Cell中.

如果需要將表預分裂爲多個region是,最好自定義分裂的規則.

Column Family(列族)

在表創建時聲明,每個Column Family爲一個存儲單元.在上例中設計了一個HBase表blog,該表有兩個列族:article和author.

列簇儘量少,最好不超過3個.因爲每個列簇是存在一個獨立的HFile裏的,flush和compaction操作都是針對一個Region進行的,當一個列簇的數據很多需要flush的時候,其它列簇即使數據很少也需要flush,這樣就產生的大量不必要的io操作.

在多列簇的情況下,注意各列簇數據的數量級要一致.如果兩個列簇的數量級相差太大,會使數量級少的列簇的數據掃描效率低下.

將經常查詢和不經常查詢的數據放到不同的列簇.

因爲列簇和列的名字會存在HBase的每個Cell中,所以他們的名字應該儘可能的短.比如,用f:q代替mycolumnfamily:mycolumnqualifier

Column(列)

HBase的每個列都屬於一個列族,以列族名爲前綴,如列article:title和article:content屬於article列族,author:name和author:nickname屬於author列族.

Column不用創建表時定義即可以動態新增,同一Column Family的Columns會羣聚在一個存儲單元上,並依Column key排序,因此設計時應將具有相同I/O特性的Column設計在一個Column Family上以提高性能.同時這裏需要注意的是:這個列是可以增加和刪除的,這和我們的傳統數據庫很大的區別.所以他適合非結構化數據.

Timestamp

HBase通過row和column確定一份數據,這份數據的值可能有多個版本,不同版本的值按照時間倒序排序,即最新的數據排在最前面,查詢時默認返回最新版本.如上例中row key=1的author:nickname值有兩個版本,分別爲1317180070811對應的"一葉渡江"和1317180718830對應的"yedu"(對應到實際業務可以理解爲在某時刻修改了nickname爲yedu,但舊值仍然存在).Timestamp默認爲系統當前時間(精確到毫秒),也可以在寫入數據時指定該值.

Value

每個值通過4個鍵唯一索引,tableName+RowKey+ColumnKey+Timestamp=>value,例如上例中{tableName='blog',RowKey='1',ColumnName='author:nickname',Timestamp=' 1317180718830'}索引到的唯一值是"yedu".

存儲類型

TableName 是字符串
RowKeyColumnName是二進制值(Java 類型 byte[])
Timestamp是一個 64 位整數(Java 類型 long) value是一個字節數組(Java類型 byte[]).


HBase配置優化

zookeeper.session.timeout

默認值:3分鐘(180000ms)

說明:RegionServer與Zookeeper間的連接超時時間.當超時時間到後,ReigonServer會被Zookeeper從RS集羣清單中移除,HMaster收到移除通知後,會對這臺server負責的regions重新balance,讓其他存活的RegionServer接管.

調優:這個timeout決定了RegionServer是否能夠及時的failover.設置成1分鐘或更低,可以減少因等待超時而被延長的failover時間. 不過需要注意的是,對於一些Online應用,RegionServer從宕機到恢復時間本身就很短的(網絡閃斷,crash等故障,運維可快速介入),如果調低timeout時間,反而會得不償失.因爲當ReigonServer被正式從RS集羣中移除時,HMaster就開始做balance了(讓其他RS根據故障機器記錄的WAL日誌進行恢復).當故障的RS在人工介入恢復後,這個balance動作是毫無意義的,反而會使負載不均勻,給RS帶來更多負擔.特別是那些固定分配regions的場景.

hbase.regionserver.handler.count

默認值:10

說明:RegionServer的請求處理IO線程數.

調優: 這個參數的調優與內存息息相關. 較少的IO線程,適用於處理單次請求內存消耗較高的Big PUT場景(大容量單次PUT或設置了較大cache的scan,均屬於Big PUT)或ReigonServer的內存比較緊張的場景. 較多的IO線程,適用於單次請求內存消耗低,TPS要求非常高的場景.設置該值的時候,以監控內存爲主要參考. 這裏需要注意的是如果server的region數量很少,大量的請求都落在一個region上,因快速充滿memstore觸發flush導致的讀寫鎖會影響全局TPS,不是IO線程數越高越好. 壓測時,開啓Enabling RPC-level logging,
可以同時監控每次請求的內存消耗和GC的狀況,最後通過多次壓測結果來合理調節IO線程數. 這裏是一個案例?Hadoop and HBase Optimization for Read Intensive Search Applications,作者在SSD的機器上設置IO線程數爲100,僅供參考.

hbase.hregion.max.filesize

默認值:256M

說明:在當前ReigonServer上單個Reigon的最大存儲空間,單個Region超過該值時,這個Region會被自動split成更小的region.

調優: 小region對split和compaction友好,因爲拆分region或compact小region裏的storefile速度很快,內存佔用低.缺點是split和compaction會很頻繁.特別是數量較多的小region不停地split, compaction,會導致集羣響應時間波動很大,region數量太多不僅給管理上帶來麻煩,甚至會引發一些Hbase的bug.一般512以下的都算小region.
大region,則不太適合經常split和compaction,因爲做一次compact和split會產生較長時間的停頓,對應用的讀寫性能衝擊非常大.此外,大region意味着較大的storefile,compaction時對內存也是一個挑戰. 當然,大region也有其用武之地.如果你的應用場景中,某個時間點的訪問量較低,那麼在此時做compact和split,既能順利完成split和compaction,又能保證絕大多數時間平穩的讀寫性能.
既然split和compaction如此影響性能,有沒有辦法去掉? compaction是無法避免的,split倒是可以從自動調整爲手動. 只要通過將這個參數值調大到某個很難達到的值,比如100G,就可以間接禁用自動split(RegionServer不會對未到達100G的region做split). 再配合RegionSplitter這個工具,在需要split時,手動split. 手動split在靈活性和穩定性上比起自動split要高很多,相反,管理成本增加不多,比較推薦online實時系統使用. 內存方面,小region在設置memstore的大小值上比較靈活,大region則過大過小都不行,過大會導致flush時app的IO wait增高,過小則因store file過多影響讀性能.

hbase.regionserver.global.memstore.upperLimit/lowerLimit

默認值:0.4/0.35

upperlimit說明:hbase.hregion.memstore.flush.size 這個參數的作用是當單個Region內所有的memstore大小總和超過指定值時,flush該region的所有memstore.RegionServer的flush是通過將請求添加一個隊列,模擬生產消費模式來異步處理的.那這裏就有一個問題,當隊列來不及消費,產生大量積壓請求時,可能會導致內存陡增,最壞的情況是觸發OOM. 這個參數的作用是防止內存佔用過大,當ReigonServer內所有region的memstores所佔用內存總和達到heap的40%時,HBase會強制block所有的更新並flush這些region以釋放所有memstore佔用的內存.

lowerLimit說明: 同upperLimit,只不過lowerLimit在所有region的memstores所佔用內存達到Heap的35%時,不flush所有的memstore.它會找一個memstore內存佔用最大的region,做個別flush,此時寫更新還是會被block.lowerLimit算是一個在所有region強制flush導致性能降低前的補救措施.在日誌中,表現爲 "** Flush thread woke up with memory above low water."

調優:這是一個Heap內存保護參數,默認值已經能適用大多數場景. 參數調整會影響讀寫,如果寫的壓力大導致經常超過這個閥值,則調小讀緩存hfile.block.cache.size增大該閥值,或者Heap餘量較多時,不修改讀緩存大小. 如果在高壓情況下,也沒超過這個閥值,那麼建議你適當調小這個閥值再做壓測,確保觸發次數不要太多,然後還有較多Heap餘量的時候,調大hfile.block.cache.size提高讀性能. 還有一種可能性是?hbase.hregion.memstore.flush.size保持不變,但RS維護了過多的region,要知道 region數量直接影響佔用內存的大小.

hfile.block.cache.size

默認值:0.2

說明:storefile的讀緩存佔用Heap的大小百分比,0.2表示20%.該值直接影響數據讀的性能.

調優:當然是越大越好,如果寫比讀少很多,開到0.4-0.5也沒問題.如果讀寫較均衡,0.3左右.如果寫比讀多,果斷默認吧.設置這個值的時候,你同時要參考?hbase.regionserver.global.memstore.upperLimit?,該值是memstore佔heap的最大百分比,兩個參數一個影響讀,一個影響寫.如果兩值加起來超過80-90%,會有OOM的風險,謹慎設置.

hbase.hstore.blockingStoreFiles

默認值:7

說明:在flush時,當一個region中的Store(Coulmn Family)內有超過7個storefile時,則block所有的寫請求進行compaction,以減少storefile數量.

調優:block寫請求會嚴重影響當前regionServer的響應時間,但過多的storefile也會影響讀性能.從實際應用來看,爲了獲取較平滑的響應時間,可將值設爲無限大.如果能容忍響應時間出現較大的波峯波谷,那麼默認或根據自身場景調整即可.

hbase.hregion.memstore.block.multiplier

默認值:2

說明:當一個region裏的memstore佔用內存大小超過hbase.hregion.memstore.flush.size兩倍的大小時,block該region的所有請求,進行flush,釋放內存. 雖然我們設置了region所佔用的memstores總內存大小,比如64M,但想象一下,在最後63.9M的時候,我Put了一個200M的數據,此時memstore的大小會瞬間暴漲到超過預期的hbase.hregion.memstore.flush.size的幾倍.這個參數的作用是當memstore的大小增至超過hbase.hregion.memstore.flush.size 2倍時,block所有請求,遏制風險進一步擴大.

調優: 這個參數的默認值還是比較靠譜的.如果你預估你的正常應用場景(不包括異常)不會出現突發寫或寫的量可控,那麼保持默認值即可.如果正常情況下,你的寫請求量就會經常暴長到正常的幾倍,那麼你應該調大這個倍數並調整其他參數值,比如hfile.block.cache.size和hbase.regionserver.global.memstore.upperLimit/lowerLimit,以預留更多內存,防止HBase server OOM.

hbase.hregion.memstore.mslab.enabled

默認值:true

說明:減少因內存碎片導致的Full GC,提高整體性能.

調優:詳見 http://kenwublog.com/avoid-full-gc-in-hbase-using-arena-allocation


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