本課主題
- NoSQL 數據庫介紹
- HBase 基本操作
- HBase 集群架構與設計介紹
- HBase 與HDFS的關系
- HBase 數據拆分和緊縮
引言
介紹什么是 NoSQL,NoSQL 和 RDBMS 之間有什么區別,有什么埸景下需要用 NoSQL 數據庫,NoSQL 數據的優點和缺點;談談 NoSQL 一些基本的背景之后,這章會重點深入談討 HBase 數據庫,HBase 的原理,交換 Shell 的基本更刪改查操作,HBase 集群體系的結構,還會談談 HBase 與 HDFS 之間的關系,它在讀寫數據時的流程,有了這些理論基礎下,就可以對 HBase 的性能調優有更透徹的了解,最后會談談 HBase 的備份和復制 (HBase 進階)。希望讀者看完這篇文章后
- 了解 NoSQL 數據庫與關系型數據庫的區別;
- 了解 HBase 在功能, 設計和集群架構上的角色;
- 了解 HBase 中增刪改查 API 並熟識其操作;
- 了解 HBase 與 HDFS, ZooKeeper 之間的關系;
- 了解 HBase 是如何對數據進行拆分和緊縮;
NoSQL 數據庫介紹
NoSQL 數據庫和關系型數據庫的設計目的是為了解決不同的問題,NoSQL 數據模型相對簡單,它適合應用靈活更強的 IT 系統,不需要預先定義表如構,而且 NoSQL 對數據庫性能要求較高,對 PB 級別的數據進行快速的檢索,不需要高度的數據一致性及廷遲性的埸景,可以快的跟據 Key-Value 的方式來查看數據。在市埸上有四種NoSQL數據庫,分別是:
- 鍵值存儲數據庫:Key-Value 的鐽值對,通常用 Hash Table 來實現,這類數據庫的查找速度快、簡單,易部署,但數據無結構化,如果區部查找會很慢,和應用埸景是內容緩存,快速的檢索數據,主要用於大量數據的高訪問量負X,也適用於一些日志系統, e.g. Redis, Oracle BDB, Tokyo Cabinet;
- 列存儲數據庫:以列族 Column Family 式存儲,將同一列數據存在一起,鐽的特點是指向了多少個列,這些列是由列族來實現的,它的好處是查找快速,擴展性非常好以便應用海量數據存儲和處理,但功能相對局限,對設計要求很特定的要求,非常適合分布式文件系統 e.g. HBase、Cassandra, Accumulo, Riak;
- 文檔存儲數據庫:Key-Value 對應的鍵值時,Value 為結構化數據,更了解 Value 的內容,數據結構不嚴格,表結構可變它不需要像關系型數據庫一樣要預先定義表結構,可以看作他是鍵值數據庫的升級版,文檔類型處理得力比較好,但查詢能力不高,缺乏統一的查詢語法。使用埸景是 Web 應用,,e.g. MongoDB, CouchDB, Couchbase Server ;
- 圖形數據庫:圖結構,它可以提用圖結構的算法,比如最佳路線尋址,N度關系查找,使用靈活的圖形模型並且能擴展到不同的服務器上,但很多時候要對整個圖作計算才能得出需要的信息,這種結構不太適合分布式的集群方案。應用埸景:推薦系統,社交網絡和關於結構關系圖譜, e.g. Neo4J, Infinite Graph;
NoSQL 與 RDBMS 的區別
[下圖總結 NoSQL 和 RDBMS 的區別]
NoSQL 與 RDBMS 最大的分別是數據量和讀寫吞吐量的不同,數據布局和數據訪問頻率也不同,他們兩個應用解決問題的本質也不一樣,比如列存儲數據庫可以快速查找的原因是列族的設計可以在每一次查詢中大量減少磁盤 IO 和數據量的訪問。NoSQL 數據庫很容易支持數據量達 PB 級別的數據,因為它的特性很容易支持分布式水平擴展;但 RDBMS 只能處理 TB+ 級別的數據,如果你的數據場景是要處理很多事務性數據 e.g. 更新和刪除,那么還是優先選擇關系型數據庫 RBDMS,因為NoSQL數據庫不太善於頻繁的處理數據更新和刪除,因為數據是分布在不同的節點上,還有數據是默認有三份副本,如果需要太量的更新操作,那么每台節點上的數據也有一並更新,這太太增加了解決方案的復雜性;NoSQL 遵從 CAP 和 BASE 理論,RDBMS 遵從 ACID 的理論。如果只有上千行和上百萬行的數據,則用傅統數據庫會比較適合
HBase 介紹
HBase 是以數據為中心,RDBMS 是以關系為數據,HBase 是 NoSQL 數據庫中的列存儲數據庫,它有以下特點:強一致性讀寫,自動分片,HBase 通過 Region 分布在集群中,數據增加時,Region 會自動分割並重新分片。RegionServer 自動故障移取,HBase 支持 HDFS 之外的存儲文件,HBase 通過 MapReduce 支持大並發處理,HBase 支持以 API 方式訪問數據,HBase 以 Bloom Filters 和 Bloom Cache 對大量數據進行查詢優化。HBase 適合場景是存在隨機讀寫的埸景,每秒需要在 TB 級別數據上完成數以千計的操作,訪問的操作的方式要簡單、明確和直接,如果應用只是插入數據而且處理時需要讀取全部數據。HBase 不支持二次索引、事務性數據、關聯表的操作。HBase 的使用埸景:消息 (Message) 比如點贊,電商中的 SMS/ MMS,有隨機讀寫的能力,局部數據進行 TopN 的查詢、簡單實體、圖數據、指標。
[下圖是一張 HBase 的表,概括了列族、列名和行之間的關系]
- HBase 在表中存儲數據,而表數據最后存儲在 HDFS 上,數據被分割成 HDFS 塊 (Block) 存儲在集群的多個節點上,以128G為一個 BlockSize;
- HBase 是由 Column Family (列族),Column (列) 和 Row Key (行) 組成的,列族是列的一個集合,列族可以有任意數量的列,e.g. contactinfo:fname, contactinfo:lname 它也可以單獨對每個列族進行存儲屬性優化,比如對 profilephoto 進行壓縮存儲。
- HBase 每一行都有一個 RowKey 用於快速檢索,來保證一行數據的完整性,每個 RowKey 就類似於 RDBMS 的主鍵,HBase 表是基於 RowKey 進行快速檢索,行按照排序后進行存儲,
- HBase 底層磁盤上是按照 Column Family 分開進行存儲。這樣的好處是相對於行存,占用空間會很小;
- HBase 中間的數據是存儲在 Cell 中,而且 Cell 是有版本化的,可以自定義保留多少過版本,Cell 為空時不存儲。
這只是一個概念模型,HBase 的物理模型在存儲層面上是按照列族來存儲,因此,它的設計是不建議存儲太多的列在同一個列族中。
如何設計一個 HBase 的表
要設計一個 HBase 表,要考慮的有以下幾個重點:RowKey 是唯一的索引鍵,應用程式依賴行來完成快速數據訪問;RDBMS 與 HBase 的特性比較;RDBMS 與 HBase 的表設計,RowKey 的設計,列族的設計,確定數據的訪問類型;RDBMS 與 HBase 的 Scham 設計:關系為中心,HBase 是以數據為中心,先確定數據的訪問方式。
HBase 的 Region 是一張表,它類似於關系型數據庫中 partition 的概念, Region 是通過 RegionSever 的一個守護進程來對外(客戶端) 提供服務的, 表被折分為小的分區, Region 包含起始行到結束行所有的行信息,一個 RegionServer 可以有多個 Region。例如:User 表的其中一部份通過基於 RowKey 順序的動作被拆分成三個不同的小 Region 然后隨機分發在不同的 RegionServer 節點上來對外提供受務。
[下圖是一張Hbase 的 User 表,描述了一張表是如何拆分成不同的 Region 然后分發給 RegionServer]
HBase 基本操作
HBase Shell 是發送命令給 HBase 的交換式 Shell,HBase 是用 JRuby 來方問,在 terminal 上輸入 hbase shell 進入交換式界面。語法規則是如下:
command 'para1' 'para2' command 'param1',{PARA2 => 'stringvalue', PARA3 => 'intvalue'}
常用的語句包括增、刪、改、查分別以 put (先新增數據,發現 rowkey 相同則修改數據)、delete、get 或 scan. 以下是 put/ get/ scan/ delete 的模版語句。
HBase 存在兩個自定義兩個 namespace,分別是 hbase 和 default namespace。默認 hbase 是包含HBase 內部的 system namespace,如果沒有顯式定義 namespace 便會自動歸類為 default namespace。
create_namespace 'namespaceName' drop_namespace 'namespaceName' alter 'namespaceName' ,{METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}

create_namespace 'entertainment' create 'entertainment:movie', {NAME => 'desc'}
- 在 HBase Shell 中執行 help 來查看幫助文檔 e.g. hbase> help
hbase(main):040:0> help HBase Shell, version 1.2.0-cdh5.9.0, rUnknown, Fri Oct 21 01:20:14 PDT 2016 Type 'help "COMMAND"', (e.g. 'help "get"' -- the quotes are necessary) for help on a specific command. Commands are grouped. Type 'help "COMMAND_GROUP"', (e.g. 'help "general"') for help on a command group. COMMAND GROUPS: Group name: general Commands: status, table_help, version, whoami Group name: ddl Commands: alter, alter_async, alter_status, create, describe, disable, disable_all, drop, drop_all, enable, enable_all, exists, get_table, is_disabled, is_enabled, list, locate_region, show_filters Group name: namespace Commands: alter_namespace, create_namespace, describe_namespace, drop_namespace, list_namespace, list_namespace_tables Group name: dml Commands: append, count, delete, deleteall, get, get_counter, get_splits, incr, put, scan, truncate, truncate_preserve Group name: tools Commands: assign, balance_switch, balancer, balancer_enabled, catalogjanitor_enabled, catalogjanitor_run, catalogjanitor_switch, close_region, compact, compact_mob, compact_rs, flush, major_compact, major_compact_mob, merge_region, move, normalize, normalizer_enabled, normalizer_switch, split, trace, unassign, wal_roll, zk_dump Group name: replication Commands: add_peer, append_peer_tableCFs, disable_peer, disable_table_replication, enable_peer, enable_table_replication, list_peers, list_replicated_tables, remove_peer, remove_peer_tableCFs, set_peer_tableCFs, show_peer_tableCFs Group name: snapshots Commands: clone_snapshot, delete_all_snapshot, delete_snapshot, list_snapshots, restore_snapshot, snapshot Group name: configuration Commands: update_all_config, update_config Group name: quotas Commands: list_quotas, set_quota Group name: security Commands: grant, list_security_capabilities, revoke, user_permission Group name: procedures Commands: abort_procedure, list_procedures Group name: visibility labels Commands: add_labels, clear_auths, get_auths, list_labels, set_auths, set_visibility SHELL USAGE: Quote all names in HBase Shell such as table and column names. Commas delimit command parameters. Type <RETURN> after entering a command to run it. Dictionaries of configuration used in the creation and alteration of tables are Ruby Hashes. They look like this: {'key1' => 'value1', 'key2' => 'value2', ...} and are opened and closed with curley-braces. Key/values are delimited by the '=>' character combination. Usually keys are predefined constants such as NAME, VERSIONS, COMPRESSION, etc. Constants do not need to be quoted. Type 'Object.constants' to see a (messy) list of all constants in the environment. If you are using binary keys or values and need to enter them in the shell, use double-quote'd hexadecimal representation. For example: hbase> get 't1', "key\x03\x3f\xcd" hbase> get 't1', "key\003\023\011" hbase> put 't1', "test\xef\xff", 'f1:', "\x01\x33\x40" The HBase shell is the (J)Ruby IRB with the above HBase-specific commands added. For more on the HBase Shell, see http://hbase.apache.org/book.html hbase(main):041:0>
- 在 HBase Shell 中查看狀態和當前版本是用 status, version, e.g. hbase> status; hbase> version
hbase(main):036:0> status 1 active master, 0 backup masters, 3 servers, 0 dead, 1.3333 average load hbase(main):037:0> version 1.2.0-cdh5.9.0, rUnknown, Fri Oct 21 01:20:14 PDT 2016
- 在 HBase Shell 查看表是用 list,e.g. hbase> list
- 在 HBase Shell 創建表是用 create,假設有一張 movie 表,它以 row1 作為 rowKey, ColumnFamily 和 Column 分別是 desc 和 title,現在新增一條數值為 HomeAlone 的數據 e.g. hbase> create 'tablename', {NAME => 'ColumnFamilyName', VERSIONS => 5}
create 'movie', {NAME => 'desc'} create 'movie', {NAME => 'desc', VERSIONS => 2} create 'movie', {NAME => 'desc'}, {NAME => 'media'} create 'movie','desc','media'
- 在 HBase Shell 新增和更新數據是用 put,先新增數據,默認會插入當前服務器時間作為時間戳,發現 rowkey 相同便修改數據,把 movie 的數據更改為 HomeAlone 2,並插入時間戳 e.g. hbase> put 'tablename', 'rowkey', 'colfam:col', 'value' [,timestamp]
put 'movie', 'row1', 'desc:title', 'Goblin' put 'movie', 'row2', 'desc:title', 'Descendants Of The Sun' put 'movie', 'row3', 'desc:title', 'Doctors' put 'movie', 'row4', 'desc:title', 'W Special'
- 在 HBase Shell 刪除數據是用 drop 但前提是要先 disbale 表,disbale 表禁用表的置可維護的狀態來防止客戶端的訪問,允許執行各種維護命令,e.g. hbase> disable 'tablename' ; drop 'tablename'
hbase(main):017:0> disable 'movie' 0 row(s) in 2.2980 seconds hbase(main):018:0> drop 'movie' 0 row(s) in 1.2590 seconds
- 在 HBase Shell 查看表結構定義信息,包含所有表的列族名、屬性名和屬性值是用 describe, e.g. hbase> describe 'tablename'
hbase(main):007:0> describe 'movie' Table movie is ENABLED movie COLUMN FAMILIES DESCRIPTION {NAME => 'desc', DATA_BLOCK_ENCODING => 'NONE', BLOOMFILTER => 'ROW', REPLICATION_SCOPE => '0', VERSIONS => '1', COMPRESSION => 'NONE', MIN_VERSIONS => '0', TTL => 'FOREVER', KEEP_DELETED_CELLS => 'FALSE', BL OCKSIZE => '65536', IN_MEMORY => 'false', BLOCKCACHE => 'true'} 1 row(s) in 0.0950 seconds
- 在 HBase Shell 修改表結構是用 alter, 調整表的 meta,比如可以增刪改列族信息,也可以在線 Schama 調整功能,需要把以下參數調整為 true
hbase.online.schema.update.enable property = true
alter 'movie', NAME => 'media', METHOD => 'delete' alter 'movie', NAME => 'desc', VERSIONS => 5 alter_async 'movie', NAME => 'desc', VERSIONS => 5 alter_status
- 在 HBase Shell 查詢單條數據是用 get 可以進行單行數據根據行鍵檢索,檢索一行數據時,最近的版本時間戳最大的版本會被返回,e.g. hbase> get 'movie', 'row1'
hbase(main):022:0> get 'movie', 'row1' COLUMN CELL desc:title timestamp=1502806209403, value=Goblin 1 row(s) in 0.0110 seconds get 'movie', 'row2' get 'movie', 'row2', {COLUMN => 'desc:title'} get 'movie', 'row2', {COLUMN => 'desc:title', VERSIONS => 2} get 'movie', 'row2', {COLUMN => ['desc']}
- 在 HBase Shell 查詢整塊數據是用 scan,e.g. hbase> scan 'movie'
scan 'movie' scan 'movie', {LIMIT => 3} scan 'movie', {STARTROW => 'row1', STOPROW => 'row3'} scan 'movie', {COLUMN => ['desc:title','media:type']}
- 在 HBase Shell 檢查表是否被停用或啟動是用 is_disabled 或者 is_enabled, e.g. hbase> is_disabled 'table'; is_enabled 'table'
hbase(main):025:0> is_disabled 'movie' false 0 row(s) in 0.0170 seconds hbase(main):026:0> is_enabled 'movie' true 0 row(s) in 0.0130 seconds
- 在 HBase Shell 刪除Cell中的數據是用 delete, e.g. hbase> delete 'tablename', 'rowkey', 'colfam:col', [,timestamp]
delete 'movie', 'row2', 'desc:title', 1502806209427
- 在 HBase Shell 刪除表的所有行的數據是用 truncate, 表的列族不愛影響 e.g. hbase> truncate 'movie'
- 在 HBase Shell 刪除行的所有數據是用 deleteall, e.g. hbase> deleteall 'movie', 'row1'
hbase(main):032:0> deleteall 'movie', 'row1' 0 row(s) in 0.0300 seconds
- 在 HBase Shell 計算表的總行數是用 count, e.g. hbase> count 'movie'
hbase(main):031:0> count 'movie' 4 row(s) in 0.0380 seconds => 4
HBase 集群體系結構
RegionServer 是安裝在 Hadoop 的 DataNode 節點上,每個 WorkerNode 都有一個 RegionServer 的進程,分配的變化都是由 HBase Master 來管理啦,HBase Master 是監控集群中所有 RegionServer 實例,它是所有元數據修改的接口界面。HBase Master 是協調眾多的 Region Sever 的守護進程,確定每一個 Region Sever 管理那些 Region 的數據,新增、刪除、更新數據都由產生分配變化,因此需要 HBase Master 來統一管理。HBase 集群可以配置多個 Master 來提供高可用,集群受控於一個Master,ZooKeeper 服務處理 Master 之間的協調動作。 ZooKeeper 運行在集群的 Master 節點上,啟動后所有節點會連接到 ZooKeeper, 以競爭的形式運行,第一個連接到 ZooKeeper 的會獲得控制權,如果主節點的 Master 乏敗后,剩下的 Master 會競爭控制權
HBase 有兩大類的表,一類是 UserSpace,這是通過 HBase Shell 和 HBase API 創建的表,記錄了真正用戶創建的表,e.g. Moive, UserInfo;另外一種是 Catalog 表,它只有 HBase 系統訪問的表,它的用途是記錄元數據的特定表,跟蹤並記錄 Region 和 Region Sever 的位置,hbase:meta 是一張 HBase 的表,但不可以通過 HBaseShell 的 list 命令查找,HBase Master 通過 ZooKeeper 能夠快從 hbase:meta 定位並查找元數據表的位置。
假設現在用戶以 HBase Shell 創建了一張 UserInfo 的表, HBase 會通過以下幾個步驟來查找 HBase 的數據:
[下圖是HBase 如何經過 hbase:meta 表來查找數據]
- 第一步:客戶端會首先連接 ZooKeeper 來查詢 hbase:meta 表元數據的位置;
- 第二步:查詢 hbase:meta 表的元數據內容,來指定所有 Region 和它們的位置 (一張 UserInfo 表的數據會被拆分成不同的 Region,但 hbase:meta 不會被拆分到不同的節點上,希望hbase:meta 是可以集中式管理以便快速找到 meta 表的信息和檢索。)
- 第三步:然后查詢包含 UserInfo 表數據的 Region 所在的 Region Sever,這樣就可以獲取到數據內容並返回給客戶端,前兩步的查詢會在客戶端進行緩存,以便快速查找數據。
HBase 與 HDFS 的關系
HBase 的 RegionServer 將數據寫入 HDFS 的本地磁盤上,這樣就可以使用 HDFS 存儲所有表的數據,而且 Region 是以文件的形式存儲在 HDFS 之上,它繼承了 HDFS 的特性其中包括 NameNode 避免了單點故障提供了高可用性,DataNode 上存儲了三個數據副本保障了數據的持久性和確保如果節點出現故障也可以保護數據的可用性,可以通過添加 DataNode 來提高數據存儲的線性擴展能力,在 HDFS 的任意位置都可以寫讀Region 的數據,允計 RegionServer 運行在集群的任何位置上。
[下圖是 DataNode 與 RegionServer 在 WorkerNode 實現數據本地性的概念圖 ]
HBase 存儲在 HDFS 是以 HFile 的特定文件格式,它構成表的實際存儲文件,Region 的列是根據表中不同的列族被分開存儲,每個表在 RegionServer 上是以 StoreFile 的形式存儲,它在 HDFS 是不同的獨立文件
HBase 數據拆分和緊縮
數據拆分
HBase 是如何進行數據拆分的? 當表在拆分的過程中,會創建額外的兩個列 info:splitA 和 info:splitB,它代表兩個 daughter region,這兩個列的值會序列化 HRegionInfo 實列,Region 分割完畢后,這兩行會自動刪除。然后創建兩個 daughter reference 文件,daughter 文件只包含 region 拆分的位置的鍵,在主緊縮中原始數據文件會被重新寫成新 Region 目錄下的單獨文件,小的 reference 文件和原始 Region 則會被刪除掉。
[下圖是一個 Region (Start Key A 到 Start Key G) 拆分成兩個Region: Region1 (Start Key A 到 Start Key C) 和 Region2 (Start Key C 到 Start Key G) 的過程]
什么時候會獨發拆分?當有大量的新增數據到一個 Region 時,RegionServer 感知到數據量超過了預值,便會獨發 Region 拆分,在拆分過程中要注意有以下幾點:
- 此時的 Region 是不能對外提供服務的,快完成整個拆分的動作
- 復制和拷貝動動是不可進行的
- RegionServer 會更新 hbase:meta 元數據信息
- Region 拆分完畢
Region 大小可以基於每一張表設置,某些表的需要與默設置的 Region 大小不同時,通過 HTableDescriptior 和 setFileSize 事件設置,Region 的大小是容量可用性和分布性的基本單位,所以不建議太小的數據分布到過多的 Region 中,高 RegionCount 會影響性能,例如超過 3000 Count,但低 RegionCount 也會降低並行擴展能力,建議:每一個 RegionServer 包含 20~小幾百個 Region。RegionServer 會自動移動 Region 來實現集群的負載均衡,負載均衡操作的時間是由 hbase.balancer.period 來設置的,默認是 300000 ms (5分鍾)。
小緊縮與主緊縮
HBase 是如何進行緊縮的?緊縮的目的是把幾個小的 StoreFile 合並為一個大的文件,來減少因為需要管理過多的小文件而導的資源開銷,通常是3個小的 StoreFile 就會觸發一次 Minor Compression,可以適當地控制 StoreFile 的數量。可以通過 hbase.hstore.compactionThreshold,數值較大會導致緊鎖更少,但是每次緊鎖耗的時間更長,在緊鎖期間,Memstore 無法刷新磁盤,此時如果 memstore 的內存耗盡,客戶端就會導致阻塞或者是超時。
[下圖是多個 StoreFile 小文件經過小緊縮后合並成了三個小的 StoreFile]
主緊縮 (major compaction), 讀取一個 Region 中所有 StoreFile 並且將其寫到一個 StoreFile,之前標示刪除的數據和舊版本的數據都會在物理層面上被清除掉,主緊縮默應是一周 (七天) 進行一次,可以通過參數 hbase.hregion.majorcompaction 配置主緊縮的時間間隔 (單位是毫秒),當該參數設置為 0 時表示禁用主緊縮,因為主緊縮是非常耗資源的,所以建議是以交錯的方法為每個 RegionServer 進行主緊縮,這樣可以防止全部 RegionServer 在同一個時間內進行主緊縮。
[下圖是三個 StoreFile 經過主緊縮后合並成了一個大的 StoreFile]
在生產環境下主緊縮的最佳實踐:
- 因為主緊縮是一個非常耗資源的操作,所以建議在負載比較低的時候運行;
- 通過參數 hbase.hregion.majorcompaction 調大主緊縮的間隔時間 (單位是毫秒),同時使用腳本來執行主緊縮操作,如果腳本失敗,需將這個參數的值設置為 0,當然這種設置同時會出現主緊縮永不發生的風險;
- 通過參數 hbase.hregion.majorcompaction.jitter 來確保不讓所有 RegionServer 上的主緊縮操作同時進行,默應是 0.5 (50%),每一個 RegionServer 的 hbase.hregion.majorcompaction 參數的值乘以一個隨機的分數 (這個隨機分數取值區間不超過 jitter) 和hbase.hregion.majorcompaction 參數的值加或減這個值來確定下一次主緊縮的運行時間。
例子:通過 hbase.hregion.majorcompaction x hbase.hregion.majorcompaction.jitter 兩個參數的結合來防止各個 RegionServer 上的主緊縮操作在同一個時間點上發生,假設主緊縮每7天進行一次,然后乘以 jitter 這個隨機分數 e.g. 0.5。7 天 x (0~0.5) = 0 ~ 3.5 天。然后把 7天加或者減這個值 e.g. (7天-3.5) ~ (7天+3.5) = 3.5天 ~ 10.5 天,便會計算出下一次主緊縮發生的時間。在這個例子中,每個 3.5 天到 10.5 天便會觸發一次主緊縮行為。
RegionServer 最終目的是要實現數據本地化,才能夠快速查找數據,HDFS 客戶端默認拷貝三份數據副本,其中第一份副本寫到本地節點上,第二和第三份則寫在不同機器的節點上 (RegionServer);Region 的拆分會導致 RegionServer 需要讀取非本地的 StoreFile,此時,HDFS 將會自動通過網絡拉取數據,但通過網絡讀寫數據相對地比本地讀寫數據的效率要低,要提升效率,必須盡可能采用數據本地性,這也是為什么 HBase 要不定時地進行主緊縮和刷新把數據聚合在本地磁盤上來實現數據本地化,提升查詢效率。
總結
NoSQL 數據庫與關系型數據庫有著本質的設計與功能差別,兩者之間的使用的埸景和需求都不一樣。關系型數據庫善於處理結構化數據和頻繁地對數據進行更新和刪除的操作,設計模型是以關系為中心的,有一系列的功能包含提供索引,很容易實現二次排序,數據分片、可以實現大量的關聯操作,針對事務性數據有良好的支持,不過比較難實現分布式擴展和只能支持 TB+ 以上的數據量。NoSQL 數據庫是以數據為中心,沒有過多對表結構的規范,比如不需要在創建表之前先定義整個表結構,只需要定義列族和行信息即可,NoSQL 數據庫很容易實現分布式擴展且能支持 PB+ 以上的數據量,因為分布式和靈活的表設計,NoSQL 的應用埸景是適合快速隨機讀寫數據,但它是不支持事務性數據,e.g. CUID (增刪改查),所以NoSQL 數據庫與關系型數據庫是不能完全替代的,只是為不同的需求提出不同的解決方案。
HBase 的架構也是 Master-Slave 結構,HBase Master 負責協調各個節點的工作,在每個工作節點上都布署了一個 RegionServer,負責對外提供服務。HBase 的表是以 Region 概念來拆分,一張表可以拆分為不同的 Region 然后分發到不同的 RegionServer 上,每個表在創建時只需要定義列族,HBase 是以列族形式分開存儲在 HDFS 上。
HBase 有拆分和緊縮機制,當數據量達到一個預值上限時,便會觸發拆分操作,每個 Region 上有很多小的 StoreFile,當 StoreFile 達到一定數量,也會觸發一次小緊縮,緊縮的目的是把幾個小的 StoreFile 合並為一個大的文件,來減少因為需要管理過多的小文件而導的資源開銷,每一段時間過后,也需要進行主緊縮,主緊縮會讀取一個 Region 中所有 StoreFile 並且將其寫到一個 StoreFile,因為 RegionServer 最終目的是要實現數據本地化來提高數據的檢索速度,所以要透過緊縮的操作來達到這個效果。
參考資料
[3] NoSQL 數據庫應用埸景:京東618:一個中心五個原則,談談物流系統的大促優化實踐