介紹什麼是 NoSQL,NoSQL 和 RDBMS 之間有什麼區別,有什麼埸景下須要用 NoSQL 數據庫,NoSQL 數據的優勢和缺點;談談 NoSQL 一些基本的背景以後,這章會重點深刻談討 HBase 數據庫,HBase 的原理,交換 Shell 的基本更刪改查操做,HBase 集羣體系的結構,還會談談 HBase 與 HDFS 之間的關係,它在讀寫數據時的流程,有了這些理論基礎下,就能夠對 HBase 的性能調優有更透徹的瞭解,最後會談談 HBase 的備份和複製 (HBase 進階)。但願讀者看完這篇文章後html
NoSQL 數據庫和關係型數據庫的設計目的是爲了解決不一樣的問題,NoSQL 數據模型相對簡單,它適合應用靈活更強的 IT 系統,不須要預先定義表如構,並且 NoSQL 對數據庫性能要求較高,對 PB 級別的數據進行快速的檢索,不須要高度的數據一致性及廷遲性的埸景,能夠快的跟據 Key-Value 的方式來查看數據。在市埸上有四種NoSQL數據庫,分別是:算法
[下圖總結 NoSQL 和 RDBMS 的區別]
sql
NoSQL 與 RDBMS 最大的分別是數據量和讀寫吞吐量的不一樣,數據佈局和數據訪問頻率也不一樣,他們兩個應用解決問題的本質也不同,好比列存儲數據庫能夠快速查找的緣由是列族的設計能夠在每一次查詢中大量減小磁盤 IO 和數據量的訪問。NoSQL 數據庫很容易支持數據量達 PB 級別的數據,由於它的特性很容易支持分佈式水平擴展;但 RDBMS 只能處理 TB+ 級別的數據,若是你的數據場景是要處理不少事務性數據 e.g. 更新和刪除,那麼仍是優先選擇關係型數據庫 RBDMS,由於NoSQL數據庫不太善於頻繁的處理數據更新和刪除,由於數據是分佈在不一樣的節點上,還有數據是默認有三份副本,若是須要太量的更新操做,那麼每臺節點上的數據也有一併更新,這太太增長了解決方案的複雜性;NoSQL 聽從 CAP 和 BASE 理論,RDBMS 聽從 ACID 的理論。若是隻有上千行和上百萬行的數據,則用傅統數據庫會比較適合shell
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 的表,歸納了列族、列名和行之間的關係]
apache
這只是一個概念模型,HBase 的物理模型在存儲層面上是按照列族來存儲,所以,它的設計是不建議存儲太多的列在同一個列族中。緩存
要設計一個 HBase 表,要考慮的有如下幾個重點:RowKey 是惟一的索引鍵,應用程式依賴行來完成快速數據訪問;RDBMS 與 HBase 的特性比較;RDBMS 與 HBase 的表設計,RowKey 的設計,列族的設計,肯定數據的訪問類型;RDBMS 與 HBase 的 Scham 設計:關係爲中心,HBase 是以數據爲中心,先肯定數據的訪問方式。ruby
HBase 的 Region 是一張表,它相似於關係型數據庫中 partition 的概念, Region 是經過 RegionSever 的一個守護進程來對外(客戶端) 提供服務的, 表被折分爲小的分區, Region 包含起始行到結束行全部的行信息,一個 RegionServer 能夠有多個 Region。例如:User 表的其中一部份經過基於 RowKey 順序的動做被拆分紅三個不一樣的小 Region 而後隨機分發在不一樣的 RegionServer 節點上來對外提供受務。bash
[下圖是一張Hbase 的 User 表,描述了一張表是如何拆分紅不一樣的 Region 而後分發給 RegionServer]服務器
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(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(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
create 'movie', {NAME => 'desc'} create 'movie', {NAME => 'desc', VERSIONS => 2} create 'movie', {NAME => 'desc'}, {NAME => 'media'} create 'movie','desc','media'
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(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(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.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(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']}
scan 'movie' scan 'movie', {LIMIT => 3} scan 'movie', {STARTROW => 'row1', STOPROW => 'row3'} scan 'movie', {COLUMN => ['desc:title','media:type']}
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
delete 'movie', 'row2', 'desc:title', 1502806209427
hbase(main):032:0> deleteall 'movie', 'row1' 0 row(s) in 0.0300 seconds
hbase(main):031:0> count 'movie' 4 row(s) in 0.0380 seconds => 4
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 表來查找數據]
HBase 的 RegionServer 將數據寫入 HDFS 的本地磁盤上,這樣就可使用 HDFS 存儲全部表的數據,並且 Region 是以文件的形式存儲在 HDFS 之上,它繼承了 HDFS 的特性其中包括 NameNode 避免了單點故障提供了高可用性,DataNode 上存儲了三個數據副本保障了數據的持久性和確保若是節點出現故障也能夠保護數據的可用性,能夠經過添加 DataNode 來提升數據存儲的線性擴展能力,在 HDFS 的任意位置均可以寫讀Region 的數據,允計 RegionServer 運行在集羣的任何位置上。
[下圖是 DataNode 與 RegionServer 在 WorkerNode 實現數據本地性的概念圖 ]
HBase 存儲在 HDFS 是以 HFile 的特定文件格式,它構成表的實際存儲文件,Region 的列是根據表中不一樣的列族被分開存儲,每一個表在 RegionServer 上是以 StoreFile 的形式存儲,它在 HDFS 是不一樣的獨立文件
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 大小能夠基於每一張表設置,某些表的須要與默設置的 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 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 最終目的是要實現數據本地化來提升數據的檢索速度,因此要透過緊縮的操做來達到這個效果。