本文已收錄至Github,推薦閱讀 ?? Java隨想錄
微信公眾號:Java隨想錄
目錄- HBase特性
- Hadoop的限制
- 基本概念
- NameSpace
- Table
- RowKey
- Column
- TimeStamp
- Cell
- 存盤結構
- HBase 資料訪問形式
- 架構體系
- HBase組件
- HBase讀寫流程
- 讀流程
- 寫流程
- MemStore Flush
- 引數說明
- StoreFile Compaction
- 引數說明
- 觸發程序
- Region Split
- 預磁區
- HBase優化
- 查詢優化
- 設定Scan快取
- 顯示指定列
- 禁用塊快取
- 寫入優化
- 設定AutoFlush
- 引數優化
- Zookeeper 會話超時時間
- 設定 RPC 監聽數量
- 手動控制 Major Compaction
- 優化 HStore 檔案大小
- 優化 HBase 客戶端快取
- 指定 scan.next 掃描 HBase 所獲取的行數
- 查詢優化
- SpringBoot中使用HBase
- Scan
- Phoenix
HBase(Hadoop Database)是一個開源的、分布式的、面向列的NoSQL資料庫,它是構建在Hadoop之上的,HBase旨在提供可靠的、高性能的、可擴展的存盤和訪問大規模資料集的能力,
HBase特性
以下是HBase的一些關鍵特性和概念:
- 分布式架構:HBase是一個分布式資料庫,它可以在一個集群中運行在多個機器上,資料以水平分片的方式分布在不同的機器上,這樣可以實作資料的高可用性和橫向擴展性,
- 列存盤:HBase是面向列的資料庫,它將資料存盤在表中的列族中,每個列族可以包含多個列,這樣可以方便地存盤和檢索具有不同結構的資料,HBase的列存盤特性使得可以高效地讀取和寫入大量資料,
- 強一致性:HBase提供強一致性的讀寫操作,當資料被寫入或讀取時,HBase會確保所有相關的副本都是最新的,這使得HBase非常適合需要強一致性的應用場景,如金融、電信等領域,
- 高可擴展性:HBase可以輕松地擴展到大規模的資料集和集群,通過添加更多的機器和分片資料,可以線性地擴展存盤容量和吞吐量,
- 快速讀寫:HBase是為了高性能而設計的,它使用了記憶體和硬碟的組合來存盤資料,可以實作快速的讀寫操作,此外,HBase還支持批量寫入和異步寫入,進一步提高了寫入性能,
- 靈活的資料模型:HBase提供了靈活的資料模型,可以根據應用程式的需求設計表結構,它支持動態添加列,并且可以高效地執行范圍查詢和單行讀寫操作,
- 資料一致性:HBase通過使用ZooKeeper來管理集群的元資料和協調分布式操作,確保資料的一致性和可用性,
- 集成Hadoop生態系統:HBase與Hadoop生態系統緊密集成,可以與Hadoop分布式檔案系統(HDFS)和Hadoop的計算框架(如MapReduce)無縫配合使用,這使得HBase能夠處理大規模的資料存盤和分析任務,
Hadoop的限制
盡管Hadoop是一個強大的分布式計算框架,但它也存在一些不足之處,與HBase相比,以下是一些Hadoop的限制:
- 實時性:Hadoop主要用于批處理任務,對于實時性要求較高的應用場景,如實時資料分析和流式處理,Hadoop的延遲可能會比較高,Hadoop的MapReduce模型通常不適合處理需要即時回應的資料處理任務,
- 存盤效率:Hadoop在存盤效率方面存在一些問題,為了提供容錯性和可靠性,Hadoop將資料復制多次存盤在不同的節點上,這會導致存盤開銷增加,相對于HBase的列存盤模型,Hadoop的存盤效率可能較低,
- 復雜性:Hadoop的配置和管理相對復雜,需要專業知識和經驗,搭建和維護一個Hadoop集群需要處理許多引數和組件,對于初學者來說可能存在一定的學習曲線,
- 擴展性限制:雖然Hadoop具有良好的可擴展性,可以通過添加更多的節點來擴展集群的存盤和計算能力,但在某些情況下,隨著集群規模的增加,管理和調度節點可能變得更加困難,
- 處理復雜查詢的限制:Hadoop的主要計算模型是MapReduce,它適合處理簡單的計算任務,但對于復雜的查詢和資料分析,如復雜聚合、連接和實時查詢等,Hadoop的性能可能不如專門設計的分析資料庫,
基本概念
NameSpace
命名空間,類似于關系型資料庫的Database概念,每個命名空間下有多個表,
HBase自帶兩個命名空間,分別是hbase和default,hbase 中存放的是HBase內置的表,default表是用戶默認使用的命名空間,這2個命名空間默認是不展示的,
Table
類似于關系型資料庫的表概念,不同的是,HBase定義表時只需要宣告列族即可,不需要宣告具體的列,因為資料存盤時稀疏的,空(null)列不占用存盤空間,所有往HBase寫入資料時,欄位可以動態、按需指定,因此,和關系型資料庫相比,HBase 能夠輕松應對欄位變更的場景,
RowKey
HBase表中的每行資料都由一個RowKey和多個Column(列)組成,資料是按照RowKey的字典順序存盤的,并且查詢資料時只能根據RowKey進行檢索,所以RowKey的設計十分重要,
Column
HBase中的每個列都由Colunn Family (列族)和Column Qualifier (列限定符)進行限定,例如info: name, info: age, 建表時,只需指明列族,而列限定符無需預先定義,
TimeStamp
用于標識資料的不同版本(version),每條資料寫入時,系統會自動為其加上該欄位,其值為寫入HBase的時間,
Cell
由{rowkey, column Family:column Qualifier, timestamp} 唯一確定的單元,Cell 中的資料全部是位元組碼形式存貯,
一條資料有多個版本,每個版本都是一個Cell,
存盤結構
HBase存盤結構如下:
上面的這種資料會存盤為下面這樣,底層存盤為Byte:
行分為Region,列分為Store,Region可以放在其他機器上,
HBase是基于HDFS的,而HDFS是不能夠修改資料的,所以HBase其實也是不能修改資料的,HBase使用時間戳實作修改功能,取資料的時候取最新時間戳的資料,取出來的就是最新的資料,
HBase 資料訪問形式
HBase資料訪問可以通過以下幾種形式進行:
- 單行讀寫(Get和Put):使用HBase提供的API,可以通過指定行鍵(Row Key)來讀取和寫入單行資料,Get操作可以根據行鍵從表中獲取特定行的資料,而Put操作可以將資料寫入表的指定行,
- 批量讀寫(Scan和Batch Put):HBase支持批量讀寫操作,可以一次性讀取或寫入多行資料,Scan操作可以按照一定的條件掃描表中的多行資料,而Batch Put操作可以一次性寫入多行資料,
- 全表掃描(Scan):通過Scan操作,可以遍歷整個表的資料,按照指定的條件進行過濾和篩選,可以設定起始行鍵和結束行鍵,還可以使用過濾器(Filter)進行更精確的資料查詢,
- 列族范圍掃描(Scan):HBase中的資料以列族(Column Family)為單位進行存盤,可以通過Scan操作對指定列族的資料進行范圍掃描,這種方式可以提高資料查詢的效率,只獲取所需列族的資料,而不必讀取整個表的資料,
- 過濾器(Filter):HBase支持多種過濾器來進行資料的精確查詢和過濾,可以使用行鍵過濾器(Row Filter)按照行鍵的條件進行資料過濾,還可以使用列族過濾器(Family Filter)、列限定符過濾器(Qualifier Filter)和值過濾器(Value Filter)等進行更細粒度的資料過濾,
- 原子性操作(Check-and-Put和Check-and-Delete):HBase支持原子性操作,例如Check-and-Put和Check-and-Delete,這些操作允許在寫入資料之前進行檢查,只有在滿足指定條件的情況下才執行寫入操作,
以上形式提供了不同的資料訪問方式,可以根據具體的需求和查詢條件選擇適合的方式來訪問和操作HBase中的資料,
架構體系
HBase的架構體系是基于分布式存盤和處理的設計,它包含了以下幾個重要的組成部分:
- HMaster:HMaster是HBase集群的主節點,負責管理整個集群的元資料和協調各個RegionServer的作業,它維護了表的結構資訊、分片規則、RegionServer的負載均衡等,并協調分布式操作,如Region的分裂和合并,
- RegionServer:RegionServer是HBase集群中的作業節點,負責存盤和處理資料,每個RegionServer管理多個Region,每個Region負責存盤表中的一部分資料,RegionServer處理客戶端的讀寫請求,負責資料的存盤、讀取和寫入操作,
- ZooKeeper:ZooKeeper是一個分布式協調服務,被HBase用于管理集群的元資料和協調分布式操作,HBase使用ZooKeeper來進行主節點的選舉、故障檢測、集群配置的同步等任務,
- HDFS(Hadoop Distributed File System):HBase使用HDFS作為底層的分布式檔案系統,用于存盤資料,HDFS將資料分割成塊并分布在不同的節點上,提供高可靠性和可擴展性的存盤,
- HBase客戶端:HBase客戶端是與HBase互動的應用程式或工具,用于發送讀寫請求和接收查詢結果,客戶端可以通過HBase的Java API或者命令列工具(如HBase shell)來訪問和操作HBase表,
- 表和列族:HBase資料模型是基于表的,表由一個或多個列族(Column Family)組成,每個列族可以包含多個列(Column),列存盤著實際的資料,表被分割成多個Region存盤在不同的RegionServer上,每個Region負責存盤一部分行資料,
這些組成部分共同構成了HBase的架構體系,實作了分布式存盤和處理大規模資料集的能力,HMaster負責管理元資料和協調作業,RegionServer存盤和處理資料,ZooKeeper提供分布式協調服務,HDFS提供底層的分布式檔案存盤,而HBase客戶端用于與HBase進行互動,表和列族的概念提供了資料的組織和存盤方式,
HBase組件
- MemStore:每個RegionServer都有一個MemStore,它是位于記憶體中的臨時資料存盤區域,當客戶端寫入資料時,資料首先被寫入到MemStore中,以提供快速的寫入性能,
- WAL(Write-Ahead-Log):WAL是HBase的日志檔案,用于記錄所有的寫操作,當資料被寫入到MemStore時,相應的寫操作也會被寫入WAL中,以保證資料的持久性和故障恢復能力,
- StoreFile:當MemStore中的資料達到一定大小閾值后,會被重繪到磁盤上的StoreFile中,StoreFile是HBase中實際持久化存盤資料的檔案形式,它包含了已經寫入的資料和相應的索引,
- HFile:HFile是StoreFile的底層存盤格式,采用了塊索引和時間范圍索引的方式,提供了高效的資料查找和掃描能力,HFile使用塊(Block)來組織資料,并采用壓縮和編碼技術來減小存盤空間,
MemStore提供了臨時的記憶體存盤,StoreFile提供了持久化的磁盤存盤,WAL用于保證資料的持久性,這種架構設計使得HBase能夠提供高可用性、高性能和可擴展性的分布式存盤和處理能力,
HBase讀寫流程
讀流程
- 客戶端發送讀取請求:客戶端向HBase集群發送讀取請求,包括所需的表名、行鍵(Row Key)以及其他可選的引數(如列族、列限定符等),
- 定位RegionServer和Region:HBase的客戶端會與ZooKeeper進行通信,獲取到存盤有所需資料的Region所在的RegionServer的資訊,
- RegionServer處理請求:客戶端發送的讀取請求到達對應的RegionServer,RegionServer會根據請求的行鍵定位到包含所需資料的Region,
- 資料讀取:RegionServer首先會從MemStore中查找資料,如果資料在MemStore中找到,則直接回傳給客戶端,如果資料不在MemStore中,RegionServer會在磁盤上的StoreFile中進行查找,根據索引定位到所需的資料塊,并將資料塊讀取到記憶體中進行處理,
- 資料回傳給客戶端:RegionServer將讀取到的資料回傳給客戶端,客戶端可以根據需要對資料進行進一步的處理和分析,
寫流程
- 客戶端發送寫入請求:客戶端向HBase集群發送寫入請求,包括表名、行鍵、列族、列限定符和對應的值等資訊,
- 定位RegionServer和Region:客戶端與ZooKeeper通信,獲取存盤目標資料的Region所在的RegionServer的資訊,
- RegionServer處理請求:客戶端發送的寫入請求到達對應的RegionServer,RegionServer根據行鍵定位到目標Region,
- 寫入到MemStore:RegionServer將寫入請求中的資料寫入到目標Region對應的記憶體中的MemStore,寫入到MemStore是一個追加操作,將資料追加到記憶體中的MemStore中,并不直接寫入磁盤,
- WAL日志記錄:同時,RegionServer將寫入請求中的操作寫入WAL(Write-Ahead-Log)日志檔案,確保資料的持久性和故障恢復能力,
- MemStore重繪到磁盤:當MemStore中的資料達到一定的大小閾值時,RegionServer會將MemStore中的資料重繪到磁盤上的StoreFile中,重繪程序將記憶體中的資料寫入到磁盤上的StoreFile,并生成相應的索引,
- 資料回傳給客戶端:寫入完成后,RegionServer向客戶端發送寫入成功的回應,表示資料已成功寫入,
MemStore Flush
在HBase中,MemStore Flush是將記憶體中的資料重繪到磁盤上的StoreFile的程序,當MemStore中的資料達到一定大小閾值時,或者達到了一定的時間限制,HBase會觸發MemStore Flush操作,以將資料持久化到磁盤,確保資料的持久性和可靠性,
下面是MemStore Flush的基本程序:
- MemStore Flush觸發:當MemStore中的資料量達到一定的閾值(由配置引數控制)或者達到了一定的時間限制時,HBase會觸發MemStore Flush操作,這個閾值和時間限制可以根據需求進行配置,以平衡寫入性能和資料持久性的要求,
- 寫入記憶體快照:在觸發Flush操作時,HBase會先將MemStore中的資料做一個記憶體快照(Snapshot),以保證在Flush期間繼續接收新的寫入請求,
- 刷寫到磁盤:記憶體快照完成后,HBase會將記憶體中的資料按照列族的維度劃分為多個KeyValue,然后將這些KeyValue寫入磁盤上的StoreFile,StoreFile采用HFile格式,用于持久化存盤資料,
- 更新Region元資料:完成刷寫到磁盤后,HBase會更新Region的元資料,包括最新的StoreFile串列和相應的時間戳等資訊,
- MemStore清空:一旦資料刷寫到磁盤上的StoreFile,HBase會清空相應的MemStore,以釋放記憶體空間用于接收新的寫入請求,
通過MemStore Flush操作,HBase可以將記憶體中的資料持久化到磁盤,以確保資料的持久性和可靠性,Flush操作的頻率和成本可以通過配置引數進行調整,以適應不同的應用場景和性能需求,頻繁的Flush操作可能會影響寫入性能,而較長的Flush間隔可能會增加資料丟失的風險,因此,根據實際情況,需要合理設定Flush操作的引數,以平衡資料的持久性和寫入性能的要求,
引數說明
MemStore Flush在HBase中由以下幾個引數進行控制,它們的含義如下:
- hbase.hregion.memstore.flush.size:該引數指定了MemStore的大小閾值,當MemStore中的資料量達到或超過這個閾值時,將觸發MemStore Flush操作,該引數的默認值為 128MB,這個引數在HBase 0.98版本及更高版本中生效,在舊版本中,類似的引數名為 hbase.hregion.memstore.flush.size.upper,但其含義和作用相同,
- hbase.hregion.memstore.block.multiplier:該引數是用來設定MemStore大小閾值的倍數,當MemStore的大小超過 hbase.hregion.memstore.flush.size 乘以 hbase.hregion.memstore.block.multiplier 時,將觸發MemStore Flush操作,默認值為2,這個引數在HBase 0.98版本及更高版本中生效,
- hbase.hregion.memstore.flush.size.lower.limit:該引數定義了MemStore大小的下限限制,當MemStore中的資料量小于此下限時,不會觸發MemStore Flush操作,該引數的默認值為0,在HBase 2.0版本及更高版本中生效,
- hbase.hregion.memstore.flush.size.upper.limit:該引數定義了MemStore大小的上限限制,當MemStore中的資料量超過此上限時,將強制觸發MemStore Flush操作,該引數的默認值為Long.MAX_VALUE,在HBase 2.0版本及更高版本中生效,
上述的1和2,滿足任一條件都會觸發MemStore Flush操作,
這些引數需要根據具體的應用場景和性能要求進行合理的設定,較小的Flush閾值可以提高資料的持久性,但可能會增加Flush的頻率和寫入的開銷;較大的Flush閾值可以減少Flush的頻率和開銷,但可能會增加資料丟失的風險,因此,需要根據應用的讀寫特征和資料的重要性,選擇合適的引數值,
StoreFile Compaction
StoreFile Compaction(檔案合并)是 HBase 中的一個重要操作,它用于合并和優化存盤在磁盤上的資料檔案(StoreFile),StoreFile Compaction 可以幫助減少磁盤空間占用、提高讀取性能,并且在某些情況下可以提高寫入性能,
StoreFile Compaction 的基本程序如下:
- Compact Selection(選擇合并):在進行 Compaction 之前,HBase 首先進行選擇性合并,它會根據一定的策略,如大小、時間戳等,選擇一組需要合并的 StoreFile,這樣可以限制合并的資料量,避免一次合并過多資料,
- Minor Compaction(小規模合并):Minor Compaction 主要合并較少數量的 StoreFile,它通過創建一個新的 StoreFile,并從多個舊的 StoreFile 中選擇合并的資料,將其合并到新的檔案中,這個程序中,舊的 StoreFile 不會被洗掉,新的 StoreFile 會被創建并寫入新的資料,
- Major Compaction(大規模合并):Major Compaction 是一種更為綜合和耗時的合并操作,它會合并一個或多個 HBase 表的所有 StoreFile,Major Compaction 將會創建一個新的 StoreFile,并將所有舊的 StoreFile 中的資料合并到新的檔案中,與 Minor Compaction 不同,Major Compaction 還會洗掉舊的 StoreFile,從而釋放磁盤空間,
- Compaction Policy(合并策略):HBase 提供了不同的合并策略,可以根據資料特點和應用需求進行選擇,常見的合并策略包括 SizeTieredCompactionPolicy(按大小合并)和 DateTieredCompactionPolicy(按時間戳合并)等,
通過 StoreFile Compaction,HBase 可以減少磁盤上的存盤空間占用,提高讀取性能,同時合并操作還可以優化資料布局,加速資料的訪問,合適的合并策略的選擇可以根據資料的訪問模式和應用需求,以達到最佳的性能和存盤效率,
引數說明
StoreFile Compaction 程序中涉及到的一些相關引數及其含義如下:
- hbase.hstore.compaction.min:指定了進行 Minor Compaction 的最小檔案數,當 StoreFile 的數量達到或超過該值時,才會觸發 Minor Compaction,默認值為 3,
- hbase.hstore.compaction.max:指定了進行 Major Compaction 的最大檔案數,當 StoreFile 的數量超過該值時,將觸發 Major Compaction,默認值為 10,
- hbase.hstore.compaction.ratio:指定了觸發 Major Compaction 的比率,當一個 Region 中的 StoreFile 的總大小超過其最大檔案大小的比率時,將觸發 Major Compaction,默認值為 1.2,
- hbase.hstore.compaction.min.size:指定了進行 Compaction 的最小檔案大小,當一個 StoreFile 的大小小于該值時,將不會參與 Compaction,默認值為 1 KB,
- hbase.hstore.compaction.max.size:指定了進行 Compaction 的最大檔案大小,當一個 StoreFile 的大小超過該值時,將不會參與 Compaction,默認值為 Long.MAX_VALUE,即無限制,
- hbase.hstore.compaction.enabled:指定了是否啟用 Compaction,如果設定為 false,則不會觸發任何 Compaction 操作,默認值為 true,
- hbase.hstore.compaction.checker.interval.multiplier:指定了進行 Compaction 檢查的時間間隔,實際檢查的時間間隔為 hbase.hstore.compaction.checker.interval.multiplier 乘以 StoreFile 的平均大小,默認值為 1.0,
這些引數可以在 HBase 的組態檔(hbase-site.xml)中進行設定,通過調整這些引數的值,可以根據資料量、存盤需求和性能要求來優化 Compaction 操作的觸發條件和行為,
觸發程序
以下是判斷是否觸發 Compaction 的程序:
-
判斷是否滿足進行 Minor Compaction 的條件:
- 檢查 StoreFile 的數量是否達到或超過 hbase.hstore.compaction.min,如果是,則滿足觸發 Minor Compaction 的條件,
-
判斷是否滿足進行 Major Compaction 的條件:
- 檢查 StoreFile 的數量是否超過 hbase.hstore.compaction.max,如果是,則滿足觸發 Major Compaction 的條件,
或者
- 計算 StoreFile 的總大小與最大檔案大小之間的比率,如果超過 hbase.hstore.compaction.ratio,即 StoreFile 的總大小超過最大檔案大小的比率,那么滿足觸發 Major Compaction 的條件,
-
對于即將進行 Compaction 的 StoreFile:
- 檢查 StoreFile 的大小是否在 hbase.hstore.compaction.min.size 和 hbase.hstore.compaction.max.size 之間,如果不在這個范圍內,則該檔案將不會參與 Compaction,
-
檢查是否啟用 Compaction:
- 檢查 hbase.hstore.compaction.enabled 的值是否為 true,如果為 false,則不會觸發任何 Compaction 操作,
-
判斷觸發 Compaction 的時間間隔:
- 根據 hbase.hstore.compaction.checker.interval.multiplier 乘以 StoreFile 的平均大小,得出實際的檢查時間間隔,
根據以上判斷程序,HBase 在每個 RegionServer 上的每個 Store(列族)會根據配置引數進行定期的 Compaction 檢查,一旦滿足觸發 Compaction 的條件,相應的 Minor Compaction 或 Major Compaction 將被觸發,合并和優化存盤的資料檔案,這樣可以提高讀取性能、節省磁盤空間,并且在某些情況下可以提高寫入性能,
Region Split
Region Split(區域分割)是 HBase 中的一個重要操作,它用于在資料增長程序中,將一個較大的 HBase 表的 Region(區域)劃分成更小的子區域,以提高讀寫性能和負載均衡,
當一個 Region 的大小達到了預先配置的閾值時,HBase 將觸發 Region Split 操作,Region Split 的基本程序如下:
- Split Policy(分割策略):HBase 提供了多種分割策略,用于決定何時觸發 Region Split,常見的分割策略包括按大小分割(Size-based Split)和按行數分割(Row-count-based Split),這些策略可以根據資料特點和應用需求進行選擇,
- Split Selection(選擇分割點):在觸發分割之前,HBase 首先選擇一個適當的分割點,分割點是指一個 RowKey,它將成為分割后的兩個子區域的邊界,選擇分割點的策略可以是根據大小、行數或其他自定義邏輯進行選擇,
- Region Split(區域分割):一旦選擇了分割點,HBase 將通過創建兩個新的子區域來執行分割操作,原始的 Region 將被拆分成兩個子區域,每個子區域負責存盤分割點兩側的資料,同時,HBase 會為新的子區域生成新的 Region ID,并更新元資料資訊,
常見的區域分割方式包括:
- 均勻分割(Even Split):將一個 Region 均勻地劃分為兩個子區域,分割點根據資料大小或行數進行選擇,以保持兩個子區域的大小相近,
- 預磁區(Pre-splitting):在創建表時,可以提前定義多個分割點,將表劃分為多個初始的子區域,這樣可以在表創建之初就實作資料的均衡分布,避免后續的動態分割,
- 自定義分割(Custom Split):根據具體的業務需求和資料特點,可以通過自定義邏輯來選擇分割點,實作更靈活的分割方式,
通過合理地使用區域分割,可以充分利用集群資源,提高讀寫性能和負載均衡能力,不同的分割策略和分割方式可以根據資料規模、訪問模式和應用需求進行選擇,以滿足不同場景下的需求,
預磁區
在 HBase 中進行預磁區可以通過 HBase Shell 或 HBase API 進行操作,以下是使用 HBase Shell 進行預磁區的示例:
-
打開 HBase Shell:
$ hbase shell
-
創建表并指定磁區:
hbase(main):001:0> create 'my_table', 'cf', {SPLITS => ['a', 'b', 'c']}
上述命令創建了一個名為
my_table
的表,并指定了三個磁區點:'a'、'b' 和 'c',這將創建四個初始的子區域, -
查看表的磁區情況:
hbase(main):002:0> describe 'my_table'
這將顯示表的詳細資訊,包括磁區資訊,
通過上述步驟,你可以在創建表時預先定義磁區點,從而實作預磁區,每個磁區點將成為一個子區域的邊界,確保資料在表創建時就能分布在多個子區域中,從而實作負載均衡和性能優化,
請注意,上述示例是使用 HBase Shell 進行預磁區的簡單示例,如果需要在編程中進行預磁區,可以使用 HBase API,例如 Java API,通過在創建表時設定 SPLITS
引數來指定磁區點,
以下是使用 HBase Java API 進行預磁區的示例代碼:
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
public class PreSplitExample {
public static void main(String[] args) throws IOException {
// 創建 HBase 配置
org.apache.hadoop.conf.Configuration config = HBaseConfiguration.create();
// 創建 HBase 連接
try (Connection connection = ConnectionFactory.createConnection(config)) {
// 創建 HBase 管理器
try (Admin admin = connection.getAdmin()) {
// 定義表名
TableName tableName = TableName.valueOf("my_table");
// 定義磁區點
byte[][] splitKeys = {
Bytes.toBytes("a"),
Bytes.toBytes("b"),
Bytes.toBytes("c")
};
// 創建表并指定磁區
admin.createTable(TableDescriptorBuilder.newBuilder(tableName)
.addColumnFamily(ColumnFamilyDescriptorBuilder.of("cf"))
.setSplitKeys(splitKeys)
.build());
}
}
}
}
上述代碼通過 HBase Java API 創建了一個名為 my_table
的表,并指定了三個磁區點:'a'、'b' 和 'c',這將創建四個初始的子區域,
請注意,在使用 Java API 進行預磁區時,需要先建立與 HBase 的連接,并通過 HBase 管理器(Admin)執行表的創建操作,并設定 setSplitKeys(splitKeys)
方法來指定磁區點,
通過上述示例代碼,你可以在編程中使用 HBase Java API 實作預磁區功能,
HBase優化
查詢優化
設定Scan快取
在HBase中,可以通過設定Scan
物件的setCaching()
方法來調整Scan
快取的大小,Scan
快取用于指定每次掃描操作從RegionServer回傳給客戶端的行數,通過調整快取大小,可以在一定程度上控制資料的讀取性能和網路傳輸的開銷,
以下是設定Scan
快取的示例代碼:
Scan scan = new Scan();
scan.setCaching(500); // 設定快取大小為500行
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 處理掃描結果
}
scanner.close();
在上述示例中,setCaching()
方法將快取大小設定為500行,可以根據實際需求調整這個值,需要根據資料大小、網路帶寬和性能要求進行權衡,較大的快取大小可以減少客戶端與RegionServer之間的通信次數,提高讀取性能,但同時也會增加記憶體消耗,較小的快取大小可以減少記憶體消耗,但可能會增加通信次數和網路傳輸開銷,
需要注意的是,setCaching()
方法設定的是每次掃描的快取大小,并不是全域的設定,如果需要對整個表的掃描操作生效,需要在每次掃描時都設定快取大小,
此外,還可以通過調整HBase的配置引數來全域設定快取大小,在hbase-site.xml
組態檔中添加以下引數可以設定默認的快取大小:
<property>
<name>hbase.client.scanner.caching</name>
<value>500</value> <!-- 設定默認的快取大小為500行 -->
</property>
以上是通過代碼和組態檔來設定Scan
快取大小的方法,根據具體的應用場景和需求,可以選擇適當的方式進行設定,
顯示指定列
當使用Scan或者GET獲取大量的行時,最好指定所需要的列,因為服務端通過網路傳輸到客戶端,資料量太大可能是瓶頸,如果能有效過濾部分資料,能很大程度的減少網路I/O的花費,
在HBase中,可以使用Scan
或Get
操作來顯示指定的列,下面分別介紹兩種方式的用法:
- 使用
Scan
操作顯示指定列:
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定列族(cf)和列(col1)
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
byte[] value = https://www.cnblogs.com/booksea/p/result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
// 處理列(col1)的值
}
scanner.close();
在上述示例中,使用scan.addColumn()
方法來指定要顯示的列族和列,在for
回圈中,通過result.getValue()
方法獲取指定列的值,
- 使用
Get
操作顯示指定列:
Get get = new Get(Bytes.toBytes("row1")); // 指定行鍵(row1)
get.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定列族(cf)和列(col1)
Result result = table.get(get);
byte[] value = https://www.cnblogs.com/booksea/p/result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
// 處理列(col1)的值
在上述示例中,使用get.addColumn()
方法來指定要顯示的列族和列,通過table.get()
方法獲取行資料,并通過result.getValue()
方法獲取指定列的值,
無論是使用Scan
還是Get
,都可以通過addColumn()
方法來指定要顯示的列族和列,可以根據具體的需求,多次呼叫addColumn()
方法來顯示多個列,
需要注意的是,HBase中的列是以位元組陣列(byte[]
)形式表示的,因此在使用addColumn()
和getValue()
方法時,需要將列族和列名轉換為位元組陣列,
禁用塊快取
如果批量進行全表掃描,默認是有快取的,如果此時有快取,會降低掃描的效率,
在HBase中,可以通過設定Scan
物件的setCacheBlocks()
方法來禁用塊快取,塊快取是HBase中的一種快取機制,用于加快資料的讀取操作,然而,在某些情況下,禁用塊快取可能是有益的,例如對于某些熱點資料或者需要立即獲取最新資料的場景,
以下是禁用Scan
塊快取的示例代碼:
Scan scan = new Scan();
scan.setCacheBlocks(false); // 禁用塊快取
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 處理掃描結果
}
scanner.close();
在上述示例中,setCacheBlocks(false)
方法將禁用Scan
操作的塊快取,
需要注意的是,禁用塊快取可能會增加對HBase存盤的實際磁盤讀取次數,并且在一些場景下可能導致性能下降,因此,在禁用塊快取之前,建議仔細評估應用需求和場景,確保禁用塊快取的決策是合理的,
對于經常讀到的資料,建議使用默認值,開啟塊快取,
寫入優化
設定AutoFlush
Htable有一個屬性是AutoFlush,該屬性用于支持客戶端的批量更新,默認是true,當客戶端每收到一條資料,立刻發送到服務端,如果設定為false,當客戶端提交put請求時候,先將該請求在客戶端快取,到達閾值的時候或者執行hbase.flushcommits(),才向RegionServer提交請求,
在HBase中,可以通過設定Table
物件的setAutoFlush()
方法來控制自動重繪(AutoFlush)行為,AutoFlush決定了在何時將資料從客戶端發送到RegionServer并寫入到存盤中,
以下是設定AutoFlush的示例代碼:
// 創建HBase配置物件
Configuration conf = HBaseConfiguration.create();
// 創建HBase連接
Connection connection = ConnectionFactory.createConnection(conf);
// 獲取表物件
TableName tableName = TableName.valueOf("your_table_name");
Table table = connection.getTable(tableName);
// 設定AutoFlush
table.setAutoFlush(false); // 關閉AutoFlush
// 執行寫入操作
Put put = new Put(Bytes.toBytes("row1"));
put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1"), Bytes.toBytes("value1"));
table.put(put);
// 手動重繪資料
table.flushCommits(); // 手動重繪資料到RegionServer
// 關閉表和連接
table.close();
connection.close();
在上述示例中,table.setAutoFlush(false)
方法將關閉AutoFlush,這意味著在執行寫操作時,資料不會立即被重繪到RegionServer和存盤中,而是先快取在客戶端的記憶體中,只有當呼叫table.flushCommits()
方法時,資料才會被手動重繪到RegionServer,
需要注意的是,關閉AutoFlush可以提高寫入性能,尤其是在批量寫入或者頻繁寫入的場景中,但是,關閉AutoFlush也會增加資料在客戶端記憶體中的暫存時間,并增加了資料丟失的風險,因此,在關閉AutoFlush時,需要在適當的時機手動呼叫flushCommits()
方法來確保資料的持久性,
同時,還可以通過設定table.setWriteBufferSize()
方法來指定客戶端寫緩沖區的大小,這可以幫助在快取中存盤更多的資料,減少重繪到RegionServer的次數,提高寫入性能,例如:
table.setWriteBufferSize(1024 * 1024); // 設定寫緩沖區大小為1MB
在上述示例中,將寫緩沖區大小設定為1MB,
總之,通過設定table.setAutoFlush(false)
和table.setWriteBufferSize()
方法,可以控制AutoFlush行為和客戶端寫緩沖區大小,以優化寫入性能和資料重繪的策略,根據具體的應用需求和場景,可以進行適當的配置調整,
引數優化
Zookeeper 會話超時時間
屬性:zookeeper.session.timeout
解釋:默認值為 90000 毫秒(90s),當某個 RegionServer 掛掉,90s 之后 Master 才能察覺到,可適當減小此值,盡可能快地檢測 regionserver 故障,可調整至 20-30s,看你能有都能忍耐超時,同時可以調整重試時間和重試次數
hbase.client.pause(默認值 100ms)
hbase.client.retries.number(默認 15 次)
設定 RPC 監聽數量
屬性:hbase.regionserver.handler.count
解釋:默認值為 30,用于指定 RPC 監聽的數量,可以根據客戶端的請求數進行調整,讀寫請求較多時,增加此值,
手動控制 Major Compaction
屬性:hbase.hregion.majorcompaction
解釋:默認值:604800000 秒(7 天), Major Compaction 的周期,若關閉自動 Major Compaction,可將其設為 0,如果關閉一定記得自己手動合并,因為大合并非常有意義,
優化 HStore 檔案大小
屬性:hbase.hregion.max.filesize
解釋:默認值 10737418240(10GB),如果需要運行 HBase 的 MR 任務,可以減小此值,因為一個 region 對應一個 map 任務,如果單個 region 過大,會導致 map 任務執行時間,過長,該值的意思就是,如果 HFile 的大小達到這個數值,則這個 region 會被切分為兩個 Hfile,
優化 HBase 客戶端快取
屬性:hbase.client.write.buffer
解釋:默認值 2097152bytes(2M)用于指定 HBase 客戶端快取,增大該值可以減少 RPC呼叫次數,但是會消耗更多記憶體,反之則反之,一般我們需要設定一定的快取大小,以達到減少 RPC 次數的目的,
指定 scan.next 掃描 HBase 所獲取的行數
屬性:hbase.client.scanner.caching
解釋:用于指定 scan.next 方法獲取的默認行數,值越大,消耗記憶體越大,
SpringBoot中使用HBase
添加 Maven 依賴:
<!-- HBase 2.4.3 依賴 -->
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase-client</artifactId>
<version>2.4.3</version>
</dependency>
配置 HBase 連接:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
@Configuration
public class HBaseConfig {
@Bean
public Connection hbaseConnection() throws IOException {
Configuration config = HBaseConfiguration.create();
config.set("hbase.zookeeper.quorum", "localhost"); // HBase ZooKeeper 地址
config.set("hbase.zookeeper.property.clientPort", "2181"); // HBase ZooKeeper 埠
return ConnectionFactory.createConnection(config);
}
}
撰寫增刪改查代碼:
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class HBaseService {
@Autowired
private Connection hbaseConnection;
//添加資料
public void putData(String tableName, String rowKey, String columnFamily, String column, String value) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(columnFamily), Bytes.toBytes(column), Bytes.toBytes(value));
table.put(put);
table.close();
}
//洗掉資料
public void deleteData(String tableName, String rowKey) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Delete delete = new Delete(Bytes.toBytes(rowKey));
table.delete(delete);
table.close();
}
//獲取資料
public String getData(String tableName, String rowKey, String columnFamily, String column) throws IOException {
Table table = hbaseConnection.getTable(TableName.valueOf(tableName));
Get get = new Get(Bytes.toBytes(rowKey));
Result result = table.get(get);
byte[] valueBytes = result.getValue(Bytes.toBytes(columnFamily), Bytes.toBytes(column));
table.close();
return Bytes.toString(valueBytes);
}
}
在上述代碼中,HBaseConfig
類配置了 HBase 連接,通過 hbaseConnection()
方法創建 HBase 連接,HBaseService
類提供了 putData()
、deleteData()
和 getData()
方法,分別用于插入資料、洗掉資料和獲取資料,
Scan
以下是使用Scan 操作的示例代碼:
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;
import java.io.IOException;
public class HBaseScanExample {
public static void main(String[] args) throws IOException {
// 創建 HBase 配置物件
Configuration conf = HBaseConfiguration.create();
// 創建 HBase 連接
Connection connection = ConnectionFactory.createConnection(conf);
// 獲取表物件
TableName tableName = TableName.valueOf("your_table_name");
Table table = connection.getTable(tableName);
// 創建 Scan 物件
Scan scan = new Scan();
scan.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("col1")); // 指定要查詢的列族和列
// 執行 Scan 操作
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
// 處理每一行資料
byte[] row = result.getRow();
byte[] value = https://www.cnblogs.com/booksea/p/result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("col1"));
System.out.println("Row key: " + Bytes.toString(row) + ", Value: " + Bytes.toString(value));
}
// 關閉資源
scanner.close();
table.close();
connection.close();
}
}
在上述代碼中,首先創建 HBase 配置物件 Configuration
,然后通過 ConnectionFactory
創建 HBase 連接 Connection
,接下來,通過連接獲取表物件 Table
,指定要進行 Scan 操作的表名,然后創建 Scan
物件,并使用 addColumn
方法指定要查詢的列族和列,最后,使用 getScanner
方法執行 Scan 操作,并遍歷 ResultScanner
獲取每一行的資料,并進行處理,
Phoenix
Phoenix是一個開源的基于Apache HBase的關系型資料庫引擎,它提供了SQL介面來訪問HBase中存盤的資料,它在HBase的基礎上添加了SQL查詢和事務功能,使得使用HBase的開發者可以使用熟悉的SQL語言進行資料操作和查詢,
Phoenix在HBase中的主要用途包括:
- SQL查詢:Phoenix允許開發者使用標準的SQL陳述句來查詢和操作HBase中的資料,無需撰寫復雜的HBase API代碼,這簡化了開發程序,降低了使用HBase進行資料訪問的門檻,
- 索引支持:Phoenix提供了對HBase資料的二級索引支持,開發者可以使用SQL陳述句創建索引,從而加快查詢速度,索引在資料查詢和過濾中起到重要的作用,提高了資料的檢索效率,
- 事務支持:Phoenix引入了基于MVCC(多版本并發控制)的事務機制,使得在HBase中進行復雜的事務操作成為可能,開發者可以通過Phoenix的事務功能來保證資料的一致性和可靠性,
- SQL函式和聚合:Phoenix支持各種內置的SQL函式和聚合函式,如SUM、COUNT、MAX、MIN等,使得在HBase上進行資料統計和分析變得更加方便,
要在HBase中使用Phoenix,需要先安裝并配置好Phoenix,以下是一個在HBase中使用Phoenix的示例代碼:
- 添加 Maven 依賴: 在 Maven 專案的
pom.xml
檔案中添加以下依賴:
<!-- Phoenix 依賴 -->
<dependency>
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core</artifactId>
<version>4.16.0-HBase-2.4</version>
</dependency>
- 創建 Phoenix 表: 在 HBase 中創建 Phoenix 表,可以使用 Phoenix 提供的 SQL 語法創建表和定義模式,例如,創建一個名為
users
的表:
CREATE TABLE users (
id BIGINT PRIMARY KEY,
name VARCHAR,
age INTEGER
);
- 使用 Phoenix 進行操作: 在 Java 代碼中,可以使用 Phoenix 提供的
PhoenixConnection
和PhoenixStatement
來執行 SQL 操作,
import java.sql.*;
public class PhoenixExample {
public static void main(String[] args) throws SQLException {
// 創建 Phoenix 連接
String url = "jdbc:phoenix:<HBase ZooKeeper Quorum>:<HBase ZooKeeper Port>";
Connection connection = DriverManager.getConnection(url);
// 執行 SQL 查詢
String query = "SELECT * FROM users";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);
// 處理查詢結果
while (resultSet.next()) {
long id = resultSet.getLong("ID");
String name = resultSet.getString("NAME");
int age = resultSet.getInt("AGE");
System.out.println("ID: " + id + ", Name: " + name + ", Age: " + age);
}
// 關閉資源
resultSet.close();
statement.close();
connection.close();
}
}
在上述代碼中,需要將 <HBase ZooKeeper Quorum>
和 <HBase ZooKeeper Port>
替換為你的 HBase ZooKeeper 地址和埠,
通過創建 PhoenixConnection
并傳遞正確的 JDBC URL,可以獲得連接物件,接下來,可以使用 createStatement()
方法創建 PhoenixStatement
物件,并使用 executeQuery()
方法執行 SQL 查詢,
然后,可以使用 ResultSet
物件遍歷查詢結果,并提取所需的欄位,在此示例中,遍歷了 users
表的結果,并列印了每行的 ID、Name 和 Age,
本篇文章就到這里,感謝閱讀,如果本篇博客有任何錯誤和建議,歡迎給我留言指正,文章持續更新,可以關注公眾號第一時間閱讀,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/554938.html
標籤:Java
上一篇:分庫分表用這個就夠了
下一篇:返回列表