HBase最佳实践
https://help.aliyun.com/document_detail
數(shù)據(jù)壓縮與編碼
我們分為兩種情況,一種是壓縮、一種是編碼。
此為典型的儉約空間的做法,在一些場(chǎng)景下,甚至可以節(jié)約90%的空間
目前 我們建議采取 snappy 方式,編碼采取 DIFF 即可
Snappy在GZIP、LZO等眾多的壓縮格式中,壓縮率較高、編碼、解碼的速度較快,目前 平臺(tái)已經(jīng)默認(rèn)支持
read讀取優(yōu)化
其實(shí)HBase還是比較靈活的,關(guān)鍵看你是否使用得當(dāng),以下主要列舉一些讀的優(yōu)化。HBase在生產(chǎn)中往往會(huì)遇到Full GC、進(jìn)程OOM、RIT問題、讀取延遲較大等一些問題,使用更好的硬件往往可以解決一部分問題,但是還是需要使用的方式。
我們把優(yōu)化分為:
客戶端優(yōu)化、服務(wù)端優(yōu)化、平臺(tái)優(yōu)化(ApsaraDB for HBase平臺(tái)完成)
客戶端優(yōu)化
get請(qǐng)求是否可以使用批量請(qǐng)求
這樣可以成倍減小客戶端與服務(wù)端的rpc次數(shù),顯著提高吞吐量
大scan緩存是否設(shè)置合理
scan一次性需求從服務(wù)端返回大量的數(shù)據(jù),客戶端發(fā)起一次請(qǐng)求,客戶端會(huì)分多批次返回客戶端,這樣的設(shè)計(jì)是避免一次性傳輸較多的數(shù)據(jù)給服務(wù)端及客戶端有較大的壓力。目前 數(shù)據(jù)會(huì)加載到本地的緩存中,默認(rèn)100條數(shù)據(jù)大小。 一些大scan需要獲取大量的數(shù)據(jù),傳輸數(shù)百次甚至數(shù)萬的rpc請(qǐng)求。 我們建議可以 適當(dāng)放開 緩存的大小。
請(qǐng)求指定列族或者列名
HBase是列族數(shù)據(jù)庫(kù),同一個(gè)列族的數(shù)據(jù)存儲(chǔ)在一塊,不同列族是分開的,為了減小IO,建議指定列族或者列名
離線計(jì)算訪問Hbase建議禁止緩存
當(dāng)離線訪問HBase時(shí),往往就是一次性的讀取,此時(shí)讀取的數(shù)據(jù)沒有必要存放在blockcache中,建議在讀取時(shí)禁止緩存
可干預(yù)服務(wù)端優(yōu)化
請(qǐng)求是否均衡
讀取的壓力是否都在一臺(tái)或者幾臺(tái)之中,在業(yè)務(wù)高峰期間可以查看下,可以到 HBase管控平臺(tái)查看HBase的ui。如果有明顯的熱點(diǎn),一勞永逸是重新設(shè)計(jì)rowkey,短期是 把熱點(diǎn)region嘗試拆分
BlockCache是否合理
BlockCache作為讀緩存,對(duì)于讀的性能比較重要,如果讀比較多,建議內(nèi)存使用1:4的機(jī)器,比如:8cpu32g或者16pu64g的機(jī)器。當(dāng)前可以調(diào)高 BlockCache 的數(shù)值,降低 Memstore 的數(shù)值。
在ApsaraDB for HBase控制臺(tái)可以完成:hfile.block.cache.size 改為0.5 ; hbase.regionserver.global.memstore.size 改為0.3;再重啟
HFile文件數(shù)目
因?yàn)樽x取需要頻繁打開HFile,如果文件越多,IO次數(shù)就越多,讀取的延遲就越高此 需要主要定時(shí)做 major compaction,如果晚上的業(yè)務(wù)壓力不大,可以在晚上做major compaction
Compaction是否消耗較多的系統(tǒng)資源
compaction主要是將HFile的小文件合并成大文件,提高后續(xù)業(yè)務(wù)的讀性能,但是也會(huì)帶來較大的資源消耗。Minor Compaction一般情況下不會(huì)帶來大量的系統(tǒng)資源消耗,除非因?yàn)榕渲貌缓侠怼?切勿在高峰期間做 major compaction。 建議在業(yè)務(wù)低峰期做major compaction。
Bloomfilter設(shè)置是否合理
Bloomfilter主要用來在查詢時(shí),過濾HFile的,避免不需要的IO操作。Bloomfilter能提高讀取的性能,一般情況下創(chuàng)建表,都會(huì)默認(rèn)設(shè)置為:BLOOMFILTER => ‘ROW’
平臺(tái)端優(yōu)化
數(shù)據(jù)本地率是否太低?(平臺(tái)已經(jīng)優(yōu)化)
Hbase 的HFile,在本地是否有文件,如果有文件可以走Short-Circuit Local Read目前平臺(tái)在重啟、磁盤擴(kuò)容時(shí),都會(huì)自動(dòng)拉回移動(dòng)出去的region,不降低數(shù)據(jù)本地率;另外 定期做major compaction也有益于提高本地化率
Short-Circuit Local Read (已經(jīng)默認(rèn)開啟)
當(dāng)前HDFS讀取數(shù)據(jù)需要經(jīng)過DataNode,開啟Short-Circuit Local Read后,客戶端可以直接讀取本地?cái)?shù)據(jù)
Hedged Read (已經(jīng)默認(rèn)開啟)
優(yōu)先會(huì)通過Short-Circuit Local Read功能嘗試本地讀。但是在某些特殊情況下,有可能會(huì)出現(xiàn)因?yàn)榇疟P問題或者網(wǎng)絡(luò)問題引起的短時(shí)間本地讀取失敗,為了應(yīng)對(duì)這類問題,開發(fā)出了Hedged Read。該機(jī)制基本工作原理為:客戶端發(fā)起一個(gè)本地讀,一旦一段時(shí)間之后還沒有返回,客戶端將會(huì)向其他DataNode發(fā)送相同數(shù)據(jù)的請(qǐng)求。哪一個(gè)請(qǐng)求先返回,另一個(gè)就會(huì)被丟棄
關(guān)閉swap區(qū)(已經(jīng)默認(rèn)關(guān)閉)
swap是當(dāng)物理內(nèi)存不足時(shí),拿出部分的硬盤空間當(dāng)做swap使用,解決內(nèi)存不足的情況。但是會(huì)有較大的延遲的問題,所以我們HBase平臺(tái)默認(rèn)關(guān)閉。 但是關(guān)閉swap導(dǎo)致anon-rss很高,page reclaim沒辦法reclaim足夠的page,可能導(dǎo)致內(nèi)核掛住,平臺(tái)已經(jīng)采取相關(guān)隔離措施避免此情況。
write寫入優(yōu)化
HBase基于LSM模式,寫是寫HLOG及Memory的,也就是基本沒有隨機(jī)的IO,所以在寫鏈路上性能高校還比較平穩(wěn)。很多時(shí)候,寫都是用可靠性來換取性能。
客戶端優(yōu)化
批量寫
也是為了減少rpc的次數(shù)
Auto Flush
autoflush=false可以提升幾倍的寫性能,但是還是要注意,直到數(shù)據(jù)超過2M(hbase.client.write.buffer決定)或用戶執(zhí)行了hbase.flushcommits()時(shí)才向regionserver提交請(qǐng)求。需要注意并不是寫到了遠(yuǎn)端。
HTable.setWriteBufferSize(writeBufferSize) 可以設(shè)置buffer的大小
服務(wù)端優(yōu)化
WAL Flag
不寫WAL可以成倍提升性能,因?yàn)椴恍枰獙慔Log,減少3次IO,寫MemStore是內(nèi)存操作
是以數(shù)據(jù)可靠性為代價(jià)的,在數(shù)據(jù)導(dǎo)入時(shí),可以關(guān)閉WAL
增大memstore的內(nèi)存
當(dāng)前可以調(diào)高M(jìn)emstore 的數(shù)值,降低 BlockCache 的數(shù),跟讀優(yōu)化的思路正好相反
大量的HFile產(chǎn)生
如果寫很快,很容易帶來大量的HFile,因?yàn)榇藭r(shí)HFile合并的速度還沒有寫入的速度快
需要在業(yè)務(wù)低峰期做majorcompaction,充分利用系統(tǒng)資源;如果HFile降低不下來,則需要添加節(jié)點(diǎn)
讀寫分離
HBase有三個(gè)典型的API : read(get、scan)、write ,我們有時(shí)候希望這三個(gè)訪問盡可能的互相不影響,可以參考如下配置:(線上默認(rèn)沒有配置讀寫分離)
場(chǎng)景
- 寫請(qǐng)求與讀請(qǐng)求都比較高,業(yè)務(wù)往往接受:寫請(qǐng)求慢點(diǎn)可以,讀請(qǐng)求越快越好,最好有單獨(dú)的資源保障
- scan與get都比較多,業(yè)務(wù)希望scan不影響get(因?yàn)閟can比較消耗資源)
相關(guān)配置:
- hbase.ipc.server.callqueue.read.ratio
- hbase.ipc.server.callqueue.scan.ratio
具體含義:
- hbase.ipc.server.callqueue.read.ratio 設(shè)置為0.5,代表有50%的線程數(shù)處理讀請(qǐng)求
- 如果再設(shè)置hbase.ipc.server.callqueue.scan.ratio 設(shè)置為0.5,則代表在50%的讀線程之中,再有50%的線程處理scan,也就是全部線程的25%
操作步驟
- 打開HBase控制臺(tái),找到實(shí)例,點(diǎn)擊進(jìn)去,找到 - 參數(shù)設(shè)置
- 修改配置,按照業(yè)務(wù)讀寫情況
- 不重啟不會(huì)生效,請(qǐng)?jiān)跇I(yè)務(wù)低峰期重啟集群,重啟不會(huì)中斷業(yè)務(wù),可能會(huì)有一些抖動(dòng)
請(qǐng)根據(jù)實(shí)際的業(yè)務(wù)配置以上數(shù)值,默認(rèn)情況下是沒有配置的,也就是讀寫都共享。
預(yù)分區(qū)
初次接觸HBase的客戶,在創(chuàng)建HBase表的時(shí)候,不指分區(qū)的數(shù)目,另外就是rowkey設(shè)計(jì)不合理,導(dǎo)致熱點(diǎn)。
最為常見的建表語句為:
create ‘t3’,’f1’, { NUMREGIONS => 50, SPLITALGO => ‘HexStringSplit’ , COMPRESSION => ‘snappy’}
- 其中 NUMREGIONS 為 region的個(gè)數(shù),一般取10-500左右,集群規(guī)模大,可以取大一些,
- SPLITALGO 為 rowkey分割的算法:Hbase自帶了兩種pre-split的算法,分別是 HexStringSplit 和 UniformSplit,HexStringSplit 如果我們的row key是十六進(jìn)制的字符串作為前綴的,就比較適合用HexStringSplit,關(guān)于rowkey的設(shè)計(jì)可以參考:RowKey設(shè)計(jì)
- COMPRESSION壓縮算法,參考:數(shù)據(jù)壓縮與編碼
Rowkey設(shè)計(jì)
HBase的rowkey設(shè)計(jì)可以說是使用HBase最為重要的事情,直接影響到HBase的性能,常見的RowKey的設(shè)計(jì)問題及對(duì)應(yīng)訪問為:
Hotspotting
的行由行鍵按字典順序排序,這樣的設(shè)計(jì)優(yōu)化了掃描,允許存儲(chǔ)相關(guān)的行或者那些將被一起讀的鄰近的行。然而,設(shè)計(jì)不好的行鍵是導(dǎo)致 hotspotting 的常見原因。當(dāng)大量的客戶端流量( traffic )被定向在集群上的一個(gè)或幾個(gè)節(jié)點(diǎn)時(shí),就會(huì)發(fā)生 hotspotting。這些流量可能代表著讀、寫或其他操作。流量超過了承載該region的單個(gè)機(jī)器所能負(fù)荷的量,這就會(huì)導(dǎo)致性能下降并有可能造成region的不可用。在同一 RegionServer 上的其他region也可能會(huì)受到其不良影響,因?yàn)橹鳈C(jī)無法提供服務(wù)所請(qǐng)求的負(fù)載。設(shè)計(jì)使集群能被充分均勻地使用的數(shù)據(jù)訪問模式是至關(guān)重要的。
為了防止在寫操作時(shí)出現(xiàn) hotspotting ,設(shè)計(jì)行鍵時(shí)應(yīng)該使得數(shù)據(jù)盡量同時(shí)往多個(gè)region上寫,而避免只向一個(gè)region寫,除非那些行真的有必要寫在一個(gè)region里。
下面介紹了集中常用的避免 hotspotting 的技巧,它們各有優(yōu)劣:
Salting
Salting 從某種程度上看與加密無關(guān),它指的是將隨機(jī)數(shù)放在行鍵的起始處。進(jìn)一步說,salting給每一行鍵隨機(jī)指定了一個(gè)前綴來讓它與其他行鍵有著不同的排序。所有可能前綴的數(shù)量對(duì)應(yīng)于要分散數(shù)據(jù)的region的數(shù)量。如果有幾個(gè)“hot”的行鍵模式,而這些模式在其他更均勻分布的行里反復(fù)出現(xiàn),salting就能到幫助。下面的例子說明了salting能在多個(gè)RegionServer間分散負(fù)載,同時(shí)也說明了它在讀操作時(shí)候的負(fù)面影響。
假設(shè)行鍵的列表如下,表按照每個(gè)字母對(duì)應(yīng)一個(gè)region來分割。前綴‘a(chǎn)’是一個(gè)region,‘b’就是另一個(gè)region。在這張表中,所有以‘f’開頭的行都屬于同一個(gè)region。這個(gè)例子關(guān)注的行和鍵如下:
現(xiàn)在,假設(shè)想將它們分散到不同的region上,就需要用到四種不同的 salts :a,b,c,d。在這種情況下,每種字母前綴都對(duì)應(yīng)著不同的一個(gè)region。用上這些salts后,便有了下面這樣的行鍵。由于現(xiàn)在想把它們分到四個(gè)獨(dú)立的區(qū)域,理論上吞吐量會(huì)是之前寫到同一region的情況的吞吐量的四倍。
如果想新增一行,新增的一行會(huì)被隨機(jī)指定四個(gè)可能的salt值中的一個(gè),并放在某條已存在的行的旁邊。
由于前綴的指派是隨機(jī)的,因而如果想要按照字典順序找到這些行,則需要做更多的工作。從這個(gè)角度上看,salting增加了寫操作的吞吐量,卻也增大了讀操作的開銷。
Hashing
可用一個(gè)單向的 hash 散列來取代隨機(jī)指派前綴。這樣能使一個(gè)給定的行在“salted”時(shí)有相同的前綴,從某種程度上說,這在分散了RegionServer間的負(fù)載的同時(shí),也允許在讀操作時(shí)能夠預(yù)測(cè)。確定性hash( deterministic hash )能讓客戶端重建完整的行鍵,以及像正常的一樣用Get操作重新獲得想要的行。
考慮和上述salting一樣的情景,現(xiàn)在可以用單向hash來得到行鍵foo0003,并可預(yù)測(cè)得‘a(chǎn)’這個(gè)前綴。然后為了重新獲得這一行,需要先知道它的鍵。可以進(jìn)一步優(yōu)化這一方法,如使得將特定的鍵對(duì)總是在相同的region。
Reversing the Key(反轉(zhuǎn)鍵)
第三種預(yù)防hotspotting的方法是反轉(zhuǎn)一段固定長(zhǎng)度或者可數(shù)的鍵,來讓最常改變的部分(最低顯著位, the least significant digit )在第一位,這樣有效地打亂了行鍵,但是卻犧牲了行排序的屬性
單調(diào)遞增行鍵/時(shí)序數(shù)據(jù)
在一個(gè)集群中,一個(gè)導(dǎo)入數(shù)據(jù)的進(jìn)程鎖住不動(dòng),所有的client都在等待一個(gè)region(因而也就是一個(gè)單個(gè)節(jié)點(diǎn)),過了一會(huì)后,變成了下一個(gè)region… 如果使用了單調(diào)遞增或者時(shí)序的key便會(huì)造成這樣的問題。使用了順序的key會(huì)將本沒有順序的數(shù)據(jù)變得有順序,把負(fù)載壓在一臺(tái)機(jī)器上。所以要盡量避免時(shí)間戳或者序列(e.g. 1, 2, 3)這樣的行鍵。
如果需要導(dǎo)入時(shí)間順序的文件(如log)到HBase中,可以學(xué)習(xí)OpenTSDB的做法。它有一個(gè)頁面來描述它的HBase模式。OpenTSDB的Key的格式是[metric_type][event_timestamp],乍一看,這似乎違背了不能將timestamp做key的建議,但是它并沒有將timestamp作為key的一個(gè)關(guān)鍵位置,有成百上千的metric_type就足夠?qū)毫Ψ稚⒌礁鱾€(gè)region了。因此,盡管有著連續(xù)的數(shù)據(jù)輸入流,Put操作依舊能被分散在表中的各個(gè)region中
簡(jiǎn)化行和列
在HBase中,值是作為一個(gè)單元(Cell)保存在系統(tǒng)的中的,要定位一個(gè)單元,需要行,列名和時(shí)間戳。通常情況下,如果行和列的名字要是太大(甚至比value的大小還要大)的話,可能會(huì)遇到一些有趣的情況。在HBase的存儲(chǔ)文件( storefiles )中,有一個(gè)索引用來方便值的隨機(jī)訪問,但是訪問一個(gè)單元的坐標(biāo)要是太大的話,會(huì)占用很大的內(nèi)存,這個(gè)索引會(huì)被用盡。要想解決這個(gè)問題,可以設(shè)置一個(gè)更大的塊大小,也可以使用更小的行和列名 。壓縮也能得到更大指數(shù)。
大部分時(shí)候,細(xì)微的低效不會(huì)影響很大。但不幸的是,在這里卻不能忽略。無論是列族、屬性和行鍵都會(huì)在數(shù)據(jù)中重復(fù)上億次。
列族
盡量使列族名小,最好一個(gè)字符。(如:f 表示)
屬性
詳細(xì)屬性名 (如:”myVeryImportantAttribute”) 易讀,最好還是用短屬性名 (e.g., “via”) 保存到HBase.
行鍵長(zhǎng)度
讓行鍵短到可讀即可,這樣對(duì)獲取數(shù)據(jù)有幫助(e.g., Get vs. Scan)。短鍵對(duì)訪問數(shù)據(jù)無用,并不比長(zhǎng)鍵對(duì)get/scan更好。設(shè)計(jì)行鍵需要權(quán)衡
字節(jié)模式
long類型有8字節(jié)。8字節(jié)內(nèi)可以保存無符號(hào)數(shù)字到18,446,744,073,709,551,615。 如果用字符串保存——假設(shè)一個(gè)字節(jié)一個(gè)字符——需要將近3倍的字節(jié)數(shù)。
下面是示例代碼,可以自己運(yùn)行一下:
不幸的是,用二進(jìn)制表示會(huì)使數(shù)據(jù)在代碼之外難以閱讀。下例便是當(dāng)需要增加一個(gè)值時(shí)會(huì)看到的shell:
這個(gè)shell盡力在打印一個(gè)字符串,但在這種情況下,它決定只將進(jìn)制打印出來。當(dāng)在region名內(nèi)行鍵會(huì)發(fā)生相同的情況。如果知道儲(chǔ)存的是什么,那自是沒問題,但當(dāng)任意數(shù)據(jù)都可能被放到相同單元的時(shí)候,這將會(huì)變得難以閱讀。這是最需要權(quán)衡之處。
倒序時(shí)間戳
一個(gè)數(shù)據(jù)庫(kù)處理的通常問題是找到最近版本的值。采用倒序時(shí)間戳作為鍵的一部分可以對(duì)此特定情況有很大幫助。該技術(shù)包含追加( Long.MAX_VALUE - timestamp ) 到key的后面,如 [key][reverse_timestamp] 。
表內(nèi)[key]的最近的值可以用[key]進(jìn)行Scan,找到并獲取第一個(gè)記錄。由于HBase行鍵是排序的,該鍵排在任何比它老的行鍵的前面,所以是第一個(gè)。
該技術(shù)可以用于代替版本數(shù),其目的是保存所有版本到“永遠(yuǎn)”(或一段很長(zhǎng)時(shí)間) 。同時(shí),采用同樣的Scan技術(shù),可以很快獲取其他版本。
行鍵和列族
行鍵在列族范圍內(nèi)。所以同樣的行鍵可以在同一個(gè)表的每個(gè)列族中存在而不會(huì)沖突。
行鍵不可改
行鍵不能改變。唯一可以“改變”的方式是刪除然后再插入。這是一個(gè)常問問題,所以要注意開始就要讓行鍵正確(且/或在插入很多數(shù)據(jù)之前)。
行鍵和region split的關(guān)系
如果已經(jīng) pre-split (預(yù)裂)了表,接下來關(guān)鍵要了解行鍵是如何在region邊界分布的。為了說明為什么這很重要,可考慮用可顯示的16位字符作為鍵的關(guān)鍵位置(e.g., “0000000000000000” to “ffffffffffffffff”)這個(gè)例子。通過 Bytes.split來分割鍵的范圍(這是當(dāng)用 Admin.createTable(byte[] startKey, byte[] endKey, numRegions) 創(chuàng)建region時(shí)的一種拆分手段),這樣會(huì)分得10個(gè)region。
但問題在于,數(shù)據(jù)將會(huì)堆放在前兩個(gè)region以及最后一個(gè)region,這樣就會(huì)導(dǎo)致某幾個(gè)region由于數(shù)據(jù)分布不均勻而特別忙。為了理解其中緣由,需要考慮ASCII Table的結(jié)構(gòu)。根據(jù)ASCII表,“0”是第48號(hào),“f”是102號(hào);但58到96號(hào)是個(gè)巨大的間隙,考慮到在這里僅[0-9]和[a-f]這些值是有意義的,因而這個(gè)區(qū)間里的值不會(huì)出現(xiàn)在鍵空間( keyspace ),進(jìn)而中間區(qū)域的region將永遠(yuǎn)不會(huì)用到。為了pre-split這個(gè)例子中的鍵空間,需要自定義拆分。
教程1:預(yù)裂表( pre-splitting tables ) 是個(gè)很好的實(shí)踐,但pre-split時(shí)要注意使得所有的region都能在鍵空間中找到對(duì)應(yīng)。盡管例子中解決的問題是關(guān)于16位鍵的鍵空間,但其他任何空間也是同樣的道理。
教程2:16位鍵(通常用到可顯示的數(shù)據(jù)中)盡管通常不可取,但只要所有的region都能在鍵空間找到對(duì)應(yīng),它依舊能和預(yù)裂表配合使用。
一下case說明了如何16位鍵預(yù)分區(qū)
schema設(shè)計(jì)原則
Schema 創(chuàng)建
可以使用HBase Shell或者java API的HBaseAdmin來創(chuàng)建和編輯HBase的Schema
當(dāng)修改列族時(shí),建議先將這張表下線(disable):
更新
當(dāng)表或者列族改變時(shí)(包括:編碼方式、壓力格式、block大小等等),都將會(huì)在下次marjor compaction時(shí)或者StoreFile重寫時(shí)生效
表模式設(shè)計(jì)經(jīng)驗(yàn)
- region規(guī)模大小再10到50g之間;
- 單個(gè)cell不超過10mMB,如果超過10MB,請(qǐng)使用mob(目前 ApsaraDB for HBase不支持,2.0會(huì)支持),再大可以考慮直接存在OSS中
- 一個(gè)典型的表中含有1-3個(gè)列族,hbase表不應(yīng)該設(shè)計(jì)成類似RDBMS的表
- 一個(gè)表大約 50到100個(gè) region,1或者2個(gè)列族。記住:每個(gè)列族內(nèi)是連續(xù)的,不同列族之間是分割的
- 盡量讓你的列族名短,因?yàn)榇鎯?chǔ)時(shí)每個(gè)value都包含列族名(忽略前綴編碼, prefix encoding )
- 如果在基于時(shí)間的機(jī)器上存儲(chǔ)數(shù)據(jù)這和日志信息,row key是由設(shè)備ID加上時(shí)間得到的,那最后得到這樣的模式:除了某個(gè)特定的時(shí)間段,舊的數(shù)據(jù)region沒有額外的寫。這樣的情況下,得到的是少量的活躍region和大量沒有新寫入的舊region。這時(shí)由于資源消耗僅僅來自活躍的region,大量的Region能被接受
列族的數(shù)量
現(xiàn)在HBase并不能很好的處理兩個(gè)或者三個(gè)以上的列族,所以盡量讓列族數(shù)量少一些。
目前, flush 和 compaction 操作是針對(duì)一個(gè)region。所以當(dāng)一個(gè)列族操作大量數(shù)據(jù)的時(shí)候會(huì)引發(fā)一個(gè)flush。那些鄰近的列族也有進(jìn)行flush操作,盡管它們沒有操作多少數(shù)據(jù)。
compaction操作現(xiàn)在是根據(jù)一個(gè)列族下的全部文件的數(shù)量觸發(fā)的,而不是根據(jù)文件大小觸發(fā)的。
當(dāng)很多的列族在flush和compaction時(shí),會(huì)造成很多沒用的I/O負(fù)載(要想解決這個(gè)問題,需要將flush和compaction操作只針對(duì)一個(gè)列族) 。
盡量在模式中只針對(duì)一個(gè)列族操作。將使用率相近的列歸為一列族,這樣每次訪問時(shí)就只用訪問一個(gè)列族,提高效率。
列族的基數(shù)
如果一個(gè)表存在多個(gè)列族,要注意列族之間基數(shù)(如行數(shù))相差不要太大。 例如列族A有100萬行,列族B有10億行,按照行鍵切分后,列族A可能被分散到很多很多region(及RegionServer),這導(dǎo)致掃描列族A十分低效。
版本的數(shù)量
行的版本的數(shù)量是HColumnDescriptor設(shè)置的,每個(gè)列族可以單獨(dú)設(shè)置,默認(rèn)是3。這個(gè)設(shè)置是很重要的,因?yàn)镠Base是不會(huì)去覆蓋一個(gè)值的,它只會(huì)在后面在追加寫,用時(shí)間戳來區(qū)分、過早的版本會(huì)在執(zhí)行major compaction時(shí)刪除,這些在HBase數(shù)據(jù)模型有描述。這個(gè)版本的值可以根據(jù)具體的應(yīng)用增加減少。
不推薦將版本最大值設(shè)到一個(gè)很高的水平 (如, 成百或更多),除非老數(shù)據(jù)對(duì)你很重要。因?yàn)檫@會(huì)導(dǎo)致存儲(chǔ)文件變得極大。
最小版本數(shù)
和行的最大版本數(shù)一樣,最小版本數(shù)也是通過HColumnDescriptor 在每個(gè)列族中設(shè)置的。最小版本數(shù)缺省值是0,表示該特性禁用。 最小版本數(shù)參數(shù)和存活時(shí)間一起使用,允許配置如“保存最后T秒有價(jià)值數(shù)據(jù),最多N個(gè)版本,但最少約M個(gè)版本”(M是最小版本數(shù),M<N)。 該參數(shù)僅在存活時(shí)間對(duì)列族啟用,且必須小于行版本數(shù)。
支持?jǐn)?shù)據(jù)類型
HBase通過Put和Result支持 bytes-in/bytes-out 接口,所以任何可被轉(zhuǎn)為字節(jié)數(shù)組的東西可以作為值存入。輸入可以是字符串、數(shù)字、復(fù)雜對(duì)象、甚至圖像,它們能轉(zhuǎn)為字節(jié)。
存在值的實(shí)際長(zhǎng)度限制 (如:保存10-50MB對(duì)象到HBase可能對(duì)查詢來說太長(zhǎng)); 搜索郵件列表獲取本話題的對(duì)話。HBase的所有行都遵循HBase數(shù)據(jù)模型包括版本化。設(shè)計(jì)時(shí)需考慮到這些,以及列族的塊大小。
存活時(shí)間
列族可以設(shè)置TTL秒數(shù),HBase在超時(shí)后將自動(dòng)刪除數(shù)據(jù),HBase里面TTL時(shí)間時(shí)區(qū)是UTC
存儲(chǔ)文件僅包含有過期的行(expired rows),它們可通過minor compaction刪除。將 hbase.store.delete.expired.storefile設(shè)置為false,可禁用此功能;將最小版本數(shù)設(shè)置成非0值也可達(dá)到同樣的效果。
HBase的最新版本還支持將設(shè)定的時(shí)間存放在每個(gè)結(jié)構(gòu)單元。TTL單元通過Mutation#setTTL作為更變請(qǐng)求(Appends, Increments, Puts, etc.)的一個(gè)屬性提交,如果TTL的屬性被設(shè)定了,它將會(huì)應(yīng)用到由于該更變操作更新的所有單元上。cell TTL handling和ColumnFamily TTLs間有兩個(gè)顯著的差別:
1.Cell TTLs的數(shù)量級(jí)是毫秒而不是秒;
2.一個(gè)cell TTL不能超出ColumnFamily TTLs設(shè)置的有效時(shí)間。
?
轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/9253631.html
總結(jié)
- 上一篇: 携程开源Redis多数据中心解决方案-X
- 下一篇: Hbase Replication 介绍