版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。http://www.itdecent.cn/p/27c2137fdfee
一、通過預(yù)分區(qū)的方式建表
在建表時(shí)對HBase進(jìn)行region的預(yù)分區(qū),這樣就能避免熱點(diǎn),提高數(shù)據(jù)寫入效率。比如,rowkey的前幾位字符串都是從0001~0010的數(shù)字,這樣就可以分成10個region,使用SPLISTS,如下:
create't1','f1',{SPLITS=>['0001','0002','0003','0004','0005','0006','0007','0008','0009']}
二、列族數(shù)量不應(yīng)超過2個
一個StoreFile對應(yīng)一個ColumnFamily,多個ColumnFamily那么就有多個StoreFile。由于不同的列族會共享region,所以有可能出現(xiàn),一個列族A已經(jīng)有1000萬行,而另外一個B才100行。當(dāng)一個要求region分割的時(shí)候,會導(dǎo)致100行的列族B會同樣分布到多個region中,導(dǎo)致掃描列族B的性能低下。
三、 隆過濾器
減少特定訪問模式下的查詢時(shí)間,建議使用ROW模式。
NONE:不使用布隆過濾器
ROW:行級,行鍵使用布隆過濾器——其在額外空間開銷和提升性能之間有很好平衡
ROWCOL:行加列級,列鍵也使用布隆過濾器,不建議開啟。
BLOOMFILTER=>‘ROW’
四、BlockCache設(shè)置
BlockCache作為讀緩存,對于對性能來說至關(guān)重要,默認(rèn)情況下BlockCache和Memstore的配置相對均衡(各占40%),可以根據(jù)集群業(yè)務(wù)進(jìn)行調(diào)整,比如讀多寫少業(yè)務(wù)可以將BlockCache比例調(diào)大,反之亦然。
緩存策略:BlockCache的不同策略雖然對讀性能無太多影響,但對GC影響很大。默認(rèn)為LRUBlockCache,但由于該機(jī)制完全基于JVM Heap的緩存,有發(fā)生FGC的風(fēng)險(xiǎn),因此有了基于堆外內(nèi)存的BlockCache方案BucketCache,該方案為阿里貢獻(xiàn)的,堆外內(nèi)存的好處就是JVM幾乎不會停頓,但由于性能上來說LRUCache較強(qiáng),BucketCache屬于二級緩存的概念,實(shí)際生產(chǎn)情況下,兩者可以結(jié)合使用。
具體來說,HBase在讀取時(shí),是以Block為單位進(jìn)行cache的,而Block分為DataBlock(默認(rèn)64K,存儲KV)、BloomBlock(默認(rèn)128K,存儲BloomFilter數(shù)據(jù))、IndexBlock(默認(rèn)128K,索引數(shù)據(jù)),對于一次隨機(jī)讀,Block的訪問順序?yàn)锽loomBlock、IndexBlock、DataBlock。因此可以將IndexBlock和BloomBlock放入LRUCache張,DataBlock放入BucketCache。LRUCache使用內(nèi)存,BucketCache使用SSD或offheap。
緩存塊大?。築lockCache默認(rèn)大小64K,如果業(yè)務(wù)請求以隨機(jī)Get為主,可以考慮將其設(shè)置較小,比如32K;對于以SCAN為主的業(yè)務(wù),可以適當(dāng)加大到128K,以獲得更好的性能。
BLOCKCACHE=>’true’
BLOCKSIZE=>’65535’
五、在內(nèi)存中
基于LRUBlockCache策略,正常的數(shù)據(jù)讀取過程中,塊數(shù)據(jù)加載到緩存區(qū)中并長期駐留在內(nèi)存中。
這個參數(shù)適應(yīng)于數(shù)據(jù)量較少的列族,例如:登陸賬號和密碼的用戶表,否則建議設(shè)為false。
In Memory=’false’
六、復(fù)制
REPLICATION_SCOPE=>’0’——復(fù)制范圍,提供了跨集群的同步功能,無此需求可關(guān)閉。
七、壓縮
COMPRESSION=>’SNAPPY’
數(shù)據(jù)壓縮是HBase提供的另一個特性,HBase在寫入數(shù)據(jù)塊到HDFS之前會首先對數(shù)據(jù)塊進(jìn)行壓縮,再落盤,從而可以減少磁盤空間使用。壓縮是flush這個階段執(zhí)行的,因此對flush操作有影響,對寫性能本身并不會有太大影響。而在讀數(shù)據(jù)的時(shí)候首先從HDFS中加載出block塊之后進(jìn)行解壓縮,然后再緩存到BlockCache(內(nèi)存中的block是解壓后的),最后返回給用戶。由于讀取存在解壓縮過程,理論上讀性能會有所下降,而如果是從緩存中讀取數(shù)據(jù),因?yàn)榫彺嬷械臄?shù)據(jù)是解壓后的,那么性能不好有任何影響。大多數(shù)讀都是熱點(diǎn)讀,緩存讀占比例較大,因而壓縮讀讀性能的影響不會太大。
HBase支持大量壓縮算法,并支持列族級別上的數(shù)據(jù)壓縮。建議開啟。理論Snappy壓縮率可以達(dá)到5:1,壓縮率比較低,且編解碼速率最高,對CPU消耗也最小,建議使用。
八、數(shù)據(jù)編碼(Encode/Decode)
DataBlock Encode是HBase 0.94版本引入的特性,可以將重復(fù)的行/列族/值進(jìn)行壓縮,
減少block的空間占用,提高內(nèi)存使用率。它和Compress提高了相似的功能,但由于用戶從緩存中加載出KV時(shí)需要先解碼,不利于讀性能,因此不建議在內(nèi)存不足的情況下啟用。并且由于已開啟了SNAPPY壓縮,就無必要再開啟編碼了。
DATA_BLOCK_ENCODING=>’NONE’
九、生存期TTL
生存期(TTL)設(shè)置了一個基于時(shí)間戳的臨界值,HBase會檢查TTL值是否達(dá)到上限,在進(jìn)行Major Compaction過程中被判定為TTL超期的數(shù)據(jù)會被刪除。單位是秒。使用TTL默認(rèn)值的數(shù)據(jù)可以理解為永久保存,建議設(shè)置合適保留生存期以節(jié)約存儲。
十、使用批量put進(jìn)行寫入
HBase分別提供了單條put以及批量put的API接口,使用批量put接口可以減少客戶
端到RegionServer之間的RPC連接數(shù),提高寫入性能。另外需要注意的是,批量put請求要么全部成功返回,要么拋出異常。
table.setWriteBufferSize(6* 1024 * 1024);
通過調(diào)用HTable.setWriteBufferSize(writeBufferSize)方法可以設(shè)置HTable客戶端的寫buffer大小,比如6M,如果新設(shè)置的buffer小于當(dāng)前寫buffer中的數(shù)據(jù)時(shí),buffer將會被flush到服務(wù)端。其中,writeBufferSize的單位是byte字節(jié)數(shù),可以根據(jù)實(shí)際寫入數(shù)據(jù)量的多少來設(shè)置該值。需要注意的是,在某些情況下客戶端異常的情況下緩存數(shù)據(jù)有可能丟失。
使用方式:setAutoFlush(false)
十一、SCAN或GET
對客戶端訪問的時(shí)候?qū)Ψ祷亟Y(jié)果大小做限制
1、setCaching(100),Scan.next()的一次RPC請求fetch的記錄條數(shù),可以設(shè)置一次返回多條緩存在客戶端緩存,比如100條;
2、對列數(shù)量做限制(scan.setBatch(10)),可以控制每次獲取的最大列數(shù),進(jìn)一步從列級別控制流量,例如表有兩個列簇 cf,info,每個列簇50個列,這樣每行可能有100列了,設(shè)置為10,則每次只取10列;
3、scan.setMaxResultSize(2*1024*1024)),HBase-1.2 默認(rèn)值為 210241024,即2M。Scan.next()的一次RPC請求fetch的數(shù)據(jù)量大小,如果網(wǎng)絡(luò)帶寬足夠,每次scan數(shù)據(jù)量比較大,可以配置高一點(diǎn),但有可能導(dǎo)致scantimeout,該值需與setCaching配合使用;
4、hbase.server.scanner.max.result.size,該參數(shù)為server端的一個配置,為HBase-1.2版本以后新增,可以對返回結(jié)果大小在服務(wù)器端進(jìn)行限制,默認(rèn)值為 10010241024,即 100M。該參數(shù)表示當(dāng) Scan.next() 發(fā)起 RPC 后,服務(wù)端返回給客戶端的最大字節(jié)數(shù),防止 Server OOM。
對于離線批量讀取請求設(shè)置禁用緩存,scan.setBlockCache(false)
通常離線批量讀取數(shù)據(jù)會進(jìn)行一次性全表掃描,一方面數(shù)據(jù)量很大,另一方面請求只會執(zhí)行一次。這種場景下如果使用scan默認(rèn)設(shè)置,就會將數(shù)據(jù)從HDFS加載出來之后放到緩存??上攵?,大量數(shù)據(jù)進(jìn)入緩存必將其他實(shí)時(shí)業(yè)務(wù)熱點(diǎn)數(shù)據(jù)擠出,其他業(yè)務(wù)不得不從HDFS加載,進(jìn)而會造成明顯的讀延遲毛刺。?優(yōu)化建議:離線批量讀取請求設(shè)置禁用緩存,scan.setBlockCache(false)
十二、業(yè)務(wù)重試機(jī)制
重試機(jī)制主要考慮三個參數(shù),一是重試的最大次數(shù),hbase.client.retries.number,默認(rèn)31。
HBase有一個重試系數(shù)表,表示重試時(shí)間會隨著重試次數(shù)逐漸遞增:
public static int RETRY_BACKOFF[] = { 1, 2, 3, 5, 10, 20, 40, 100, 100, 100,100, 200, 200 }
,最大是200,那么默認(rèn)情況下最大的重試間隔休眠時(shí)間expectedSleep=hbase.client.pause*200,hbase.client.pause默認(rèn)100,那么最大重試間隔休眠為20s。假設(shè)重試次數(shù)為31次,那么重試時(shí)間為[100,200,300,500,1000,2000,4000,10000,10000,10000,10000,20000,20000,…,20000],即客戶端將在448s內(nèi)重試30次,然后放棄連接HBase。這樣的話,一個線程會存在7.5分鐘左右的重試時(shí)間,從而導(dǎo)致其他線程阻塞,因此可考慮降低著兩個參數(shù)值。
hbase.client.pause=80;hbase.client.retries.number=21。
十三、Rowkey設(shè)計(jì)
RowKey類似于RDBMS中的主鍵,設(shè)計(jì)好壞對業(yè)務(wù)影響很大,常見的方法有加鹽、反轉(zhuǎn)、哈希,這個后面單獨(dú)開一篇文章來講。