HBase(八): 表結構設計優化

来源:http://www.cnblogs.com/tgzhu/archive/2016/09/11/5862299.html
-Advertisement-
Play Games

在 HBase(六): HBase體繫結構剖析(上) 介紹過,Hbase創建表時,只需指定表名和至少一個列族,基於HBase表結構的設計優化主要是基於列族級別的屬性配置,如下圖: 目錄: BLOOMFILTER BLOCKSIZE IN_MEMORY COMPRESSION/ENCODING VER ...


    在 HBase(六): HBase體繫結構剖析(上) 介紹過,Hbase創建表時,只需指定表名和至少一個列族,基於HBase表結構的設計優化主要是基於列族級別的屬性配置,如下圖:

目錄:

  • BLOOMFILTER
  • BLOCKSIZE
  • IN_MEMORY
  • COMPRESSION/ENCODING
  • VERSIONS
  • TTL

BLOOMFILTER


  • Bloom Filter是由Bloom在1970年提出的一種多哈希函數映射的快速查找演算法。通常應用在一些需要快速判斷某個元素是否屬於集合,但是並不嚴格要求100%正確的場合
  • bloom filter的數據存在StoreFile的meta中,一旦寫入無法更新,因為StoreFile是不可變的。Bloomfilter是一個列族(cf)級別的配置屬性,如果在表中設置了Bloomfilter,那麼HBase會在生成StoreFile時包含一份bloomfilter結構的數據,稱其為MetaBlock;MetaBlock與DataBlock(真實的KeyValue數據)一起由LRUBlockCache維護。所以,開啟bloomfilter會有一定的存儲及記憶體cache開銷
  • 對於已經存在的表,可以使用alter表的方式修改表結構,但這種修改對於之前的數據不會生效,只針對修改後插入的數據
  • 包含三種類型:NONE、ROW、ROWCOL
    1. ROW: 根據KeyValue中的row來過濾storefile,舉例如下:假設有2個storefile文件sf1和sf2
      • sf1包含kv1(r1 cf:q1 v)、kv2(r2 cf:q1 v)
      • sf2包含kv3(r3 cf:q1 v)、kv4(r4 cf:q1 v)
      • 如果設置了CF屬性中的bloomfilter為ROW,那麼get(r1)時就會過濾sf2,get(r3)就會過濾sf1
    2. ROWCOL:根據KeyValue中的row+qualifier來過濾storefile
      • 如上例:若設置了CF屬性中的bloomfilter為ROW,無論get(r1,q1)還是get(r1,q2),都會讀取sf1+sf2;
      • 而如果設置了CF屬性中的bloomfilter為ROWCOL,那麼get(r1,q1)就會過濾sf2,get(r1,q2)就會過濾sf1
  • region下的storefile數目越多,bloomfilter的效果越好
  • region下的storefile數目越少,HBase讀性能越好

BLOCKSIZE:


  • 從上圖可發現,預設的BlockSize 為 65536B (64KB),在 HBase(七): HBase體繫結構剖析(下) 介紹HBase讀原理,如果在blaock cache 、memostore中都沒查到符合條件的數據,則迴圈遍歷 storeFile 文件,而hbase讀取磁碟文件是按其基本I/O單元(即 hbase block)讀數據的,因此HFile塊大小是影響性能的重要參數
  • 參見Get\Scan場景下測試不同BlockSize大小(16K,64K,128K)對性能的影響,如下圖:對比結果參考:http://hbasefly.com/2016/07/02/hbase-pracise-cfsetting/
  •   
  • 可見,如果業務請求以Get請求為主,可以考慮將塊大小設置較小;如果以Scan請求為主,可以將塊大小調大;預設的64K塊大小是在Scan和Get之間取得的一個平衡
  • 平均鍵值對規劃,如下
    [root@HDP0 bin]# hbase hfile -m -f /apps/hbase/data/data/default/PerTest/7685e6c39d1394d94e26cf5ddafb7f9f/d/3ef195ca65044eca93cfa147414b56c2
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/usr/hdp/2.4.2.0-258/hadoop/lib/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/usr/hdp/2.4.2.0-258/zookeeper/lib/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
    2016-09-11 12:54:40,514 INFO  [main] hfile.CacheConfig: CacheConfig:disabled
    Block index size as per heapsize: 6520
    reader=/apps/hbase/data/data/default/PerTest/7685e6c39d1394d94e26cf5ddafb7f9f/d/3ef195ca65044eca93cfa147414b56c2,
        compression=none,
        cacheConf=CacheConfig:disabled,
        firstKey=00123ed7-5af8-49b1-bd13-9e086a5bd5f2/d:Action/1471406616120/Put,
        lastKey=fffbc8f7-55f2-4c49-804f-444f6ccbc903/d:UserID/1471406614464/Put,
        avgKeyLen=55,
        avgValueLen=10,
        entries=54180,
        length=4070738
  •  從上面輸出的信息可以看出,該HFile的平均鍵值對規模為55B + 10B = 65B,相對較小,在這種情況下可以適當將塊大小調小(例如8KB或16KB)。這樣可以使得一個block內不會有太多kv,kv太多會增大塊內定址的延遲時間,因為HBase在讀數據時,一個block內部的查找是順序查找

  • 選擇較小塊的大小的目的是使隨機讀取更快,而付出的代價是塊索引變大,會消耗更多的記憶體。相反,如果平均鍵值對規模很大,或者磁碟速度慢造成了性能瓶頸,那就應該選擇一個較大的塊大小,以便使一次磁碟IO能夠讀取更多的數據
  • 思考:實際場景大部分是Scan讀,但平均鍵值規劃較小,如何設置BlockSize?

 IN_MEMORY:


  • Block Cache 包含三個級別的優先順序隊列:
    1. Single: 如果一個Block被第一次訪問,則放在這一級的隊列中
    2. Multi:  如果一個Block被多次訪問,則從Single隊列移動Multi隊列
    3. In Memory: 它是靜態指定的(在column family上設置),不會像其他兩種cache會因訪問頻率而發生改變,這就決定了它的獨立性,另外兩種block訪問次數再多也不會被放到in-memory的區段里去,in-memory的block不管是第幾次訪問,總是被放置到in-memory的區段中
    • LRU(Least Recently Used)淘汰數據時,Single會被優先淘汰,其次是Multi, 最後是In Memory, 這三個隊列分別占用 BlockCache的 25%、50%、25%
    • 每load一個block到cache時,都會檢查當前cache的size是否已經超過了“警戒線”,這個“警戒線”是一個規定的當前block cache總體積占額定體積的安全比例,預設該值是0.85,即當載入了一個block到cache後總大小超過了既定的85%就開始觸發非同步的evict操作了
    • evict的邏輯是這樣的:遍歷cache中的所有block,根據它們所屬的級別(single,multi,in-memory)分撥到三個優先順序隊列中,隊頭元素是最舊(最近訪問日間值最小)的那個block。對這個三隊列依次驅逐頭元素,釋放空間
    • 註意: 標記 IN_MEMORY=>'true' 的column family的總體積最好不要超過in-memory cache的大小(in-memory cache = heap size * hfile.block.cache.size * 0.85 * 0.25),特別是當總體積遠遠大於了in-memory cache時,會在in-memory cache上發生嚴重的顛簸
    • 換個角度再看,普遍提到的使用in-memory cache的場景是把元數據表的column family聲明為IN_MEMORY=>'true。實際上這裡的潛臺詞是:元數據表都很小。其時我們也可以大膽地把一些需要經常訪問的,總體積不會超過in-memory cache的column family都設為IN_MEMORY=>'true'從而更加充分地利用cache空間。普通的block永遠是不會被放入in-memory cache的,只存放少量metadata是對in-memory cache資源的浪費
    • 操作命令如下(建表時或alter已創建的表):
      hbase(main):002:0> create 'Test',{NAME=>'d',IN_MEMORY=>'true'}
      0 row(s) in 4.4970 seconds
      => Hbase::Table - Test
      hbase(main):
      003:0> describe 'Test' Table Test is ENABLED Test COLUMN FAMILIES DESCRIPTION {NAME => 'd', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'true', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'} 1 row(s) in 0.2530 seconds hbase(main):004:0> create 'Test1','d' 0 row(s) in 2.2400 seconds => Hbase::Table - Test1 hbase(main):005:0> disable 'Test1' 0 row(s) in 2.2730 seconds hbase(main):006:0> alter 'Test1',{NAME=>'d',IN_MEMORY=>'true'} Updating all regions with the new schema... 1/1 regions updated. Done. 0 row(s) in 2.4610 seconds hbase(main):007:0> enable 'Test1' 0 row(s) in 1.3370 seconds hbase(main):008:0> describe 'Test1' Table Test1 is ENABLED Test1 COLUMN FAMILIES DESCRIPTION {NAME => 'd', BLOOMFILTER => 'ROW', VERSIONS => '1', IN_MEMORY => 'true', KEEP_DELETED_CELLS => 'FALSE', DATA_BLOCK_ENCODING => 'NONE', TTL => 'FOREVER', COMPRESSION => 'NONE', MIN_VERSIONS => '0', BLOCKCACHE => 'true', BLOCKSIZE => '65536', REPLICATION_SCOPE => '0'} 1 row(s) in 0.0330 seconds hbase(main):009:0>

 COMPRESSION/ENCODING


  • Compression就是在用CPU資源換取磁碟空間資源,對讀寫性能並不會有太大影響,HBase目前提供了三種常用的壓縮方式:GZip | LZO | Snappy
  • HBase在寫入數據塊到HDFS之前會首先對數據塊進行壓縮,再落盤,從而可以減少磁碟空間使用量
  • 讀數據的時候首先從HDFS中載入出block塊之後進行解壓縮,然後再緩存到BlockCache,最後返回給用戶。寫路徑和讀路徑分別如下
  • 結合上圖,來看看數據壓縮對資源使用情況以及讀寫性能的影響:
    1. 資源使用情況:壓縮最直接、最重要的作用即是減少數據硬碟容量,理論上snappy壓縮率可以達到5:1,但是根據測試數據不同,壓縮率可能並沒有理論上理想;壓縮/解壓縮無疑需要大量計算,需要大量CPU資源;根據讀路徑來看,數據讀取到緩存之前block塊會先被解壓,緩存到記憶體中的block是解壓後的,因此和不壓縮情況相比,記憶體前後基本沒有任何影響
    2. 讀寫性能:因為數據寫入是先將kv數據值寫到緩存,最後再統一flush的硬碟,而壓縮是在flush這個階段執行的,因此會影響flush的操作,對寫性能本身並不會有太大影響;而數據讀取如果是從HDFS中讀取的話,首先需要解壓縮,因此理論上讀性能會有所下降;如果數據是從緩存中讀取,因為緩存中的block塊已經是解壓後的,因此性能不會有任何影響;一般情況下大多數讀都是熱點讀,緩存讀占大部分比例,壓縮並不會對讀有太大影響
  • 官方分別從壓縮率,編解碼速率三個方面對其進行對比如下圖:
  • 綜合來看,Snappy的壓縮率最低,但是編解碼速率最高,對CPU的消耗也最小,目前一般建議使用Snappy
  • 從上圖看數據編碼對資源使用情況以及讀寫性能的影響:
    1. 資源使用情況:和壓縮一樣,編碼最直接、最重要的作用也是減少數據硬碟容量,但是數據編碼壓縮率一般沒有數據壓縮的壓縮率高,理論上只有5:2;編碼/解碼一般也需要大量計算,需要大量CPU資源;根據讀路徑來看,數據讀取到緩存之前block塊並沒有被解碼,緩存到記憶體中的block是編碼後的,因此和不編碼情況相比,相同數據block快占用記憶體更少,即記憶體利用率更高
    2. 讀寫性能:和數據壓縮相同,數據編碼也是在數據flush到hdfs階段執行的,因此並不會直接影響寫入過程;前面講到,數據塊是以編碼形式緩存到blockcache中的,因此同樣大小的blockcache可以緩存更多的數據塊,這有利於讀性能。另一方面,用戶從緩存中載入出來數據塊之後並不能直接獲取KV,而需要先解碼,這卻不利於讀性能。可見,數據編碼在記憶體充足的情況下會降低讀性能,而在記憶體不足的情況下需要經過測試才能得出具體結論
  • HBase目前提供了四種常用的編碼方式:Prefix | Diff | Fast_Diff | Prefix_Tree
  • 壓縮與編碼使用測試結果示例,來源於:http://hbasefly.com/2016/07/02/hbase-pracise-cfsetting/
  •    
  • 結果分析:
    1. 數據壓縮率並沒有理論上0.2那麼高,只有0.7左右,這和數據結構有關係。其中壓縮、編碼、壓縮+編碼三種方式的壓縮率基本相當
    2. 隨機讀場景:和預設配置相比,snappy壓縮在性能上沒有提升,CPU開銷卻上升了38%;prefix_tree性能上沒有提升,CPU利用率也基本相當;snappy+prefix_tree性能沒有提升,CPU開銷上升了38%
    3. 區間掃描場景:和預設配置相比,snappy壓縮在性能上略有10%的提升,但是CPU開銷卻上升了23%;prefix_tree性能上略有4%左右的下降,但是CPU開銷也下降了5%,snappy+prefix_tree在性能上基本沒有提升,CPU開銷卻上升了23%
  • 設計原則:
    1. 在任何場景下開啟prefix_tree編碼都是安全的
    2. 在任何場景下都不要同時開啟snappy壓縮和prefix_tree編碼
    3. 通常情況下snappy壓縮並不能比prefix_tree編碼獲得更好的優化結果,如果需要使用snappy需要針對業務數據進行實際測試

 VERSIONS


  •  用於定義某列族所能記錄的最多的版本數量,預設值是3,即每個單元格的最大版本數量是3
  • 對於更新頻繁的應用,建設設置為1,可以快速淘汰無用的數據,節省存儲空間同時還能提升查詢效率
  • 同樣道理,可在建表時指定或通過alter修改表結構實現

TTL


  • TTL:Time To Live 用於定義列族中單元格存活時間,過期數據自動刪除
  • TTL屬性特性:
    1. 單位是秒,預設值:FOREVEN (永不過期)
    2. 當一行所有列都過期後,RowKey也會被刪除
    3. 若TTL設置為兩個月,則時間戮為2個月之前的數據不能插入
  • 同理,在建表時指定或通過alter修改表結構設置

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言:不僅要知其然,還要知所以然 MySQL資料庫作為關係型資料庫中的佼佼者,因其體積小,速度快,成本低,不僅受到了市場的極大追捧,也受到了廣大程式員的青睞。接下來,就給大家說一下,MySQL的下載和安裝: 一、MySQL的下載 第一步:在瀏覽器的地址欄輸入 https://www.mysql.co ...
  • 介紹 mysqlslap是mysql自帶的一個性能壓測工具;mysqlslap用於和其它的一些性能壓測工具一樣可以自己造數據進行壓測。mysqlslap的報告比較簡單主要體現在執行的時間方面,沒有sysbench那樣的tps、qps等更詳細的包括。 參數 --auto-generate-sql -a ...
  • 還在糾結安裝oracle失敗後無法卸載的苦惱嗎?這裡教你如何徹底卸載oracle資料庫 ...
  • mysql存儲過程詳解 1. 存儲過程簡介 我們常用的操作資料庫語言SQL語句在執行的時候需要要先編譯,然後執行,而存儲過程(Stored Procedure)是一組為了完成特定功能的SQL語句集,經編譯後存儲在資料庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。 ...
  • 介紹 以前一直使用centos今天需要對一臺ubantu的系統安裝mysql,雖然它也是類unix但是和redhat或centos命令上還是有點差別。 下載解壓 wget http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.33-linux- ...
  • 轉自http://www.shangxueba.com/jingyan/1940447.html 1.游標方式 複製代碼代碼如下: DECLARE @Data NVARCHAR(max) SET @Data='1,tanw,2,keenboy' --Id,Name DECLARE @dataItem ...
  • 附加資料庫時出現附加資料庫失敗的錯誤,錯誤號是5120,已經兩次遇到這種問題了。今天寫一下解決辦法。 有兩個方法,很簡單: 1.設置mdf文件所在文件夾的許可權,在文件夾上右擊——屬性——安全,如圖所示: 根據圖示進行設置即可,註意是Authenticated user的許可權。 2.不要用sa登陸你的 ...
  • 在主庫沒有數據情況下配置MYSQL的主從及讀寫分離。目前只接觸過mysql_proxy,atlas(360)的代理。現已學習一下。以備以後用到。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...