本文是對《 Hadoop系列四——HBase簡介 》一文的補充, 不過本文不會進行系統性介紹, 只是針對一個個獨立的點介紹, 並且會不斷更新, 有點類似於FAQ吧。
1. HBase的架構圖
簡易版架構圖:
複雜版架構圖:
架構講解見《 Hadoop系列四——HBase簡介 》。
2. HBase的資料模型
在《 Hadoop系列四——HBase簡介 》裡面已經介紹過HBase的資料模型了, 但這個的確非常重要, 這裡再做一些補充。 HBase是根據Google的Bigtable論文實現的開源版"Bigtable", 所以對Bigtable的描述同樣適用於HBase:
A Bigtable is a sparse,distributed, persistentmulti-dimensional sorted map. The map is indexed by a row key, column key, and a timestamp; each value in the map is anuninterpreted array of bytes.
這裡有幾個關鍵字我已經加粗了,
2.1 HBase裡面的"NULL值"處理
第一個就是 sparse關鍵字。 首先NULL值是RDBMS裡面的概念, HBase裡面其實沒有這個概念, 這裡只是為了作對比, 介紹稀疏性這個特性。 我們把HBase想成一個二維矩陣(這樣不準確, 但有助於理解), 那麼其實就是一個疏鬆陣列。 在RDBMS裡面, 沒有值的地方一般用NULL表示, 雖然相比於其他類型, NULL占很小的空間(一般是1bit), 但仍然是占空間的, 在RDBMS裡面這沒有問題, 主要有兩個原因:(1)RDBMS裡面資料量不會很大, 目前RDBMS能承載的最大資料量一般也就是百萬級別的。 (2)如果把RDBMS也看成二維矩陣的話, 一般RDBMS都屬於稠密矩陣, 所以NULL值不會占大多數。
但HBase不一樣, 它正好與RDBMS的特性相反:資料量很大, 一般都大於百萬級別(如果小於這個量級,
更多資訊見本文“ HBase的邏輯存儲和物理存儲”部分。
2.2 分散式
想想如果因為性能或存儲等不夠了, 需要將RDBMS擴展成分散式的, 能否做到?也許可以做到, 但一般是受限的, 而且難度比較高,
2.3 多維有序map
多維的概念在我的《 Hadoop系列四——HBase簡介 》裡面已經講過了。
有序之前也提過, 在HBase裡面, 不論是內部存儲, 還是查詢返回的資料, 都是有序的: 依次按照row key、Column Family、Column qualifier、Timestamp四個維度排序, 時間戳記是按照從新到舊排的, 其它都是字典序。
2.4 HBase裡面的資料是否有類型
上面對於value的描述是“ uninterpreted array of bytes”, 也就是沒有類型, 預設按位元組流解析(我們知道任何類型其實都可以按位元組流其解析)。 其實在HBase裡面除了會被作為路徑的名稱之外, 其它都是作為位元組流的,
3. HBase的邏輯存儲和物理存儲
引用 HBase:The Definitive Guide上的一幅圖:
第一幅圖(左上角)是HBase裡面一個典型的表的邏輯圖, 裡面有 cf1和cf2兩個Column Family(以下簡稱CF), 每個CF裡面有兩列。 裡面的紅色和黃色小塊表示有資料, 其他地方都沒有資料(如前面所說, 是一個疏鬆陣列), 多個層疊的部分表示有多個版本的資料。
第二幅圖(右上角)也是一個邏輯圖, 主要為了說明以下幾個點:
不同CF裡面的資料是分開存儲的;同一個CF裡面的資料是按照row key順序存儲的;統一cell裡面有多個版本的資料的時候, 新版本資料在前,舊版本資料在後,這樣方便先取到新版本資料。第三幅圖(右下角)是上面的邏輯存儲在物理檔上的存儲形式,需要注意以下幾個點:
不同CF的資料是存儲在不同的檔裡面的(Storefile或HFile),這就是為什麼我們要將要一起使用的資料欄位定義在同一個Column Family的原因;同一個檔裡面還是按照row key、CF、Column qualifier排序的;每一條資料裡面都要存儲Key(row key、Column Family、Column qualifier、Timestamp)和value。在RDBMS裡面我們設計欄位名時一般要求能夠“見名知意”,但在HBase裡面不推薦這樣做, Key的設計在保證功能的前提下,越短越好(比如僅用一個字母表示),至於其含義可以其它地方記錄,比如文檔裡面。第四幅圖(左下角)是為了說明查詢時指定各個Key對性能的影響:
指定 row key可以大幅度提高查詢性能,因為根據row key可以確定在哪些region上面查(也就是說可以跳過那些不包含該row key的region)。在scan命令裡面,可以通過STARTROW和STOPROW指定row key範圍。指定 Column Family可以大幅度提高查詢性能,因為根據CF可以確定跳過哪些Storefile/HFile,一般查詢時都建議指定CF。指定 Timestamp也可以較大幅度提高查詢性能,因為每個Storefile會存儲它所保存的所有資料的時間區間,如果所指定的Timestamp不在該區間內,則直接跳過。指定 Column Qualifier和Value的過濾條件可以提高查詢性能,但提高的很少。因為必須把每個Cell的值讀出來和指定的條件做對比。4. Tall-Narrow or Flat-Wide表
Tall-Narrow也就是我們所說的“窄表”,Flat-Wide是“寬表”。舉個例子,比如我們要存儲一個使用者的郵件資訊:使用者ID、郵件ID、郵件內容。如果按照Tall-Narrow的思想去設計,表結構可能是下面這樣:
# 將用戶id和郵件id拼接成row key,郵件內容作為一列資料userid-emailid, cf:emailbaody如果按照 Tall-Narrow思路去設計,表結構可能是下面這樣:
# userid為row key,emailid和emailbody作為兩個列userid, cf:emailid, cf:emailbody兩種設計各有利弊,使用寬表的好處主要在於HBase的ACID特性僅限於行內,所以如果把所有資料都放在一行,那可以很好的利用其ACID特性。而窄表在實際使用中更加常見一些,因為HBase裡面的的row key類似於RDBMS裡面的主鍵,所以我們盡可能將要經常查詢的維度放在row key裡面,可以提高查詢性能;另外一個表裡面不推薦有太多的Column Family,一般1個最好,最多也不要超過3個,具體見本文“Column Family的數量”部分。
5. HBase的表和Column Family能不能修改
先說結論: 可以修改。使用alter命令可以修改表和Column Family,具體語法可以help "alter"查看。這裡需要注意兩點:
0.92版本之前,表必須先disable後才可以修改。之後的版本增加了一個配置項 hbase.online.schema.update.enable,如果設為true,那可以直接修改,不需要disable。但官方推薦生產環境最好還是先disable再修改,線上修改可能會引發一些問題。修改動作並非立即生效,而是等待下一次 major compaction,Storefile重寫之後才會生效。6. HBase的Compaction
我們知道當MemStore裡面的資料量達到一定值的時候,就會落盤形成StoreFile(HFile),這樣就會形成很多檔,而Compaction就是將這些檔合併成大檔。HBase裡面有兩種Compaction: Minor compactions和Major compactions,主要有如下區別:
Minor compactions一次只選取少量存儲在一起的檔做合併壓縮,其結果就是一個store(或Column Family)的資料被合併成了多個大一些的Storefile,而Major compactions合併之後的結果是一個store(或Column Family)的資料全部到一個Storefile裡面去了。Minor compactions合併時不刪除已經標記刪除或者過期版本的資料,而Major compactions會刪掉那些標記刪除或過期版本的資料。所以需要注意,HBase裡面的刪除是標記刪除,真正的物理刪除發生在Major compactions階段。雖然Compaction合併檔是為了提高性能,但合併這個操作卻是消耗資源的,就跟Jvm的GC一樣。默認 Major compactions一週一次。
7. Column Family的數量
先說結論: 一個表內的Column Family最好1個,最多不要超過3個。原因主要有兩點:
現在HBase的flush(MemStore滿了之後就會flush)和Compaction操作都是基於region的,從前面的架構圖中可以看到一個region裡面是包含多個Column Family的,所以當region內的某個Column Family需要flush或Compaction的時候,和它處於同一region內的其它Column Family也會一起flush或Compaction,但它們可能只有少量新增資料,這就會浪費IO。假設有兩個Column Family:CF-A和CF-B,其中CF-A有一百萬條資料,CF-B有一千萬條資料。假設CF-A占了100個HFile,CF-B占了1000個HFile,因為資料寫入的先後順序,很可能CF-A的100個檔會被CF-B的1000個檔打散,本來可能一個RegionServer上面的region足夠存儲所有的CF-A的HFile了,現在可能被打散到多個RegionServer上面去了,這樣查詢CF-A的資料的時候效率就會降低。這種現象稱為“Cardinality of ColumnFamilies”。8. Value的版本數和TTL
版本數指我們之前說的Timestamp,和這個特性相關的設置有兩個: max versions和min versions,其含義也很明確。max versions的預設值是1,min versions的預設值是0,表示不啟用多版本這個特性,即往一個Cell裡面重複寫資料會覆蓋,而不是保留多個版本。
min versions和HBase的TTL(time-to-live)一起使用。我們可以給Column Family設置一個TTL時間(單位為秒),時間到期後的row會自動被刪除。如果一個Storefile裡面的row全部是過期的,那麼在minor compaction階段這個Storefile會被刪除,我們可以通過把hbase.store.delete.expired.storefile設置為false或者把min versions設置為非0值來關閉刪除這個特性。
9. 選擇HBase還是RDBMS
一般來說,這個選擇是比較好做的。HBase、Impala等資料庫的誕生並不是為了替代傳統的RDBMS,只是為了解決新的RDBMS解決不了或者解決起來比較困難的問題。所以,如果你的資料量並不大(一般以百萬為分界線),那一般應該優先選擇RDBMS,畢竟RDBMS支持完善的ACID,SQL,多級索引,各種Join,完善的類型等豐富的特性,這些都是HBase所不具備的。
但如果你的資料量非常大,RDBMS已經無法支撐了,那就可以考慮HBase等分散式資料庫了。但如果你的業務離不開RDBMS的一些特性(比如各種Join、SQL、完善的ACID等),那可能就需要考慮類似於GreenPlum這種MPP資料庫了。
10. FAQ
HBase是否支持ACID?HBase裡面只支持受限的ACID(Atomicity, Consistency, Isolation, and Durability):僅支持行內的ACID,跨行不支持。也就是對於同一行的操作是可以保證ACID的,但是多行操作是不行的。更多資訊可參考: ACID in HBase 。
HBase和Hive如何選擇?這兩個不是一個層級的東西,沒有可比性。如果你還在這二者之間糾結,那可能你對它們有些誤會,或者還不清楚你自己的需求。非要比的話,那就是HBase一般做即時查詢;而Hive一般作為離線資料倉庫,Hive後面是MapReduce/Spark,所以無法做到即時。
HBase支不支持join?先說結論: 不支持。HBase讀取資料時支援Get和Scan(Get的後臺實現是Scan的一種特殊情況而已)操作,RDBMS裡面的join在HBase裡面是不支持的,但我們可以在表設計上支持一定程度上的"join"操作,比如將需要join的欄位拼接起來作為row key。
HBase支持SQL嗎?HBase不支援SQL,只提供了各種API。但Apache下有個Phoenix專案,通過該專案可以使用SQL語句操作HBase。
HBase的一個region多大合適?注意,這裡說的是region,不是RegionServer。一個region保持在10~50GB比較好。
HBase一個表包含多少個region比較好?一般一個表包含50~100個region和1~2個Column Family比較好。
HBase的Cell裡面存儲的Value有大小限制嗎?沒有,但一般不要超過10MB(對於MOB物件不要超過50MB)。如果超過了這個大小,可以將物件存到HDFS上面,然後再HBase裡面存儲HDFS路徑。
HBase裡面的daughter是什麼?HBase的region分裂的時候,分裂出來的兩個新region稱為"daughter",原來的稱為"parent"。
關於HBase還有兩個核心的點:一個是row key的設計,另外一個就是HFile。目前計畫後續會分別寫兩篇文章來介紹這兩方面東西,有興趣的可持續關注。
References:
Apache HBase Reference Guide(Version3.0.0-SNAPSHOT).HBase:The Definitive Guide.-->
2.1 HBase裡面的"NULL值"處理
2.4 HBase裡面的資料是否有類型
3. HBase的邏輯存儲和物理存儲
4. Tall-Narrow or Flat-Wide表
5. HBase的表和Column Family能不能修改
7. Column Family的數量
8. Value的版本數和TTL
9. 選擇HBase還是RDBMS
新版本資料在前,舊版本資料在後,這樣方便先取到新版本資料。第三幅圖(右下角)是上面的邏輯存儲在物理檔上的存儲形式,需要注意以下幾個點:
不同CF的資料是存儲在不同的檔裡面的(Storefile或HFile),這就是為什麼我們要將要一起使用的資料欄位定義在同一個Column Family的原因;同一個檔裡面還是按照row key、CF、Column qualifier排序的;每一條資料裡面都要存儲Key(row key、Column Family、Column qualifier、Timestamp)和value。在RDBMS裡面我們設計欄位名時一般要求能夠“見名知意”,但在HBase裡面不推薦這樣做, Key的設計在保證功能的前提下,越短越好(比如僅用一個字母表示),至於其含義可以其它地方記錄,比如文檔裡面。第四幅圖(左下角)是為了說明查詢時指定各個Key對性能的影響:
指定 row key可以大幅度提高查詢性能,因為根據row key可以確定在哪些region上面查(也就是說可以跳過那些不包含該row key的region)。在scan命令裡面,可以通過STARTROW和STOPROW指定row key範圍。指定 Column Family可以大幅度提高查詢性能,因為根據CF可以確定跳過哪些Storefile/HFile,一般查詢時都建議指定CF。指定 Timestamp也可以較大幅度提高查詢性能,因為每個Storefile會存儲它所保存的所有資料的時間區間,如果所指定的Timestamp不在該區間內,則直接跳過。指定 Column Qualifier和Value的過濾條件可以提高查詢性能,但提高的很少。因為必須把每個Cell的值讀出來和指定的條件做對比。4. Tall-Narrow or Flat-Wide表
Tall-Narrow也就是我們所說的“窄表”,Flat-Wide是“寬表”。舉個例子,比如我們要存儲一個使用者的郵件資訊:使用者ID、郵件ID、郵件內容。如果按照Tall-Narrow的思想去設計,表結構可能是下面這樣:
# 將用戶id和郵件id拼接成row key,郵件內容作為一列資料userid-emailid, cf:emailbaody如果按照 Tall-Narrow思路去設計,表結構可能是下面這樣:
# userid為row key,emailid和emailbody作為兩個列userid, cf:emailid, cf:emailbody兩種設計各有利弊,使用寬表的好處主要在於HBase的ACID特性僅限於行內,所以如果把所有資料都放在一行,那可以很好的利用其ACID特性。而窄表在實際使用中更加常見一些,因為HBase裡面的的row key類似於RDBMS裡面的主鍵,所以我們盡可能將要經常查詢的維度放在row key裡面,可以提高查詢性能;另外一個表裡面不推薦有太多的Column Family,一般1個最好,最多也不要超過3個,具體見本文“Column Family的數量”部分。
5. HBase的表和Column Family能不能修改
先說結論: 可以修改。使用alter命令可以修改表和Column Family,具體語法可以help "alter"查看。這裡需要注意兩點:
0.92版本之前,表必須先disable後才可以修改。之後的版本增加了一個配置項 hbase.online.schema.update.enable,如果設為true,那可以直接修改,不需要disable。但官方推薦生產環境最好還是先disable再修改,線上修改可能會引發一些問題。修改動作並非立即生效,而是等待下一次 major compaction,Storefile重寫之後才會生效。6. HBase的Compaction
我們知道當MemStore裡面的資料量達到一定值的時候,就會落盤形成StoreFile(HFile),這樣就會形成很多檔,而Compaction就是將這些檔合併成大檔。HBase裡面有兩種Compaction: Minor compactions和Major compactions,主要有如下區別:
Minor compactions一次只選取少量存儲在一起的檔做合併壓縮,其結果就是一個store(或Column Family)的資料被合併成了多個大一些的Storefile,而Major compactions合併之後的結果是一個store(或Column Family)的資料全部到一個Storefile裡面去了。Minor compactions合併時不刪除已經標記刪除或者過期版本的資料,而Major compactions會刪掉那些標記刪除或過期版本的資料。所以需要注意,HBase裡面的刪除是標記刪除,真正的物理刪除發生在Major compactions階段。雖然Compaction合併檔是為了提高性能,但合併這個操作卻是消耗資源的,就跟Jvm的GC一樣。默認 Major compactions一週一次。
7. Column Family的數量
先說結論: 一個表內的Column Family最好1個,最多不要超過3個。原因主要有兩點:
現在HBase的flush(MemStore滿了之後就會flush)和Compaction操作都是基於region的,從前面的架構圖中可以看到一個region裡面是包含多個Column Family的,所以當region內的某個Column Family需要flush或Compaction的時候,和它處於同一region內的其它Column Family也會一起flush或Compaction,但它們可能只有少量新增資料,這就會浪費IO。假設有兩個Column Family:CF-A和CF-B,其中CF-A有一百萬條資料,CF-B有一千萬條資料。假設CF-A占了100個HFile,CF-B占了1000個HFile,因為資料寫入的先後順序,很可能CF-A的100個檔會被CF-B的1000個檔打散,本來可能一個RegionServer上面的region足夠存儲所有的CF-A的HFile了,現在可能被打散到多個RegionServer上面去了,這樣查詢CF-A的資料的時候效率就會降低。這種現象稱為“Cardinality of ColumnFamilies”。8. Value的版本數和TTL
版本數指我們之前說的Timestamp,和這個特性相關的設置有兩個: max versions和min versions,其含義也很明確。max versions的預設值是1,min versions的預設值是0,表示不啟用多版本這個特性,即往一個Cell裡面重複寫資料會覆蓋,而不是保留多個版本。
min versions和HBase的TTL(time-to-live)一起使用。我們可以給Column Family設置一個TTL時間(單位為秒),時間到期後的row會自動被刪除。如果一個Storefile裡面的row全部是過期的,那麼在minor compaction階段這個Storefile會被刪除,我們可以通過把hbase.store.delete.expired.storefile設置為false或者把min versions設置為非0值來關閉刪除這個特性。
9. 選擇HBase還是RDBMS
一般來說,這個選擇是比較好做的。HBase、Impala等資料庫的誕生並不是為了替代傳統的RDBMS,只是為了解決新的RDBMS解決不了或者解決起來比較困難的問題。所以,如果你的資料量並不大(一般以百萬為分界線),那一般應該優先選擇RDBMS,畢竟RDBMS支持完善的ACID,SQL,多級索引,各種Join,完善的類型等豐富的特性,這些都是HBase所不具備的。
但如果你的資料量非常大,RDBMS已經無法支撐了,那就可以考慮HBase等分散式資料庫了。但如果你的業務離不開RDBMS的一些特性(比如各種Join、SQL、完善的ACID等),那可能就需要考慮類似於GreenPlum這種MPP資料庫了。
10. FAQ
HBase是否支持ACID?HBase裡面只支持受限的ACID(Atomicity, Consistency, Isolation, and Durability):僅支持行內的ACID,跨行不支持。也就是對於同一行的操作是可以保證ACID的,但是多行操作是不行的。更多資訊可參考: ACID in HBase 。
HBase和Hive如何選擇?這兩個不是一個層級的東西,沒有可比性。如果你還在這二者之間糾結,那可能你對它們有些誤會,或者還不清楚你自己的需求。非要比的話,那就是HBase一般做即時查詢;而Hive一般作為離線資料倉庫,Hive後面是MapReduce/Spark,所以無法做到即時。
HBase支不支持join?先說結論: 不支持。HBase讀取資料時支援Get和Scan(Get的後臺實現是Scan的一種特殊情況而已)操作,RDBMS裡面的join在HBase裡面是不支持的,但我們可以在表設計上支持一定程度上的"join"操作,比如將需要join的欄位拼接起來作為row key。
HBase支持SQL嗎?HBase不支援SQL,只提供了各種API。但Apache下有個Phoenix專案,通過該專案可以使用SQL語句操作HBase。
HBase的一個region多大合適?注意,這裡說的是region,不是RegionServer。一個region保持在10~50GB比較好。
HBase一個表包含多少個region比較好?一般一個表包含50~100個region和1~2個Column Family比較好。
HBase的Cell裡面存儲的Value有大小限制嗎?沒有,但一般不要超過10MB(對於MOB物件不要超過50MB)。如果超過了這個大小,可以將物件存到HDFS上面,然後再HBase裡面存儲HDFS路徑。
HBase裡面的daughter是什麼?HBase的region分裂的時候,分裂出來的兩個新region稱為"daughter",原來的稱為"parent"。
關於HBase還有兩個核心的點:一個是row key的設計,另外一個就是HFile。目前計畫後續會分別寫兩篇文章來介紹這兩方面東西,有興趣的可持續關注。
References:
Apache HBase Reference Guide(Version3.0.0-SNAPSHOT).HBase:The Definitive Guide.-->
2.1 HBase裡面的"NULL值"處理
2.4 HBase裡面的資料是否有類型
3. HBase的邏輯存儲和物理存儲
4. Tall-Narrow or Flat-Wide表
5. HBase的表和Column Family能不能修改
7. Column Family的數量
8. Value的版本數和TTL
9. 選擇HBase還是RDBMS