日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HBase最佳实践

發(fā)布時間:2025/4/5 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HBase最佳实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

https://help.aliyun.com/document_detail

數(shù)據(jù)壓縮與編碼

我們分為兩種情況,一種是壓縮、一種是編碼。

此為典型的儉約空間的做法,在一些場景下,甚至可以節(jié)約90%的空間

目前 我們建議采取 snappy 方式,編碼采取 DIFF 即可

Snappy在GZIP、LZO等眾多的壓縮格式中,壓縮率較高、編碼、解碼的速度較快,目前 平臺已經(jīng)默認支持

  • 修改壓縮編碼的步驟:
  • 1、修改表的屬性,此為壓縮編碼
  • alter?'test',?NAME?=>?'f',?COMPRESSION?=>?'snappy',?DATA_BLOCK_ENCODING?=>'DIFF'
  • 2、壓縮編碼并不會立即生效,需要major_compact,此會耗時較長,注意在業(yè)務(wù)低峰期進行
  • major_compact?'test'
  • read讀取優(yōu)化

    其實HBase還是比較靈活的,關(guān)鍵看你是否使用得當,以下主要列舉一些讀的優(yōu)化。HBase在生產(chǎn)中往往會遇到Full GC、進程OOM、RIT問題、讀取延遲較大等一些問題,使用更好的硬件往往可以解決一部分問題,但是還是需要使用的方式。

    我們把優(yōu)化分為:

    客戶端優(yōu)化、服務(wù)端優(yōu)化、平臺優(yōu)化(ApsaraDB for HBase平臺完成)

    客戶端優(yōu)化

    get請求是否可以使用批量請求

    這樣可以成倍減小客戶端與服務(wù)端的rpc次數(shù),顯著提高吞吐量

  • Result[] re= table.get(List<Get> gets)
  • 大scan緩存是否設(shè)置合理

    scan一次性需求從服務(wù)端返回大量的數(shù)據(jù),客戶端發(fā)起一次請求,客戶端會分多批次返回客戶端,這樣的設(shè)計是避免一次性傳輸較多的數(shù)據(jù)給服務(wù)端及客戶端有較大的壓力。目前 數(shù)據(jù)會加載到本地的緩存中,默認100條數(shù)據(jù)大小。 一些大scan需要獲取大量的數(shù)據(jù),傳輸數(shù)百次甚至數(shù)萬的rpc請求。 我們建議可以 適當放開 緩存的大小。

  • scan.setCaching(int caching) //大scan可以設(shè)置為1000
  • 請求指定列族或者列名

    HBase是列族數(shù)據(jù)庫,同一個列族的數(shù)據(jù)存儲在一塊,不同列族是分開的,為了減小IO,建議指定列族或者列名

    離線計算訪問Hbase建議禁止緩存

    當離線訪問HBase時,往往就是一次性的讀取,此時讀取的數(shù)據(jù)沒有必要存放在blockcache中,建議在讀取時禁止緩存

  • scan.setBlockCache(false)
  • 可干預(yù)服務(wù)端優(yōu)化

    請求是否均衡

    讀取的壓力是否都在一臺或者幾臺之中,在業(yè)務(wù)高峰期間可以查看下,可以到 HBase管控平臺查看HBase的ui。如果有明顯的熱點,一勞永逸是重新設(shè)計rowkey,短期是 把熱點region嘗試拆分

    BlockCache是否合理

    BlockCache作為讀緩存,對于讀的性能比較重要,如果讀比較多,建議內(nèi)存使用1:4的機器,比如:8cpu32g或者16pu64g的機器。當前可以調(diào)高 BlockCache 的數(shù)值,降低 Memstore 的數(shù)值。

    在ApsaraDB for HBase控制臺可以完成:hfile.block.cache.size 改為0.5 ; hbase.regionserver.global.memstore.size 改為0.3;再重啟

    HFile文件數(shù)目

    因為讀取需要頻繁打開HFile,如果文件越多,IO次數(shù)就越多,讀取的延遲就越高此 需要主要定時做 major compaction,如果晚上的業(yè)務(wù)壓力不大,可以在晚上做major compaction

    Compaction是否消耗較多的系統(tǒng)資源

    compaction主要是將HFile的小文件合并成大文件,提高后續(xù)業(yè)務(wù)的讀性能,但是也會帶來較大的資源消耗。Minor Compaction一般情況下不會帶來大量的系統(tǒng)資源消耗,除非因為配置不合理。 切勿在高峰期間做 major compaction。 建議在業(yè)務(wù)低峰期做major compaction。

    Bloomfilter設(shè)置是否合理

    Bloomfilter主要用來在查詢時,過濾HFile的,避免不需要的IO操作。Bloomfilter能提高讀取的性能,一般情況下創(chuàng)建表,都會默認設(shè)置為:BLOOMFILTER => ‘ROW’

    平臺端優(yōu)化

    數(shù)據(jù)本地率是否太低?(平臺已經(jīng)優(yōu)化)

    Hbase 的HFile,在本地是否有文件,如果有文件可以走Short-Circuit Local Read目前平臺在重啟、磁盤擴容時,都會自動拉回移動出去的region,不降低數(shù)據(jù)本地率;另外 定期做major compaction也有益于提高本地化率

    Short-Circuit Local Read (已經(jīng)默認開啟)

    當前HDFS讀取數(shù)據(jù)需要經(jīng)過DataNode,開啟Short-Circuit Local Read后,客戶端可以直接讀取本地數(shù)據(jù)

    Hedged Read (已經(jīng)默認開啟)

    優(yōu)先會通過Short-Circuit Local Read功能嘗試本地讀。但是在某些特殊情況下,有可能會出現(xiàn)因為磁盤問題或者網(wǎng)絡(luò)問題引起的短時間本地讀取失敗,為了應(yīng)對這類問題,開發(fā)出了Hedged Read。該機制基本工作原理為:客戶端發(fā)起一個本地讀,一旦一段時間之后還沒有返回,客戶端將會向其他DataNode發(fā)送相同數(shù)據(jù)的請求。哪一個請求先返回,另一個就會被丟棄

    關(guān)閉swap區(qū)(已經(jīng)默認關(guān)閉)

    swap是當物理內(nèi)存不足時,拿出部分的硬盤空間當做swap使用,解決內(nèi)存不足的情況。但是會有較大的延遲的問題,所以我們HBase平臺默認關(guān)閉。 但是關(guān)閉swap導(dǎo)致anon-rss很高,page reclaim沒辦法reclaim足夠的page,可能導(dǎo)致內(nèi)核掛住,平臺已經(jīng)采取相關(guān)隔離措施避免此情況。

    write寫入優(yōu)化

    HBase基于LSM模式,寫是寫HLOG及Memory的,也就是基本沒有隨機的IO,所以在寫鏈路上性能高校還比較平穩(wěn)。很多時候,寫都是用可靠性來換取性能。

    客戶端優(yōu)化

    批量寫

    也是為了減少rpc的次數(shù)

  • HTable.put(List<Put>)
  • Auto Flush

    autoflush=false可以提升幾倍的寫性能,但是還是要注意,直到數(shù)據(jù)超過2M(hbase.client.write.buffer決定)或用戶執(zhí)行了hbase.flushcommits()時才向regionserver提交請求。需要注意并不是寫到了遠端。

    HTable.setWriteBufferSize(writeBufferSize) 可以設(shè)置buffer的大小

    服務(wù)端優(yōu)化

    WAL Flag

    不寫WAL可以成倍提升性能,因為不需要寫HLog,減少3次IO,寫MemStore是內(nèi)存操作

    是以數(shù)據(jù)可靠性為代價的,在數(shù)據(jù)導(dǎo)入時,可以關(guān)閉WAL

    增大memstore的內(nèi)存

    當前可以調(diào)高Memstore 的數(shù)值,降低 BlockCache 的數(shù),跟讀優(yōu)化的思路正好相反

    大量的HFile產(chǎn)生

    如果寫很快,很容易帶來大量的HFile,因為此時HFile合并的速度還沒有寫入的速度快

    需要在業(yè)務(wù)低峰期做majorcompaction,充分利用系統(tǒng)資源;如果HFile降低不下來,則需要添加節(jié)點

    讀寫分離

    HBase有三個典型的API : read(get、scan)、write ,我們有時候希望這三個訪問盡可能的互相不影響,可以參考如下配置:(線上默認沒有配置讀寫分離)

    場景
    • 寫請求與讀請求都比較高,業(yè)務(wù)往往接受:寫請求慢點可以,讀請求越快越好,最好有單獨的資源保障
    • scan與get都比較多,業(yè)務(wù)希望scan不影響get(因為scan比較消耗資源)
    相關(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ù)處理讀請求
    • 如果再設(shè)置hbase.ipc.server.callqueue.scan.ratio 設(shè)置為0.5,則代表在50%的讀線程之中,再有50%的線程處理scan,也就是全部線程的25%
    操作步驟
    • 打開HBase控制臺,找到實例,點擊進去,找到 - 參數(shù)設(shè)置
    • 修改配置,按照業(yè)務(wù)讀寫情況
    • 不重啟不會生效,請在業(yè)務(wù)低峰期重啟集群,重啟不會中斷業(yè)務(wù),可能會有一些抖動

    請根據(jù)實際的業(yè)務(wù)配置以上數(shù)值,默認情況下是沒有配置的,也就是讀寫都共享。

    預(yù)分區(qū)

    初次接觸HBase的客戶,在創(chuàng)建HBase表的時候,不指分區(qū)的數(shù)目,另外就是rowkey設(shè)計不合理,導(dǎo)致熱點。

    最為常見的建表語句為:

    create ‘t3’,’f1’, { NUMREGIONS => 50, SPLITALGO => ‘HexStringSplit’ , COMPRESSION => ‘snappy’}

    • 其中 NUMREGIONS 為 region的個數(shù),一般取10-500左右,集群規(guī)模大,可以取大一些,
    • SPLITALGO 為 rowkey分割的算法:Hbase自帶了兩種pre-split的算法,分別是 HexStringSplit 和 UniformSplit,HexStringSplit 如果我們的row key是十六進制的字符串作為前綴的,就比較適合用HexStringSplit,關(guān)于rowkey的設(shè)計可以參考:RowKey設(shè)計
    • COMPRESSION壓縮算法,參考:數(shù)據(jù)壓縮與編碼

    Rowkey設(shè)計

    HBase的rowkey設(shè)計可以說是使用HBase最為重要的事情,直接影響到HBase的性能,常見的RowKey的設(shè)計問題及對應(yīng)訪問為:

    Hotspotting

    的行由行鍵按字典順序排序,這樣的設(shè)計優(yōu)化了掃描,允許存儲相關(guān)的行或者那些將被一起讀的鄰近的行。然而,設(shè)計不好的行鍵是導(dǎo)致 hotspotting 的常見原因。當大量的客戶端流量( traffic )被定向在集群上的一個或幾個節(jié)點時,就會發(fā)生 hotspotting。這些流量可能代表著讀、寫或其他操作。流量超過了承載該region的單個機器所能負荷的量,這就會導(dǎo)致性能下降并有可能造成region的不可用。在同一 RegionServer 上的其他region也可能會受到其不良影響,因為主機無法提供服務(wù)所請求的負載。設(shè)計使集群能被充分均勻地使用的數(shù)據(jù)訪問模式是至關(guān)重要的。

    為了防止在寫操作時出現(xiàn) hotspotting ,設(shè)計行鍵時應(yīng)該使得數(shù)據(jù)盡量同時往多個region上寫,而避免只向一個region寫,除非那些行真的有必要寫在一個region里。

    下面介紹了集中常用的避免 hotspotting 的技巧,它們各有優(yōu)劣:

    Salting

    Salting 從某種程度上看與加密無關(guān),它指的是將隨機數(shù)放在行鍵的起始處。進一步說,salting給每一行鍵隨機指定了一個前綴來讓它與其他行鍵有著不同的排序。所有可能前綴的數(shù)量對應(yīng)于要分散數(shù)據(jù)的region的數(shù)量。如果有幾個“hot”的行鍵模式,而這些模式在其他更均勻分布的行里反復(fù)出現(xiàn),salting就能到幫助。下面的例子說明了salting能在多個RegionServer間分散負載,同時也說明了它在讀操作時候的負面影響。

    假設(shè)行鍵的列表如下,表按照每個字母對應(yīng)一個region來分割。前綴‘a(chǎn)’是一個region,‘b’就是另一個region。在這張表中,所有以‘f’開頭的行都屬于同一個region。這個例子關(guān)注的行和鍵如下:

  • foo0001
  • foo0002
  • foo0003
  • foo0004
  • 現(xiàn)在,假設(shè)想將它們分散到不同的region上,就需要用到四種不同的 salts :a,b,c,d。在這種情況下,每種字母前綴都對應(yīng)著不同的一個region。用上這些salts后,便有了下面這樣的行鍵。由于現(xiàn)在想把它們分到四個獨立的區(qū)域,理論上吞吐量會是之前寫到同一region的情況的吞吐量的四倍。

  • a-foo0003
  • b-foo0001
  • c-foo0004
  • d-foo0002
  • 如果想新增一行,新增的一行會被隨機指定四個可能的salt值中的一個,并放在某條已存在的行的旁邊。

  • a-foo0003
  • b-foo0001
  • c-foo0003
  • c-foo0004
  • d-foo0002
  • 由于前綴的指派是隨機的,因而如果想要按照字典順序找到這些行,則需要做更多的工作。從這個角度上看,salting增加了寫操作的吞吐量,卻也增大了讀操作的開銷。

    Hashing

    可用一個單向的 hash 散列來取代隨機指派前綴。這樣能使一個給定的行在“salted”時有相同的前綴,從某種程度上說,這在分散了RegionServer間的負載的同時,也允許在讀操作時能夠預(yù)測。確定性hash( deterministic hash )能讓客戶端重建完整的行鍵,以及像正常的一樣用Get操作重新獲得想要的行。

    考慮和上述salting一樣的情景,現(xiàn)在可以用單向hash來得到行鍵foo0003,并可預(yù)測得‘a(chǎn)’這個前綴。然后為了重新獲得這一行,需要先知道它的鍵。可以進一步優(yōu)化這一方法,如使得將特定的鍵對總是在相同的region。

    Reversing the Key(反轉(zhuǎn)鍵)

    第三種預(yù)防hotspotting的方法是反轉(zhuǎn)一段固定長度或者可數(shù)的鍵,來讓最常改變的部分(最低顯著位, the least significant digit )在第一位,這樣有效地打亂了行鍵,但是卻犧牲了行排序的屬性

    單調(diào)遞增行鍵/時序數(shù)據(jù)

    在一個集群中,一個導(dǎo)入數(shù)據(jù)的進程鎖住不動,所有的client都在等待一個region(因而也就是一個單個節(jié)點),過了一會后,變成了下一個region… 如果使用了單調(diào)遞增或者時序的key便會造成這樣的問題。使用了順序的key會將本沒有順序的數(shù)據(jù)變得有順序,把負載壓在一臺機器上。所以要盡量避免時間戳或者序列(e.g. 1, 2, 3)這樣的行鍵。

    如果需要導(dǎo)入時間順序的文件(如log)到HBase中,可以學(xué)習(xí)OpenTSDB的做法。它有一個頁面來描述它的HBase模式。OpenTSDB的Key的格式是[metric_type][event_timestamp],乍一看,這似乎違背了不能將timestamp做key的建議,但是它并沒有將timestamp作為key的一個關(guān)鍵位置,有成百上千的metric_type就足夠?qū)毫Ψ稚⒌礁鱾€region了。因此,盡管有著連續(xù)的數(shù)據(jù)輸入流,Put操作依舊能被分散在表中的各個region中

    簡化行和列

    在HBase中,值是作為一個單元(Cell)保存在系統(tǒng)的中的,要定位一個單元,需要行,列名和時間戳。通常情況下,如果行和列的名字要是太大(甚至比value的大小還要大)的話,可能會遇到一些有趣的情況。在HBase的存儲文件( storefiles )中,有一個索引用來方便值的隨機訪問,但是訪問一個單元的坐標要是太大的話,會占用很大的內(nèi)存,這個索引會被用盡。要想解決這個問題,可以設(shè)置一個更大的塊大小,也可以使用更小的行和列名 。壓縮也能得到更大指數(shù)。

    大部分時候,細微的低效不會影響很大。但不幸的是,在這里卻不能忽略。無論是列族、屬性和行鍵都會在數(shù)據(jù)中重復(fù)上億次。

    列族

    盡量使列族名小,最好一個字符。(如:f 表示)

    屬性

    詳細屬性名 (如:”myVeryImportantAttribute”) 易讀,最好還是用短屬性名 (e.g., “via”) 保存到HBase.

    行鍵長度

    讓行鍵短到可讀即可,這樣對獲取數(shù)據(jù)有幫助(e.g., Get vs. Scan)。短鍵對訪問數(shù)據(jù)無用,并不比長鍵對get/scan更好。設(shè)計行鍵需要權(quán)衡

    字節(jié)模式

    long類型有8字節(jié)。8字節(jié)內(nèi)可以保存無符號數(shù)字到18,446,744,073,709,551,615。 如果用字符串保存——假設(shè)一個字節(jié)一個字符——需要將近3倍的字節(jié)數(shù)。

    下面是示例代碼,可以自己運行一下:

  • // long
  • //
  • long l = 1234567890L;
  • byte[] lb = Bytes.toBytes(l);
  • System.out.println("long bytes length: " + lb.length); // returns 8
  • String s = String.valueOf(l);
  • byte[] sb = Bytes.toBytes(s);
  • System.out.println("long as string length: " + sb.length); // returns 10
  • // hash
  • //
  • MessageDigest md = MessageDigest.getInstance("MD5");
  • byte[] digest = md.digest(Bytes.toBytes(s));
  • System.out.println("md5 digest bytes length: " + digest.length); // returns 16
  • String sDigest = new String(digest);
  • byte[] sbDigest = Bytes.toBytes(sDigest);
  • System.out.println("md5 digest as string length: " + sbDigest.length); // returns 26
  • 不幸的是,用二進制表示會使數(shù)據(jù)在代碼之外難以閱讀。下例便是當需要增加一個值時會看到的shell:

  • hbase(main):001:0> incr 't', 'r', 'f:q', 1
  • COUNTER VALUE = 1
  • hbase(main):002:0> get 't', 'r'
  • COLUMN CELL
  • f:q timestamp=1369163040570, value=\x00\x00\x00\x00\x00\x00\x00\x01
  • 1 row(s) in 0.0310 seconds
  • 這個shell盡力在打印一個字符串,但在這種情況下,它決定只將進制打印出來。當在region名內(nèi)行鍵會發(fā)生相同的情況。如果知道儲存的是什么,那自是沒問題,但當任意數(shù)據(jù)都可能被放到相同單元的時候,這將會變得難以閱讀。這是最需要權(quán)衡之處。

    倒序時間戳

    一個數(shù)據(jù)庫處理的通常問題是找到最近版本的值。采用倒序時間戳作為鍵的一部分可以對此特定情況有很大幫助。該技術(shù)包含追加( Long.MAX_VALUE - timestamp ) 到key的后面,如 [key][reverse_timestamp] 。

    表內(nèi)[key]的最近的值可以用[key]進行Scan,找到并獲取第一個記錄。由于HBase行鍵是排序的,該鍵排在任何比它老的行鍵的前面,所以是第一個。

    該技術(shù)可以用于代替版本數(shù),其目的是保存所有版本到“永遠”(或一段很長時間) 。同時,采用同樣的Scan技術(shù),可以很快獲取其他版本。

    行鍵和列族

    行鍵在列族范圍內(nèi)。所以同樣的行鍵可以在同一個表的每個列族中存在而不會沖突。

    行鍵不可改

    行鍵不能改變。唯一可以“改變”的方式是刪除然后再插入。這是一個常問問題,所以要注意開始就要讓行鍵正確(且/或在插入很多數(shù)據(jù)之前)。

    行鍵和region split的關(guān)系

    如果已經(jīng) pre-split (預(yù)裂)了表,接下來關(guān)鍵要了解行鍵是如何在region邊界分布的。為了說明為什么這很重要,可考慮用可顯示的16位字符作為鍵的關(guān)鍵位置(e.g., “0000000000000000” to “ffffffffffffffff”)這個例子。通過 Bytes.split來分割鍵的范圍(這是當用 Admin.createTable(byte[] startKey, byte[] endKey, numRegions) 創(chuàng)建region時的一種拆分手段),這樣會分得10個region。

  • 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 // 0
  • 54 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 -10 // 6
  • 61 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -67 -68 // =
  • 68 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -124 -126 // D
  • 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 72 // K
  • 82 18 18 18 18 18 18 18 18 18 18 18 18 18 18 14 // R
  • 88 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -40 -44 // X
  • 95 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -97 -102 // _
  • 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 102 // f
  • 但問題在于,數(shù)據(jù)將會堆放在前兩個region以及最后一個region,這樣就會導(dǎo)致某幾個region由于數(shù)據(jù)分布不均勻而特別忙。為了理解其中緣由,需要考慮ASCII Table的結(jié)構(gòu)。根據(jù)ASCII表,“0”是第48號,“f”是102號;但58到96號是個巨大的間隙,考慮到在這里僅[0-9]和[a-f]這些值是有意義的,因而這個區(qū)間里的值不會出現(xiàn)在鍵空間( keyspace ),進而中間區(qū)域的region將永遠不會用到。為了pre-split這個例子中的鍵空間,需要自定義拆分。

    教程1:預(yù)裂表( pre-splitting tables ) 是個很好的實踐,但pre-split時要注意使得所有的region都能在鍵空間中找到對應(yīng)。盡管例子中解決的問題是關(guān)于16位鍵的鍵空間,但其他任何空間也是同樣的道理。

    教程2:16位鍵(通常用到可顯示的數(shù)據(jù)中)盡管通常不可取,但只要所有的region都能在鍵空間找到對應(yīng),它依舊能和預(yù)裂表配合使用。

    一下case說明了如何16位鍵預(yù)分區(qū)

  • public static boolean createTable(Admin admin, HTableDescriptor table, byte[][] splits)
  • throws IOException {
  • try {
  • admin.createTable( table, splits );
  • return true;
  • } catch (TableExistsException e) {
  • logger.info("table " + table.getNameAsString() + " already exists");
  • // the table already exists...
  • return false;
  • }
  • }
  • public static byte[][] getHexSplits(String startKey, String endKey, int numRegions) {
  • byte[][] splits = new byte[numRegions-1][];
  • BigInteger lowestKey = new BigInteger(startKey, 16);
  • BigInteger highestKey = new BigInteger(endKey, 16);
  • BigInteger range = highestKey.subtract(lowestKey);
  • BigInteger regionIncrement = range.divide(BigInteger.valueOf(numRegions));
  • lowestKey = lowestKey.add(regionIncrement);
  • for(int i=0; i < numRegions-1;i++) {
  • BigInteger key = lowestKey.add(regionIncrement.multiply(BigInteger.valueOf(i)));
  • byte[] b = String.format("%016x", key).getBytes();
  • splits[i] = b;
  • }
  • return splits;
  • }
  • schema設(shè)計原則

    Schema 創(chuàng)建

    可以使用HBase Shell或者java API的HBaseAdmin來創(chuàng)建和編輯HBase的Schema

    當修改列族時,建議先將這張表下線(disable):

  • Configuration config = HBaseConfiguration.create();
  • HBaseAdmin admin = new HBaseAdmin(config);
  • String table = "Test";
  • admin.disableTable(table); // 將表下線
  • HColumnDescriptor f1 = ...;
  • admin.addColumn(table, f1); // 增加新的列族
  • HColumnDescriptor f2 = ...;
  • admin.modifyColumn(table, f2); // 修改列族
  • HColumnDescriptor f3 = ...;
  • admin.modifyColumn(table, f3); // 修改列族
  • admin.enableTable(table);
  • 更新

    當表或者列族改變時(包括:編碼方式、壓力格式、block大小等等),都將會在下次marjor compaction時或者StoreFile重寫時生效

    表模式設(shè)計經(jīng)驗

    • region規(guī)模大小再10到50g之間;
    • 單個cell不超過10mMB,如果超過10MB,請使用mob(目前 ApsaraDB for HBase不支持,2.0會支持),再大可以考慮直接存在OSS中
    • 一個典型的表中含有1-3個列族,hbase表不應(yīng)該設(shè)計成類似RDBMS的表
    • 一個表大約 50到100個 region,1或者2個列族。記住:每個列族內(nèi)是連續(xù)的,不同列族之間是分割的
    • 盡量讓你的列族名短,因為存儲時每個value都包含列族名(忽略前綴編碼, prefix encoding )
    • 如果在基于時間的機器上存儲數(shù)據(jù)這和日志信息,row key是由設(shè)備ID加上時間得到的,那最后得到這樣的模式:除了某個特定的時間段,舊的數(shù)據(jù)region沒有額外的寫。這樣的情況下,得到的是少量的活躍region和大量沒有新寫入的舊region。這時由于資源消耗僅僅來自活躍的region,大量的Region能被接受

    列族的數(shù)量

    現(xiàn)在HBase并不能很好的處理兩個或者三個以上的列族,所以盡量讓列族數(shù)量少一些。

    目前, flush 和 compaction 操作是針對一個region。所以當一個列族操作大量數(shù)據(jù)的時候會引發(fā)一個flush。那些鄰近的列族也有進行flush操作,盡管它們沒有操作多少數(shù)據(jù)。

    compaction操作現(xiàn)在是根據(jù)一個列族下的全部文件的數(shù)量觸發(fā)的,而不是根據(jù)文件大小觸發(fā)的。

    當很多的列族在flush和compaction時,會造成很多沒用的I/O負載(要想解決這個問題,需要將flush和compaction操作只針對一個列族) 。

    盡量在模式中只針對一個列族操作。將使用率相近的列歸為一列族,這樣每次訪問時就只用訪問一個列族,提高效率。

    列族的基數(shù)

    如果一個表存在多個列族,要注意列族之間基數(shù)(如行數(shù))相差不要太大。 例如列族A有100萬行,列族B有10億行,按照行鍵切分后,列族A可能被分散到很多很多region(及RegionServer),這導(dǎo)致掃描列族A十分低效。

    版本的數(shù)量

    行的版本的數(shù)量是HColumnDescriptor設(shè)置的,每個列族可以單獨設(shè)置,默認是3。這個設(shè)置是很重要的,因為HBase是不會去覆蓋一個值的,它只會在后面在追加寫,用時間戳來區(qū)分、過早的版本會在執(zhí)行major compaction時刪除,這些在HBase數(shù)據(jù)模型有描述。這個版本的值可以根據(jù)具體的應(yīng)用增加減少。

    不推薦將版本最大值設(shè)到一個很高的水平 (如, 成百或更多),除非老數(shù)據(jù)對你很重要。因為這會導(dǎo)致存儲文件變得極大。

    最小版本數(shù)

    和行的最大版本數(shù)一樣,最小版本數(shù)也是通過HColumnDescriptor 在每個列族中設(shè)置的。最小版本數(shù)缺省值是0,表示該特性禁用。 最小版本數(shù)參數(shù)和存活時間一起使用,允許配置如“保存最后T秒有價值數(shù)據(jù),最多N個版本,但最少約M個版本”(M是最小版本數(shù),M<N)。 該參數(shù)僅在存活時間對列族啟用,且必須小于行版本數(shù)。

    支持數(shù)據(jù)類型

    HBase通過Put和Result支持 bytes-in/bytes-out 接口,所以任何可被轉(zhuǎn)為字節(jié)數(shù)組的東西可以作為值存入。輸入可以是字符串、數(shù)字、復(fù)雜對象、甚至圖像,它們能轉(zhuǎn)為字節(jié)。

    存在值的實際長度限制 (如:保存10-50MB對象到HBase可能對查詢來說太長); 搜索郵件列表獲取本話題的對話。HBase的所有行都遵循HBase數(shù)據(jù)模型包括版本化。設(shè)計時需考慮到這些,以及列族的塊大小。

    存活時間

    列族可以設(shè)置TTL秒數(shù),HBase在超時后將自動刪除數(shù)據(jù),HBase里面TTL時間時區(qū)是UTC

    存儲文件僅包含有過期的行(expired rows),它們可通過minor compaction刪除。將 hbase.store.delete.expired.storefile設(shè)置為false,可禁用此功能;將最小版本數(shù)設(shè)置成非0值也可達到同樣的效果。

    HBase的最新版本還支持將設(shè)定的時間存放在每個結(jié)構(gòu)單元。TTL單元通過Mutation#setTTL作為更變請求(Appends, Increments, Puts, etc.)的一個屬性提交,如果TTL的屬性被設(shè)定了,它將會應(yīng)用到由于該更變操作更新的所有單元上。cell TTL handling和ColumnFamily TTLs間有兩個顯著的差別:

    1.Cell TTLs的數(shù)量級是毫秒而不是秒;

    2.一個cell TTL不能超出ColumnFamily TTLs設(shè)置的有效時間。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/davidwang456/articles/9253631.html

    總結(jié)

    以上是生活随笔為你收集整理的HBase最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。