HBase是什么?
HBase是Apache Hadoop中的一個子項目,Hbase依托於Hadoop的HDFS作為最基本存儲基礎單元,通過使用hadoop的DFS工具就可以看到這些這些數據 存儲文件夾的結構,還可以通過Map/Reduce的框架(算法)對HBase進行操作,如右側的圖所示:
HBase在產品中還包含了Jetty,在HBase啟動時采用嵌入式的方式來啟動Jetty,因此可以通過web界面對HBase進行管理和查看當前運行的一些狀態,非常輕巧。
為什么采用HBase?
HBase 不同於一般的關系數據庫,它是一個適合於非結構化數據存儲的數據庫.所謂非結構化數據存儲就是說HBase是基於列的而不是基於行的模式,這樣方面讀寫你的大數據內容。
HBase是介於Map Entry(key & value)和DB Row之間的一種數據存儲方式。就點有點類似於現在流行的Memcache,但不僅僅是簡單的一個key對應一個 value,你很可能需要存儲多個屬性的數據結構,但沒有傳統數據庫表中那么多的關聯關系,這就是所謂的松散數據。
簡單來說,你在HBase中的表創建的可以看做是一張很大的表,而這個表的屬性可以根據需求去動態增加,在HBase中沒有表與表之間關聯查詢。你只需要 告訴你的數據存儲到Hbase的那個column families 就可以了,不需要指定它的具體類型:char,varchar,int,tinyint,text等等。但是你需要注意HBase中不包含事務此類的功 能。
Apache HBase 和Google Bigtable 有非常相似的地方,一個數據行擁有一個可選擇的鍵和任意數量的列。表是疏松的存儲的,因此用戶可以給行定義各種不同的列,對於這樣的功能在大項目中非常實用,可以簡化設計和升級的成本。
如何運行HBase?
從 Apache的HBase的鏡像網站上下載一個穩定版本的HBase http://mirrors.devlib.org/apache/hbase/stable/hbase-0.20.6.tar.gz, 下載完成后,對其進行解壓縮。確定你的機器中已經正確的安裝了Java SDK、SSH,否則將無法正常運行。
$ cd /work/hbase
進入此目錄
$ vim conf/hbase-env.sh
export JAVA_HOME=/JDK_PATH
編輯 conf/hbase-env.sh 文件,將JAVA_HOME修改為你的JDK安裝目錄
$ vim conf/regionservers
輸入你的所有HBase服務器名,localhost,或者是ip地址
$ bin/start-hbase.sh
啟動hbase, 中間需要你輸入兩次密碼,也可以進行設置不需要輸入密碼,啟動成功,如圖所示:
$ bin/hbase rest start
啟動hbase REST服務后就可以通過對uri: http://localhost:60050/api/ 的通用REST操作(GET/POST/PUT/DELETE)實現對hbase的REST形式數據操作.
也可以輸入以下指令進入HQL指令模式
$ bin/hbase shell
$ bin/stop-hbase.sh
關閉HBase服務
啟動時存在的問題
由於linux系統的主機名配置不正確,在運行HBase服務器中可能存在的問題,如圖所示:
2010-11-05 11:10:20,189 ERROR org.apache.hadoop.hbase.master.HMaster: Can not start master
java.net.UnknownHostException: ubuntu-server216: ubuntu-server216
表示你的主機名不正確,你可以先查看一下 /etc/hosts/中名稱是什么,再用 hostname 命令進行修改, hostname you_server_name
查看運行狀態
- 如果你需要對HBase的日志進行監控你可以查看 hbase.x.x./logs/下的日志文件,可以使用tail -f 來查看。
- 通過 web方式查看運行在 HBase 下的zookeeper http://localhost:60010/zk.jsp
- 如果你需要查看當前的運行狀態可以通過web的方式對HBase服務器進行查看,如圖所示:
擴展閱讀1:
Apach 的 Hadoop的項目中包含了那些產品,如圖所示:
Pig 是在MapReduce上構建的查詢語言(SQL-like),適用於大量並行計算。
Chukwa 是基於Hadoop集群中監控系統,簡單來說就是一個“看門狗” (WatchDog)
Hive 是DataWareHouse 和 Map Reduce交集,適用於ETL方面的工作。
HBase 是一個面向列的分布式數據庫。
Map Reduce 是Google提出的一種算法,用於超大型數據集的並行運算。
HDFS 可以支持千萬級的大型分布式文件系統。
Zookeeper 提供的功能包括:配置維護、名字服務、分布式同步、組服務等,用於分布式系統的可靠協調系統。
Avro 是一個數據序列化系統,設計用於支持大批量數據交換的應用。
擴展閱讀2:
什么是列存儲?列存儲不同於傳統的關系型數據庫,其數據在表中是按行存儲的,列方式所帶來的重要好處之一就是,由於查詢中的選擇規則是通過列來定義的,因 此整個數據庫是自動索引化的。按列存儲每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量,一個字段的數據聚集存儲,那就 更容易為這種聚集存儲設計更好的壓縮/解壓算法。這張圖講述了傳統的行存儲和列存儲的區別:
擴展閱讀3:
對系統海量的Log4J日志可以存放在一個集中式的機器上,在此機器上安裝 splunk 可以方便對所有日志查看,安裝方法可以參考:
http://www.splunk.com/base/Documentation/latest/Installation/InstallonLinux
本篇文章講述用HBase Shell命令 和 HBase Java API 對HBase 服務器 進行操作。在此之前需要對HBase的總體上有個大概的了解。比如說HBase服務器內部由哪些主要部件構成?HBase的內部工作原理是什么?我想學習任何一項知識、技術的態度不能只是知道如何使用,對產品的內部構建一點都不去關心,那樣出了問題,很難讓你很快的找到答案,甚至我們希望最后能對該項技術的領悟出自己的心得,為我所用,借鑒該項技術其中的設計思想創造出自己的解決方案,更靈活的去應對多變的計算場景與架構設計。以我目前的對HBase的了解還不夠深入,將來不斷的學習,我會把我所知道的點滴分享到這個Blog上。
先來看一下讀取一行記錄HBase是如何進行工作的,首先HBase Client端會連接Zookeeper Qurom(從下面的代碼也能看出來,例如:HBASE_CONFIG.set("hbase.zookeeper.quorum", "192.168.50.216") )。通過Zookeeper組件Client能獲知哪個Server管理-ROOT- Region。那么Client就去訪問管理-ROOT-的Server,在META中記錄了HBase中所有表信息,(你可以使用 scan '.META.' 命令列出你創建的所有表的詳細信息),從而獲取Region分布的信息。一旦Client獲取了這一行的位置信息,比如這一行屬於哪個Region,Client將會緩存這個信息並直接訪問HRegionServer。久而久之Client緩存的信息漸漸增多,即使不訪問.META.表也能知道去訪問哪個HRegionServer。HBase中包含兩種基本類型的文件,一種用於存儲WAL的log,另一種用於存儲具體的數據,這些數據都通過DFS Client和分布式的文件系統HDFS進行交互實現存儲。
如圖所示:
再來看看HBase的一些內存實現原理:
- HMaster— HBase中僅有一個Master server。
- HRegionServer—負責多個HRegion使之能向client端提供服務,在HBase cluster中會存在多個HRegionServer。
- ServerManager—負責管理Region server信息,如每個Region server的HServerInfo(這個對象包含HServerAddress和startCode),已load Region個數,死亡的Region server列表
- RegionManager—負責將region分配到region server的具體工作,還監視root和meta 這2個系統級的region狀態。
- RootScanner—定期掃描root region,以發現沒有分配的meta region。
- MetaScanner—定期掃描meta region,以發現沒有分配的user region。
HBase基本命令
下面我們再看看看HBase的一些基本操作命令,我列出了幾個常用的HBase Shell命令,如下:
名稱
|
命令表達式
|
|
創建表 | create '表名稱', '列名稱1','列名稱2','列名稱N' | |
添加記錄 | put '表名稱', '行名稱', '列名稱:', '值' | |
查看記錄 | get '表名稱', '行名稱' | |
查看表中的記錄總數 | count '表名稱' | |
刪除記錄 | delete '表名' ,'行名稱' , '列名稱' | |
刪除一張表 | 先要屏蔽該表,才能對該表進行刪除,第一步 disable '表名稱' 第二步 drop '表名稱' | |
查看所有記錄 | scan "表名稱" | |
查看某個表某個列中所有數據 | scan "表名稱" , ['列名稱:'] | |
更新記錄 | 就是重寫一遍進行覆蓋 |
如果你是一個新手隊HBase的一些命令還不算非常熟悉的話,你可以進入 hbase 的shell 模式中你可以輸入 help 命令查看到你可以執行的命令和對該命令的說明,例如對scan這個命令,help中不僅僅提到有這個命令,還詳細的說明了scan命令中可以使用的參數和作用,例如,根據列名稱查詢的方法和帶LIMIT 、STARTROW的使用方法:
scan Scan a table; pass table name and optionally a dictionary of scanner specifications. Scanner specifications may include one or more of the following: LIMIT, STARTROW, STOPROW, TIMESTAMP, or COLUMNS. If no columns are specified, all columns will be scanned. To scan all members of a column family, leave the qualifier empty as in 'col_family:'. Examples: hbase> scan '.META.' hbase> scan '.META.', {COLUMNS => 'info:regioninfo'} hbase> scan 't1', {COLUMNS => ['c1', 'c2'], LIMIT => 10, STARTROW => 'xyz'} |
使用Java API對HBase服務器進行操作
需要下列jar包
hbase-0.20.6.jar hadoop-core-0.20.1.jar commons-logging-1.1.1.jar zookeeper-3.3.0.jar log4j-1.2.91.jar import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.io.BatchUpdate; @SuppressWarnings("deprecation") public class HBaseTestCase { static HBaseConfiguration cfg = null; static { Configuration HBASE_CONFIG = new Configuration(); HBASE_CONFIG.set("hbase.zookeeper.quorum", "192.168.50.216"); HBASE_CONFIG.set("hbase.zookeeper.property.clientPort", "2181"); cfg = new HBaseConfiguration(HBASE_CONFIG); } /** * 創建一張表 */ public static void creatTable(String tablename) throws Exception { HBaseAdmin admin = new HBaseAdmin(cfg); if (admin.tableExists(tablename)) { System.out.println("table Exists!!!"); } else{ HTableDescriptor tableDesc = new HTableDescriptor(tablename); tableDesc.addFamily(new HColumnDescriptor("name:")); admin.createTable(tableDesc); System.out.println("create table ok ."); } } /** * 添加一條數據 */ public static void addData (String tablename) throws Exception{ HTable table = new HTable(cfg, tablename); BatchUpdate update = new BatchUpdate("Huangyi"); update.put("name:java", "http://www.javabloger.com".getBytes()); table.commit(update); System.out.println("add data ok ."); } /** * 顯示所有數據 */ public static void getAllData (String tablename) throws Exception{ HTable table = new HTable(cfg, tablename); Scan s = new Scan(); ResultScanner ss = table.getScanner(s); for(Result r:ss){ for(KeyValue kv:r.raw()){ System.out.print(new String(kv.getColumn())); System.out.println(new String(kv.getValue() )); } } } public static void main (String [] agrs) { try { String tablename="tablename"; HBaseTestCase.creatTable(tablename); HBaseTestCase.addData(tablename); HBaseTestCase.getAllData(tablename); } catch (Exception e) { e.printStackTrace(); } } } |
這篇文章淺顯的從幾個方面談談HBase的一些優化技巧,只能作為我學習筆記的一部分,因為學多了怕忘,留給自己以后看看。
1 修改 linux 系統參數
Linux系統最大可打開文件數一般默認的參數值是1024,如果你不進行修改並發量上來的時候會出現“Too Many Open Files”的錯誤,導致整個HBase不可運行,你可以用ulimit -n 命令進行修改,或者修改/etc/security/limits.conf 和/proc/sys/fs/file-max 的參數,具體如何修改可以去Google 關鍵字 “linux limits.conf ”
2 JVM 配置
修改 hbase-env.sh 文件中的配置參數,根據你的機器硬件和當前操作系統的JVM(32/64位)配置適當的參數
HBASE_HEAPSIZE 4000 HBase使用的 JVM 堆的大小
HBASE_OPTS "‐server ‐XX:+UseConcMarkSweepGC"JVM GC 選項
HBASE_MANAGES_ZKfalse 是否使用Zookeeper進行分布式管理
3 HBase持久化
重啟操作系統后HBase中數據全無,你可以不做任何修改的情況下,創建一張表,寫一條數據進行,然后將機器重啟,重啟后你再進入HBase的shell中使用 list 命令查看當前所存在的表,一個都沒有了。是不是很杯具?沒有關系你可以在hbase/conf/hbase-default.xml中設置hbase.rootdir的值,來設置文件的保存位置指定一個文件夾 ,例如:<value>file:///you/hbase-data/path</value>,你建立的HBase中的表和數據就直接寫到了你的磁盤上,如圖所示:
同樣你也可以指定你的分布式文件系統HDFS的路徑例如: hdfs://NAMENODE_SERVER:PORT/HBASE_ROOTDIR,這樣就寫到了你的分布式文件系統上了。
4 配置HBase運行參數
其次就需要對hbase/conf/hbase-default.xml 文件進行配置,以下是我認為比較重要的配置參數
hbase.client.write.buffer
描述:這個參數可以設置寫入數據緩沖區的大小,當客戶端和服務器端傳輸數據,服務器為了提高系統運行性能開辟一個寫的緩沖區來處理它, 這個參數設置如果設置的大了,將會對系統的內存有一定的要求,直接影響系統的性能。
hbase.master.meta.thread.rescanfrequency
描述:多長時間 HMaster對系統表 root 和 meta 掃描一次,這個參數可以設置的長一些,降低系統的能耗。
hbase.regionserver.handler.count
描述:由於HBase/Hadoop的Server是采用Multiplexed, non-blocking I/O方式而設計的,所以它可以透過一個Thread來完成處理,但是由於處理Client端所呼叫的方法是Blocking I/O,所以它的設計會將Client所傳遞過來的物件先放置在Queue,並在啟動Server時就先產生一堆Handler(Thread),該Handler會透過Polling的方式來取得該物件並執行對應的方法,默認為25,根據實際場景可以設置大一些。
hbase.regionserver.thread.splitcompactcheckfrequency
描述:這個參數是表示多久去RegionServer服務器運行一次split/compaction的時間間隔,當然split之前會先進行一個compact操作.這個compact操作可能是minor compact也可能是major compact.compact后,會從所有的Store下的所有StoreFile文件最大的那個取midkey.這個midkey可能並不處於全部數據的mid中.一個row-key的下面的數據可能會跨不同的HRegion。
hbase.hregion.max.filesize
描述:HRegion中的HStoreFile最大值,任何表中的列族一旦超過這個大小將會被切分,而HStroeFile的默認大小是256M。
hfile.block.cache.size
描述:指定 HFile/StoreFile 緩存在JVM堆中分配的百分比,默認值是0.2,意思就是20%,而如果你設置成0,就表示對該選項屏蔽。
hbase.zookeeper.property.maxClientCnxns
描述: 這項配置的選項就是從zookeeper中來的,表示ZooKeeper客戶端同時訪問的並發連接數,ZooKeeper對於HBase來說就是一個入口這個參數的值可以適當放大些。
hbase.regionserver.global.memstore.upperLimit
描述:在Region Server中所有memstores占用堆的大小參數配置,默認值是0.4,表示40%,如果設置為0,就是對選項進行屏蔽。
hbase.hregion.memstore.flush.size
描述:Memstore中緩存的內容超過配置的范圍后將會寫到磁盤上,例如:刪除操作是先寫入MemStore里做個標記,指示那個value, column 或 family等下是要刪除的,HBase會定期對存儲文件做一個major compaction,在那時HBase會把MemStore刷入一個新的HFile存儲文件中。如果在一定時間范圍內沒有做major compaction,而Memstore中超出的范圍就寫入磁盤上了。
5 HBase中log4j的日志
HBase中日志輸出等級默認狀態下是把debug、 info 級別的日志打開的,可以根據自己的需要調整log級別,HBase的log4j日志配置文件在 hbase\conf\log4j.properties 目錄下。
在HBase中創建的一張表可以分布在多個Hregion,也就說一張表可以被拆分成多塊,每一塊稱我們呼為一個Hregion。每個Hregion會保 存一個表里面某段連續的數據,用戶創建的那個大表中的每個Hregion塊是由Hregion服務器提供維護,訪問Hregion塊是要通過 Hregion服務器,而一個Hregion塊對應一個Hregion服務器,一張完整的表可以保存在多個Hregion 上。HRegion Server 與Region的對應關系是一對多的關系。每一個HRegion在物理上會被分為三個部分:Hmemcache(緩存)、Hlog(日志)、HStore(持久層)。
上述這些關系在我腦海中的樣子,如圖所示:
1.HRegionServer、HRegion、Hmemcache、Hlog、HStore之間的關系,如圖所示:
2.HBase表中的數據與HRegionServer的分布關系,如圖所示:
HBase讀數據
HBase讀取數據優先讀取HMemcache中的內容,如果未取到再去讀取Hstore中的數據,提高數據讀取的性能。
HBase寫數據
HBase寫入數據會寫到HMemcache和Hlog中,HMemcache建立緩存,Hlog同步Hmemcache和Hstore的事務日志,發起Flush Cache時,數據持久化到Hstore中,並清空HMemecache。
客戶端訪問這些數據的時候通過Hmaster ,每個 Hregion 服務器都會和Hmaster 服務器保持一個長連接,Hmaster 是HBase分布式系統中的管理者,他的主要任務就是要告訴每個Hregion 服務器它要維護哪些Hregion。用戶的這些都數據可以保存在Hadoop 分布式文件系統上。 如果主服務器Hmaster死機,那么整個系統都會無效。下面我會考慮如何解決Hmaster的SPFO的問題,這個問題有點類似Hadoop的SPFO 問題一樣只有一個NameNode維護全局的DataNode,HDFS一旦死機全部掛了,也有人說采用Heartbeat來解決這個問題,但我總想找出 其他的解決方案,多點時間,總有辦法的。
昨天在hadoop-0.21.0、hbase-0.20.6的環境中折騰了很久,一直報錯,錯誤信息如下:
Exception in thread "main" java.io.IOException: Call to localhost/serv6:9000 failed on local exception: java.io.EOFException 10/11/10 15:34:34 ERROR master.HMaster: Can not start master java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at org.apache.hadoop.hbase.master.HMaster.doMain(HMaster.java:1233) at org.apache.hadoop.hbase.master.HMaster.main(HMaster.java:1274) |
死活連接不上HDFS,也無法連接HMaster,郁悶啊。
我想想啊,慢慢想,我眼前一亮 java.io.EOFException 這個異常,是不是有可能是RPC 協定格式不一致導致的?也就是說服務器端和客戶端的版本不一致的問題?換了一個HDFS的服務器端以后,一切都好了,果然是版本的問題,最后采用 hadoop-0.20.2 搭配hbase-0.20.6 比較穩當。
最后的效果如圖所示:
上圖的一些文字說明:
- hadoop版本是0.20.2 ,
- hbase版本是0.20.6,
- 在hbase中創建了一張表 tab1,退出hbase shell環境,
- 用hadoop命令查看,文件系統中的文件果然多了一個剛剛創建的tab1目錄,以上這張圖片說明HBase在分布式文件系統Apache HDFS中運行了。
在上一篇關於HBase的文章中曾經講述過HBase在分布式中的架構,這篇文章將會講述HBase在分布式環境中是如何排除單點故障的(SPFO),做一個小實驗講述HBase在分布式環境中的高可用性,親眼看到一些現象,延伸一些思考的話題。
先來回顧一下HBase主要部件:
- HBaseMaster
- HRegionServer
- HBase Client
- HBase Thrift Server
- HBase REST Server
HBaseMaster
HMaster 負責給HRegionServer分配區域,並且負責對集群環境中的HReginServer進行負載均衡,HMaster還負責監控集群環境中的HReginServer的運行狀況,如果某一台HReginServer down機,HBaseMaster將會把不可用的HReginServer來提供服務的HLog和表進行重新分配轉交給其他HReginServer來提供,HBaseMaster還負責對數據和表進行管理,處理表結構和表中數據的變更,因為在 META 系統表中存儲了所有的相關表信息。並且HMaster實現了ZooKeeper的Watcher接口可以和zookeeper集群交互。
HRegionServer
HReginServer負責處理用戶的讀和寫的操作。HReginServer通過與HBaseMaster通信獲取自己需要服務的數據表,並向HMaster反饋自己的運行狀況。當一個寫的請求到來的時候,它首先會寫到一個叫做HLog的write-ahead log中。HLog被緩存在內存中,稱為Memcache,每一個HStore只能有一個Memcache。當Memcache到達配置的大小以后,將會創建一個MapFile,將其寫到磁盤中去。這將減少HReginServer的內存壓力。當一起讀取的請求到來的時候,HReginServer會先在Memcache中尋找該數據,當找不到的時候,才會去在MapFiles 中尋找。
HBase Client
HBase Client負責尋找提供需求數據的HReginServer。在這個過程中,HBase Client將首先與HMaster通信,找到ROOT區域。這個操作是Client和Master之間僅有的通信操作。一旦ROOT區域被找到以后,Client就可以通過掃描ROOT區域找到相應的META區域去定位實際提供數據的HReginServer。當定位到提供數據的HReginServer以后,Client就可以通過這個HReginServer找到需要的數據了。這些信息將會被Client緩存起來,當下次請求的時候,就不需要走上面的這個流程了。
HBase服務接口
HBase Thrift Server和HBase REST Server是通過非Java程序對HBase進行訪問的一種途徑。
進入正題
先來看一個HBase集群的模擬環境,此環境中一共有4台機器,分別包含 zookeeper、HBaseMaster、HReginServer、HDSF 4個服務,為了展示失效轉發的效果HBaseMaster、HReginServer各有2台,只是在一台機器上即運行了HBaseMaster,也運行了HReginServer。
注意,HBase的集群環境中HBaseMaster只有失效轉發沒有壓力分載的功能,而HReginServer即提供失效轉發也提供壓力分載。
服務器清單如下:
- zookeeper 192.168.20.214
- HBaseMaster 192.168.20.213/192.168.20.215
- HReginServer 192.168.20.213/192.168.20.215
- HDSF 192.168.20.212
整個模擬環境的架構如圖所示:
注意,這里只是做了一個模擬環境,因為這個環境的重點是HBase,所以zookeeper和HDFS服務都是單台。
雖然說在整個HBase的集群環境中只能有一個HMaster,可是在集群環境中HMaster可以啟動多個,但真正使用到的HMaster Server只有一個,他不down掉的時候,其他啟動的HMaster Server並不會工作,直到與ZooKeeper服務器判斷與當前運行的HMaster通訊超時,認為這個正在運行的HMaster服務器down掉了,Zookeeper才會去連接下一台HMaster Server。
簡單來說,如果運行中HMaster服務器down掉了,那么zookeeper會從列表中選擇下一個HMaster 服務器進行訪問,讓他接管down掉的HMaster任務,換而言之,用Java客戶端對HBase進行操作是通過ZooKeeper的,也就是說如果zookeeper集群中的節點全掛了 那么HBase的集群也掛了。本身HBase並不存儲中的任何數據 真正的數據是保存在HDFS上,所以HBase的數據是一致的,但是HDFS文件系統掛了,HBase的集群也掛。
在一台HMaster失敗后,客戶端對HBase集群環境訪問時,客戶端先會通過zookeeper識別到HMaster運行異常,直到確認多次后,才連接到下一個HMaster,此時,備份的HMaster服務才生效,在IDE環境中的效果,如圖所示:
上圖中能看見拋出的一些異常和name:javahttp://www.javabloger.com和name:javahttp://www.javabloger.com1的結果集,因為我在serv215機器上用killall java命令把 HMaster和HReginServer都關掉,並且立刻用Java客戶端對HBase的集群環境進行訪問有異常拋出,但是retry到一定次數后查詢出結果,前面已經說了訪問HBase是通過zookeeper再和真正的數據打交道,也就是說zookeeper接管了一個standby 的 HMaster,讓原先Standby的HMaster接替了失效的HMaster任務,而被接管的HBaseMaster再對HReginServer的任務進行分配,當 HReginServer失敗后zookeeper會通知 HMaster對HReginServer的任務進行分配。這樣充分的說明了HBase做到了實效轉發的功能。
如圖所示:
口水:
1、HBase的失效轉發的效率比較慢了,不指望能在1-2秒切換和恢復完畢,也許是我暫時沒有發現有什么參數可以提高失效轉發和恢復過程的速度,將來會繼續關注這個問題。
2、在官方網站上看見HBase0.89.20100924的版本有篇講述關於數據同步的文章,我嘗試了一下在一台機器上可以運行所謂的HBase虛擬集群環境,但是切換到多台機器的分布式環境中,單點失效轉發的速度很慢比HBase0.20.6還要慢,我又檢查了是否存在網絡的問題,目前尚未找到正確的答案,對與HBase0.89.20100924 新版中的數據同步的原理,如圖所示:(更多信息)
我的廢話1:
任何一項新技術並非救命稻草,一抹一擦立馬葯到病除的百寶箱,並非使用Spring或者NOSQL的產品就神乎其神+五光十色,如果那樣基本是扯淡。同類 型產品中不管那種技術最終要達到的目的是一樣的,通過新的技術手段你往往可能避諱了當前你所需要面對的問題,但過后新的問題又來了。也許回過頭來看看還不 如在原來的基礎上多動動腦筋 想想辦法 做些改良可以得到更高的回報。
傳統數據庫是以數據塊來存儲數據,簡單來說,你的表字段越多,占用的數據空間就越多,那么查詢有可能就要跨數據塊,將會導致查詢的速度變慢。在大型系統中一張表上百個字段,並且表中的數據上億條這是完全是有可能的。因此會帶來數據庫查詢的瓶頸。我們都知道一個常識數據庫中表記錄的多少對查詢的性能有非常大的影響,此時你很有可能想到分表、分庫的做法來分載數據庫運算的壓力,那么又會帶來新的問題,例如:分布式事務、全局唯一ID的生成、跨數據庫查詢 等,依舊會讓你面對棘手的問題。如果打破這種按照行存儲的模式,采用一種基於列存儲的模式,對於大規模數據場景這樣情況有可能發生一些好轉。由於查詢中的選擇規則是通過列來定義的,因此整個數據庫是自動索引化的。按列存儲每個字段的數據聚集存儲, 可以動態增加,並且列為空就不存儲數據,節省存儲空間。 每個字段的數據按照聚集存儲,能大大減少讀取的數據量,查詢時指哪打哪,來的更直接。無需考慮分庫、分表 Hbase將對存儲的數據自動切分數據,並支持高並發讀寫操作,使得海量數據存儲自動具有更強的擴展性。
Java中的HashMap是Key/Value的結構,你也可以把HBase的數據結構看做是一個Key/Value的體系,話說HBase的區域由表名和行界定的。在HBase區域每一個"列族"都由一個名為HStore的對象管理。每個HStore由一個或多個MapFiles(Hadoop中的一個文件類型)組成。MapFiles的概念類似於Google的SSTable。 在Hbase里面有以下兩個主要的概念,Row key 和 Column Family,其次是Cell qualifier和Timestamp tuple,Column family我們通常稱之為“列族”,訪問控制、磁盤和內存的使用統計都是在列族層面進行的。列族Column family是之前預先定義好的數據模型,每一個Column Family都可以根據“限定符”有多個column。在HBase每個cell存儲單元對同一份數據有多個版本,根據唯一的時間戳來區分每個版本之間的差異,最新的數據版本排在最前面 。
口水:Hbase將table水平划分成N個Region,region按column family划分成Store,每個store包括內存中的memstore和持久化到disk上的HFile。
上述可能我表達的還不夠到位,下面來看一個實踐中的場景,將原來是存放在MySQL中Blog中的數據遷移到HBase中的過程:
MySQL中現有的表結構:
遷移HBase中的表結構:
原來系統中有2張表blogtable和comment表,采用HBase后只有一張blogtable表,如果按照傳統的RDBMS的話,blogtable表中的列是固定的,比如schema 定義了Author,Title,URL,text等屬性,上線后表字段是不能動態增加的。但是如果采用列存儲系統,比如Hbase,那么我們可以定義blogtable表,然后定義info 列族,User的數據可以分為:info:title ,info:author ,info:url 等,如果后來你又想增加另外的屬性,這樣很方便只需要 info:xxx 就可以了。
對於Row key你可以理解row key為傳統RDBMS中的某一個行的主鍵,Hbase是不支持條件查詢以及Order by等查詢,因此Row key的設計就要根據你系統的查詢需求來設計了額。 Hbase中的記錄是按照rowkey來排序的,這樣就使得查詢變得非常快。
具體操作過程如下:
============================創建blogtable表========================= create 'blogtable', 'info','text','comment_title','comment_author','comment_text' ============================插入概要信息========================= put 'blogtable', '1', 'info:title', 'this is doc title' put 'blogtable', '1', 'info:author', 'javabloger' put 'blogtable', '1', 'info:url', 'http://www.javabloger.com/index.php' put 'blogtable', '2', 'info:title', 'this is doc title2' put 'blogtable', '2', 'info:author', 'H.E.' put 'blogtable', '2', 'info:url', 'http://www.javabloger.com/index.html' ============================插入正文信息========================= put 'blogtable', '1', 'text:', 'what is this doc context ?' put 'blogtable', '2', 'text:', 'what is this doc context2?' ==========================插入評論信息=============================== put 'blogtable', '1', 'comment_title:', 'this is doc comment_title ' put 'blogtable', '1', 'comment_author:', 'javabloger' put 'blogtable', '1', 'comment_text:', 'this is nice doc' put 'blogtable', '2', 'comment_title:', 'this is blog comment_title ' put 'blogtable', '2', 'comment_author:', 'H.E.' put 'blogtable', '2', 'comment_text:', 'this is nice blog' |
HBase的數據查詢\讀取,可以通過單個row key訪問,row key的range和全表掃描,大致如下:
注意:HBase不能支持where條件、Order by 查詢,只支持按照Row key來查詢,但是可以通過HBase提供的API進行條件過濾。
例如:http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/ColumnPrefixFilter.html
scan 'blogtable' ,{COLUMNS => ['text:','info:title'] } —> 列出 文章的內容和標題
scan 'blogtable' , {COLUMNS => 'info:url' , STARTROW => '2'} —> 根據范圍列出 文章的內容和標題
get 'blogtable','1' —> 列出 文章id 等於1的數據
get 'blogtable','1', {COLUMN => 'info'} —> 列出 文章id 等於1 的 info 的頭(Head)內容
get 'blogtable','1', {COLUMN => 'text'} —> 列出 文章id 等於1 的 text 的具體(Body)內容
get 'blogtable','1', {COLUMN => ['text','info:author']} —> 列出 文章id 等於1 的內容和作者(Body/Author)內容
我的廢話2:
有人會問Java Web服務器中是Tomcat快還是GlassFish快?小型數據庫中是MySQL效率高還是MS-SQL效率高?我看是關鍵用在什么場景和怎么使用這 個產品(技術),所以我漸漸的認為是需要對產品、技術本身深入的了解,而並非一項新的技術就是絕佳的選擇。試問:Tomcat的默認的運行參數能和我們線 上正在使用的GlassFish性能相提並論嗎?我不相信GlassFishv2和GlassFishv3在默認的配置參數下有顯著的差別。我們需要對產 品本身做到深入的了解才能發揮他最高的性能,而並非感觀聽從廠家的廣告和自己的感性認識 迷信哪個產品的優越性。
我的廢話3:
對於NOSQL這樣的新技術,的的確確是可以解決過去我們所需要面對的問題,但也並非適合每個應用場景,所以在使用新產品的同時需要切合當前的產品需要, 是需求在引導新技術的投入,而並非為了趕時髦去使用他。你的產品是否過硬不是你使用了什么新技術,用戶關心的是速度和穩定性,不會關心你是否使用了 NOSQL。相反Google有着超大的數據量,能給全世界用戶帶來了驚人的速度和准確性,大家才會回過頭來好奇Google到底是怎么做到的。所以根據 自己的需要千萬別太勉強自己使用了某項新技術。
我的廢話4:
總之一句話,用什么不是最關鍵,最關鍵是怎么去使用!
我的廢話:
大年三十夜,看春晚實在是太無聊了,整個《新聞聯播》的電視劇版本,還不如上上網,看看資料,喝喝老酒,寫點東西來的快活。
近2年來雲計算的話題到目前為止風風火火從來沒有平靜過,一直是大家嘴邊討論的熱門話題,人們期望運用雲計算提供可靠、穩定、高速的計算,在雲計算中Google是目前最大的雲計算供應商,例如:Google GAE(Google App Engine)和Google的Docs在線文章服務,這些SaaS上線產品的數據存儲(datastore)是由BigTable提供存儲服務的,在次之前我提到過Yahoo貢獻給Apache的那些山寨版本(Google與Yahoo的那些利器),其中Apache的HBase就是山寨了Google的BigTable。
我們知道在雲計算的技術話題中Apache的Hadoop項目是一塊基石,利用Hadoop項目中的產品可以建立雲計算平台和超大型的計算。不知道你是否有想過如果將HBase作為Google GAE上的數據存儲(datastore),那么每個用戶之間的數據訪問權限怎么辦?如果使用HBase提供對大客戶提供“私有雲”(private cloud)或者另一種可能一個公司內部的集群上運行HBase,公司的內部可能有幾個部門,某幾個部門之間的數據都是獨立分離但又運行在一個平台上,那么你就會發現HBase不具備這樣的功能,貌似目前HBase的最高版本0.90.0還沒有這樣的功能對用戶的表、Row、Cell的訪問權限。但是我們知道Google的GAE上每個用戶訪問的數據肯定是有權限划分的,不然我只要有權限登錄GEA就能看見所有用戶存放的數據了。這樣的問題你有可能沒有想過,但趨勢公司的工程師們卻為此想到了這點,並且把他們的設想和設計提交了HBase項目組,並且提出了以下主要的設計思想:
- Client access to HBase is authenticated
- User data is private unless access has been granted
- Access to data can be granted at a table or per column family basis.
對HBase中的表和數據划分權限等級和身份驗證后,操作權限被分為3大類,每類中包含的操作權限如下所示:
對於方案中涉及到存儲的權限的是指整個表或表中的列族,也就是說只考慮在表這個級別的權限,表與表之間的所屬關系是存放在 .META. 系統表中,以regioninfo:owner 的格式進行存放,例如:系統中table1這個表是有權限的,這個表權限的存根保存在3個地方 :
- The row in .META. for the first region of table1
- The node /hbase/acl/table1 of Zookeeper
- The in-memory Permissions Mirror of every regionserver that serves table1
如圖所示,圖中的箭頭表示了數據流向的順序:
方案中HBase在分布式、集群環境下,而權限一致性的問題交給了Zookeeper來處理,在多個regionservers中,每個服務器的HRegion中存放着多個表,並且實現了(implement)ZKPermissionWatcher接口的nodeCreated() 和 nodeChanged() 方法,這2個方法對Zookeeper 的節點進行監控, 節點的狀態發生相應的變化時會ZooKeeper刷新鏡像中的權限。
如圖所示:
HBase的這一關於權限的功能正在設計和研討當中,讓我們繼續對他保持關注,看看今后將會發生的變化能給我們帶來什么樣的效果,非常期待這個功能早日正式發布。