HBase(十二) 最佳實踐
存儲上是否連續(xù)分布。上文說過,Hbase讀數(shù)據(jù)實際上都是scan,連續(xù)分布的數(shù)據(jù)讀取效率較高,系統(tǒng)IO的垃圾數(shù)據(jù)較少

1. 一次RPC能夠?qū)懭霐?shù)據(jù)量。IO是hbase的瓶頸之一,需要考慮一次RPC能夠?qū)懭敫嗟臄?shù)據(jù)。
2. 寫數(shù)據(jù)是否均衡。一段時間之內(nèi)寫入的數(shù)據(jù)在分布上能夠一定程度上分散開能夠保證并發(fā)度,提高寫數(shù)據(jù)速度。(所以這里和讀的順序性要求是要做權(quán)衡的)
3. 寫數(shù)據(jù)是否相對集中。短時間內(nèi)寫入的數(shù)據(jù)太分散的話會導(dǎo)致容易達到寫操作內(nèi)存警戒線,影響性能。
1. 有效清理數(shù)據(jù)。Hbase沒有提供高效的數(shù)據(jù)清理手段,數(shù)據(jù)需要合理的清理方案(Delete/dorptable/TTL/Versions)
2. 保證沒有大量過小或者空的region。空region在HBase中占用負載和內(nèi)存,而且hbase沒有有效手段來清理或者合并這些region
仿照oracle分區(qū)表的概念,按周期建表,如按天建表。
這樣涉及同一段時間的數(shù)據(jù)相對集中,且過期清理數(shù)據(jù)可以簡單drop表即可。
TTL要在合并才刪除,占用數(shù)據(jù)空間,且增加compact負擔
少量的數(shù)據(jù)版本可以巧用這個功能,但是大批量的版本差異,不太適合用這個功能。
且要注意version類似日志滾動,設(shè)置數(shù)量是恒定的,新版本進來,最老版本會移除。
hbase只能依據(jù)行分片,且從查詢效率來講,最有效的信息就是行健,所以把關(guān)鍵信息盡量放到行健中。(要平衡信息與長度)
列族可以配置是否開啟布隆過濾器。寫入數(shù)據(jù)的時候,要將該數(shù)據(jù)的key添加到bloomfilter中;讀取數(shù)據(jù)之前,要使用該數(shù)據(jù)的key在bloomfilter中進行測試,確定該key是否添加到了bloomfilter中。因此,bloomfilter可以用來在讀取一個精確的key之前,預(yù)判該key是否在文件中實際存在,進而減少讀取文件的消耗。由于bloomfilter是根據(jù)多個hash函數(shù)hash出來的bit值進行判斷,可能會有重復(fù),因此bloomfilter可以準確判斷出一個key的不存在,而不能準確判斷出key的存在。
所以對于單個get或者需要修改所有記錄的情況,是不適合使用布隆過濾器的。因為布隆過濾器是有額外的開銷的,bloomfilter的vectorsize、元素個數(shù)、hash函數(shù)個數(shù)之間的關(guān)系如下:
M表示vectorsize,n表示元素個數(shù),k表示hash函數(shù)個數(shù),則:
M = (k*n)/ln2
在hbase中,hash函數(shù)個數(shù)默認為4,因此,m和n的關(guān)系為:
M=5.77n。
因此,假定有1M條記錄要插入bloomfilter,則需要的向量的大小為5.7M bit,約0.7Mb。
如果每條記錄在磁盤上存儲的大小是256個字節(jié),如果有1T的數(shù)據(jù),則有4G條記錄,約耗費2.7G內(nèi)存用于存儲bloomfilter。
如果每條記錄在磁盤上的存儲大小為2K,如果有1T的數(shù)據(jù),則有500M條記錄,約耗費350M內(nèi)存用于存儲bloomfilter。
因此,存儲的每條記錄越大,bloomfilter的空間利用效率越高。
所以,適合使用bloomfilter的場景需要同時滿足如下條件:
訪問數(shù)據(jù)使用精確的key。
數(shù)據(jù)是小key,大value的模式。(即使這樣,也要根據(jù)數(shù)據(jù)量來計算消耗的內(nèi)存,綜合判斷)
盡量使用行級,發(fā)現(xiàn)沒有性能提升才考慮行+列級的布隆過濾器。
可枚舉數(shù)量少擴展性弱的屬性作為Family,不可枚舉數(shù)量多擴展性強的屬性作為column。
Column Family的增、刪、改都需要首先disable Table,影響其他Family的正常訪問,因此作為Family的屬性取值范圍要盡量減少擴展。存儲角度,一個列族的數(shù)據(jù)會存在一個store file中,所以列族中數(shù)據(jù)盡量相關(guān),集中。
每個family有自己獨立的屬性,例如version和TTL。因此,如果數(shù)據(jù)對于這些屬性需求不同的話,不能存儲在同個family中。 有兩種選擇,存在不同family或不同的table。
放在不同的family中,會導(dǎo)致同一個reagion不同family的大小差異比較大,出現(xiàn)很多小的或者空的store,導(dǎo)致store數(shù)量無端增加。由于hbase中,很多內(nèi)部操作(如flush、compact)的執(zhí)行單位是store,store的增加會影響系統(tǒng)性能,因此需要盡量避免由于不同family大小失衡導(dǎo)致的大量小store的出現(xiàn)。因此,daily、hourly、monthly數(shù)據(jù)推薦存放在不同的table。
類似一個對象不同屬性,同時存取,異或一個請求的不同字段等情況,適合做對象序列化后存入,如PB等。這樣減少key的存放,節(jié)約存儲效率。同時也節(jié)省RPC調(diào)用。
數(shù)據(jù)同時存取,但是量大,就不適合放在一個cell了。這時可以選擇分片到同列族的不同列中。這也會減少一定的RPC。
從上面目標中已經(jīng)看出,行健設(shè)計要權(quán)衡讀和寫的性能均衡。
因為hbase的查詢機制是指定頭尾的scan,所以盡可能要保持記錄連續(xù)性。且要考慮行健設(shè)計給分頁查詢帶來的影響,是否能有效識別offset,和offset的跳轉(zhuǎn)。
而連續(xù)寫恰恰會造成IO熱點,會降低寫入的性能。但是又不能過于分散,否則同樣會造成IO問題。
行健在不過長的前提下,盡量包含關(guān)鍵信息,有幾個策略,以下策略是寫的效率越來越低,讀的效率越來越高:
行健完全隨機,如行健采用時間戳的md5值。寫的效率非常高,但是只適合單行g(shù)et,任何范圍scan都會比其他策略的效率低。
單業(yè)務(wù)查詢下,權(quán)重最高的字段放在最前面,效率最高。
多業(yè)務(wù)共享表的情況,要綜合多業(yè)務(wù)的實際情況,選一個最優(yōu)的策略。
可枚舉的字段相當于聚合順序數(shù)據(jù),對相關(guān)業(yè)務(wù)查詢會提升效率。
如prefix=(時間戳%region數(shù)),這樣保證數(shù)據(jù)分散到所有region server。
好處是可以多線程讀取數(shù)據(jù),相當于數(shù)據(jù)平均分割。
壞處是要掃描連續(xù)數(shù)據(jù)時,對每個region server都要發(fā)起請求。
所有行健長度相等,嚴格按照一定順序增長。這種策略讀的效率雖高,但寫入效率最低。
這兩種都是數(shù)據(jù)清理的可能策略。循環(huán)key可以保證TTL清除老數(shù)據(jù),不會導(dǎo)致空region的問題,會重復(fù)寫入數(shù)據(jù)。
按照時間周期進行建表的方式也可以解決空region的問題,和循環(huán)key方法相比較,
操作簡單,不需要重復(fù)建表,系統(tǒng)自動處理
需要使用TTL來老化數(shù)據(jù),可能會增加compact負擔
需要保證查詢操作不會查詢到過期數(shù)據(jù),否則會影響系統(tǒng)性能。
根據(jù)以上對比,如果在系統(tǒng)壓力不是特別大,需要長期運行,能夠控制查詢不會查詢到過期數(shù)據(jù)的場景下,建議使用TTL+循環(huán)key的方式,否則建議使用按照時間周期進行建表的方式。
hbase的主要索引方式還是通過rowkey,官方并不提供二級索引。
華為hbase團隊是采用表數(shù)據(jù)和index數(shù)據(jù)分表查詢,這里region分區(qū)很復(fù)雜,且多表數(shù)據(jù)一致性處理也很復(fù)雜。
360分享了一個二級索引的方案,很巧妙,可以參考
http://www.infoq.com/cn/presentations/qihoo360-hbase-two-stage-index-design-and-practice
思路很簡單,做列->rowkey的映射就可以了,因為hbase自帶的rowkey->列的索引,所以就可以查出所有數(shù)據(jù)。
索引和數(shù)據(jù)在同一個region內(nèi),但索引數(shù)據(jù)存儲在單獨index family中,360固定一個family就叫INDEX。在一個region,所以寫不需要額外的操作,只需要把索引信息也加到put中。
為了保證在同一個region中,所以索引創(chuàng)建的反序列化信息要以region startkey開頭。
構(gòu)建索引查詢,如c21,就構(gòu)造region的startkey+index+c21‘,c21’是剛好大于c21的一個值。
在單列索引的情況下,所列結(jié)合在一起,看圖明意:
通過重建索引的方式解決
? 列和時間建立聯(lián)合索引
? 常用組合查詢建立聯(lián)合索引
? 查詢表達式的轉(zhuǎn)換(A | B) & (C | D) à (A&C) | (A&D) | (B&C) | (B&D)
引入搜索,如solr。
Hbase并不支持跨行和跨表的ACID。設(shè)計上要考慮這種事務(wù)缺失帶來的影響。
如果確實要用事務(wù),需要第三方協(xié)調(diào)機制,如借助zk的分布式協(xié)調(diào),做事務(wù)控制。
這里主要指region server的配置,因為hbase的主要負載不在master。
按業(yè)務(wù)需要指定堆大小,特別注意新生代的大小,遇到過minor GC過多的問題。且hbase快速flush的數(shù)據(jù)大都在年輕代搞定,所以要適當調(diào)大年輕代大小 ,一般不使用默認值。
垃圾回收指定CMS+parnew,建議開啟gc日志
-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:xxx/xxx.log"
region server設(shè)置60%的堆占用率,其中20%塊緩存+40%memstore,所以CMS收集率要調(diào)到70%,-XX:CMSInitiatingOccupancyFraction=70,也需要觀察實際情況做調(diào)整。
MSLAB的引入是為了解決內(nèi)存空洞的問題,因為長期存在的keyvalue會占用老年代,一旦flush到磁盤,就會產(chǎn)生碎片,碎片多了之后,就會產(chǎn)生stop the world GC。
MSLAB設(shè)計會減少碎片,核心思路是從堆分配相同大小的對象,回收后會產(chǎn)生固定大小的空洞,之后分配也是同樣大小的對象,這樣就不會有大量碎片空間而無法分配內(nèi)存的問題。
當一個分配區(qū)不足以放下一個KeyValue時,就會認為這個分配區(qū)已滿,所以這里面也有一定的浪費。
是否使用MSLAB通過hbase.hregion.memstore.mslab.enabled參數(shù)配置。
分配區(qū)大小默認是2MB,通過hbase.hregion.memstore.mslab.max.allocation參數(shù)調(diào)整。
KeyValue大小有控制,默認大于256KB的就會繞過MSLAB,直接申請堆內(nèi)存,所以大的keyvalue多了之后,MSLAB作用就小的多了。這個上限通過hbase.hregion.memstore.mslab.max.allocation參數(shù)修改。
Hbase支持多種壓縮算法,各有特點,如LZO速率快,但是壓縮率低。GZIP壓縮率高,但速率慢,snappy相對來說更均衡。使用哪種方式也結(jié)合業(yè)務(wù)情況。
如果保存已經(jīng)壓縮過的數(shù)據(jù),就不需要啟動壓縮了,如JPG圖片。
壓縮可以配置在family上。
識別可能的熱點,設(shè)置splitkey,進行region預(yù)分。
這個方案適合非完全連續(xù)的行健,如果完全連續(xù),一段時間內(nèi)的插入數(shù)據(jù)總會集中到最近生成的幾個region上。
可以先控制拆分10個region,或根據(jù)實際情況調(diào)整,因為region數(shù)量會影響集群性能,所以不能過多,也不能有空region。
可以按照region中最大的存儲文件大小決定預(yù)拆分region的數(shù)量,最大的region剛好跳過major合并,就會大大減少compact風暴。
region的調(diào)整,hbase提供了負載均衡機制,默認每五分鐘嘗試分配region平衡到所有region server上。運行時間SLA設(shè)置為間隔時間的一半。
默認region大小為256M,為了保證適當大小的region長期穩(wěn)定,可以調(diào)整到1G。注意業(yè)務(wù)按需,和調(diào)大后GC停頓變長的問題。
有大量寫入時,setAutoFlush(false),否則put會逐個提交,通過批量緩存,一次提交提高吞吐量。
還是提高緩存提升批量處理效率的思路,但是注意要衡量緩存大了之后內(nèi)存占用高的問題。
注意scan添加列,剔除無效列的查詢
如HTable,getScanner()得到的ResultScanner,要在finally關(guān)閉。
頻繁使用的行,要開啟這個功能。
大批量掃描,如MR的集成,要關(guān)閉這個功能。
添加MUST_PASS_ALL策略的filter,指定FirstKeyOnlyFilter 和KeyOnlyFilter,可以減少大量的網(wǎng)絡(luò)傳輸,只返回第一個發(fā)現(xiàn)的keyvalue的行健。
大量的Put操作,且急切要提升寫入效率,可以考慮關(guān)閉WAL。但是有丟數(shù)據(jù)的風險。
zk的超時有zookeeper.session.timeout參數(shù)控制,默認是3分鐘,根據(jù)業(yè)務(wù)需要可以調(diào)高和調(diào)低這個值,但是要注意的是,要考慮GC停頓的時間,否則就會造成假死現(xiàn)象,進程還在,但是master已經(jīng)認為region server掛了。
默認region server響應(yīng)外部請求的線程數(shù)為10,由參數(shù)hbase.regionserver.handler.count控制,這個值主要考慮單次請求吞吐量大的場景,一般是MB級別,如果單次請求較小,如get,小put等,可以考慮調(diào)高這個值。
但是調(diào)高這個值會增加server端的OOM異常風險,使GC更頻繁。
可以配合調(diào)高region server的堆大小,甚至有方案調(diào)到了8G以上,更夸張的也有。
堆中塊緩存大小默認為20%(0.2),由參數(shù)perf.hfile.block.cache.size控制,監(jiān)控是否有多塊被換入換出的情況,如果有,就要考慮增大這個配置。
塊緩存增加的場景大多在主讀的場景。
另外,和下面說的memstore配置,加起來是不能超過100%的,默認是60%
這個配置默認是上限40%(0.4),下限35%,由參數(shù)hbase.regionserver.global.memstore.upperLimit和hbase.regionserver.global.memstore.lowerLimit控制上限和下限,
上下限這么接近,是為了避免過度的flush。
如果是讀多的場景,可以考慮同時降低上下限,給塊緩存留出更多位置。
參考http://gbif.blogspot.com/2012/07/optimizing-writes-in-hbase.html
有兩種阻塞更新的閾值,一個是hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier,默認是64M*2,達到這個閾值會阻塞客戶端請求,來等待完成flush。
還有一個是hbase.hstore.blockingStoreFiles ,默認是7,memstore flush會創(chuàng)建新的storefile,然后通過大小合并去縮減數(shù)量,默認大于3個storefile就啟動compact,一次最多compact7個文件,所以這個值默認是7.
當存儲空間足夠時,可以考慮增大這幾個配置。以應(yīng)對突發(fā)大容量寫入的場景。
hbase自帶一個評估工具,默認是用MR任務(wù)評估,可以指定--nomapred:
./bin/hbase org.apache.hadoop.hbase.PerformanceEvaluation
Yahoo提供了一個YCSB,據(jù)說比自帶的評估工具強大,未用過。
hbase自帶了一個hbck工具,可以通過幫助看用法
./bin/hbase hbck –h
hbck會掃描.META.表,收集信息。還會掃描hbase使用的HDFS中的root目錄。然后會比較收集信息來生成一致性和完整性報告。
一致性檢查以region為單位,檢查region是否同時存在于.META.表和HDFS中,并檢查是否被唯一指派給某個region server
完整性檢查以表為單位,將region與表細節(jié)信息進行對比,找到缺失的region,同時檢查region起止鍵范圍中的空洞或重疊情況
fix選線可以修復(fù)檢查出來的問題,如.META.沒有被分配,則會分配到一個新服務(wù)器,如果.META.被重復(fù)分配,會修復(fù)。如果用戶表的region沒有分配、或分配到多個region server,會重新分配。如果region當前所在server和.META.中描述不同,則會重新分配region。
轉(zhuǎn)載請注明出處:華為云博客 https://portal.hwclouds.com/blogs
hbase
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔相應(yīng)法律責任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。