文章目錄
-
- Hbase概念
-
- Hbase資料存儲過程·
- compaction分兩種:
- compact促發條件:
- Hbase優化政策
-
- hbase優化
- HBase優化政策一:服務端優化政策
- HBase優化政策二:常用優化政策
- HBase優化政策三:讀寫優化政策
- HBase協處理器簡介
- HBase實戰:開發RegionObserver協處理器
- HBase實戰:HBase協處理器加載
什麼導緻hbase性能下降?
- jvm記憶體配置設定與gc回收政策
- 與hbase運作機制相關的部配置設定置不合理
- 表結構設計及使用者使用方式不合理
Hbase概念
Hbase資料存儲過程·
- Hbase寫入時當memstore達到一定的大小會flush到磁盤儲存成 HFile, 當hfile小檔案太多會執行compact操作進行合并。(當一個hstore裡隻包含一個hfile時;查詢效率才是最大化。因為hfile小檔案過多會影響查詢時長,合并後才可以提高查詢效率。)
- 當region的大小達到某一門檻值之後, 會執行split操作
compaction分兩種:
- Minor compaction: 選取一些小的 、 相鄰的storefile将他們合并成一個更大的storefile
- Major compaction: 将所有的storefile合并成一個storefile, 清理無意義資料、被删除的資料、ttl過期資料 、 版本号超過設定版本号的資料;資源消耗最大。
- Split: 當一個region達到一定的大小就會自動split成兩個region
compact促發條件:
- Memstore被flush到磁盤,
- 使用者執行shell指令compact, Major_compact 或者調用了相應的api
- Hbase背景線程周期性觸發檢查
Hbase優化政策
hbase優化
- 常見服務端配置優化
- 常用優化政策 (以實際需求為主)
- Hbase讀/寫性能優化
HBase優化政策一:服務端優化政策
- Jvm設定與gc設定
-
hbase-site. xml 部分屬性配置
max.filesize預設10G;
majorcompaction預設1天建議0,通過手動合并,因為需要用到很長時間;
min預設3;
--- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 cache.size在偏向讀的業務當中可以适當調大一些。
flush.size可以設定大一點;
block.multiplier建議設定成5;如果太大會有記憶體溢出的危險。
(hbase.hstore.blockingStoreFiles:預設為7,如果任何一個store(非.META.表裡的store)的storefile的檔案數大于該值,則在flush memstore前先進行split或者compact,同時把該region添加到flushQueue,延時重新整理,這期間會阻塞寫操作直到compact完成或者超過hbase.hstore.blockingWaitTime(預設90s)配置的時間,可以設定為30,避免memstore不及時flush。當regionserver運作日志中出現大量的“Region <regionName> has too many store files; delaying flush up to 90000ms"時,說明這個值需要調整了)--- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載
HBase優化政策二:常用優化政策
HBase常優用化
-預先分區 -RowKey優化 -Column優化 -Schema優化
- 預先分區
- 建立hbase表的時候會自動建立一個region分區(hbase預設建一個regionserver上建region;後期資料大會分為兩個region)
- 建立hbase表的時候預先建立一些空的regions(減少io操作;通過預先分區;解決資料傾斜問題;将頻繁通路的資料放到多個region中;将不常通路的分區放到一個或幾個region中)
- Rowkey優化
- 利用hbase預設排序特點, 将一起通路的資料放到一起
- 防止熱點問題(大量的client集中通路一個節點), 避免使用時序或者單調的遞增遞減等
- Column優化
- 列族的名稱和列的描述命名盡量簡短(過長會占據記憶體空間)
- 同一張表中columnfamily的數量不要超過 3 個
- Schema優化
- 寬表: 一種 “列多行少” 的設計(事物性能好;hbase的事物建立在行的基礎上的;行少插入的時候可以有很好的保障)
-
高表: 一種 “列少行多” 的設計(查詢性能好;查詢的條件放入rowkey中我們可以緩存更多的行;中繼資料來講開銷大因為行多rowkey多)
hbase主要在于不必苛刻設計于哪種;主要取決于業務。
HBase優化政策三:讀寫優化政策
- Hbase寫優化政策
- 同步批量送出or異步批量送出
- WAL優化, 是否必須, 持久化等級
預設時同步送出資料的;異步送出是可能丢失一些資料的;在業允許的情況下可以開啟。
WAL預設是開啟的;一方面確定資料緩存丢失了也可以資料恢複;另一方面是為了叢集間的異步複制;更關注寫入的吞吐量的時候可以關閉WAL或者采用異步寫入。
- Hbase讀優化政策
- 用戶端: Scan緩存設定, 批量擷取
- 服務端: blockcache配置是否合理, Hfile是否過多
- 表結構的設計問題
在設定scan檢索的時候可以設定scan的cache;scan在檢索的時候不會一次将資料加載到本地;而是多次rpc請求加載(防止影響其他業務或者資料量大造成記憶體溢出);cache預設100條大小設定的大一點可以減少rpc的請求資料次數。
查詢資料的時候blockcache如果不能命中;還要去Hfile裡拉取資料。
Hfile不能過多;過多會導緻查詢緩慢;需要compact合并。
HBase協處理器簡介
- HBase coprocessor
- Hbase協處理器受bigtable協處理器的啟發, 為使用者提供類庫和運作時環境, 使得代碼能夠在hbase regionserver和master上處理
- 系統協處理器and表協處理器(coprocessor分為兩類協處理器)
- Observer and Endpoint(HBase 提供的coprocessor插件)
- 系統協處理器: 全局加載到regionserver托管的所有表和region上(針對整個叢集)
- 表協處理器: 使用者可以指定一張表使用協處理器(針對單張表)
- 觀察者 (Observer): 類似于關系資料庫的觸發器
- 終端 (Endpoint): 動态的終端有點像存儲過程
- Observer
- Regionobserver: 提供用戶端的資料操縱事件鈎子: Get, Put,Delete, Scan等
- Masterobserver: 提供DDL類型的操作鈎子。如建立、删除修改資料表等
- Walobserver: 提供wal相關操作鈎子
- Observer應用場景
- 安全性: 例如執行get或put操作前, 通過preget或preput方法檢查, 是否允許該操作
- 引用完整性限制: hbase并不支援關系型資料庫中的引用完整性限制概念, 即通常所說的外鍵;我們可以使用協處理器增強這種限制
- Endpoint
- endpoint是動态rpc插件的接口, 它的實作代碼被安裝在伺服器端, 進而能夠通過hbase Rpc喚醒
- 調用接口, 它們的實作代碼會被目标regionserver遠端執行·
- 典型的案例: 一個大table有幾百個region, 需要計算某列的平均值或者總和
HBase實戰:開發RegionObserver協處理器
◆實作一個endpoint類型的協處理器
- 待整理
◆實作一個regionobserver類型的協處理器
package com.kun.hbase;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.CoprocessorEnvironment;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Durability;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
import org.apache.hadoop.hbase.coprocessor.ObserverContext;
import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
import org.apache.hadoop.hbase.util.Bytes;
/**
* Created by jixin on 18-2-25.
*/
public class RegionObserverTest extends BaseRegionObserver {
private byte[] columnFamily = Bytes.toBytes("cf");
private byte[] countCol = Bytes.toBytes("countCol");
private byte[] unDeleteCol = Bytes.toBytes("unDeleteCol");
private RegionCoprocessorEnvironment environment;
//regionserver 打開region前執行
@Override
public void start(CoprocessorEnvironment e) throws IOException {
environment = (RegionCoprocessorEnvironment) e;
}
//RegionServer關閉region前調用
@Override
public void stop(CoprocessorEnvironment e) throws IOException {
}
/**
* 需求一
* 1. cf:countCol 進行累加操作。 每次插入的時候都要與之前的值進行相加
* 需要重載prePut方法
*/
@Override
public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit,
Durability durability) throws IOException {
if (put.has(columnFamily, countCol)) {//擷取old countcol value
Result rs = e.getEnvironment().getRegion().get(new Get(put.getRow()));
int oldNum = 0;
for (Cell cell : rs.rawCells()) {
if (CellUtil.matchingColumn(cell, columnFamily, countCol)) {
oldNum = Integer.valueOf(Bytes.toString(CellUtil.cloneValue(cell)));
}
}
//擷取new countcol value
List<Cell> cells = put.get(columnFamily, countCol);
int newNum = 0;
for (Cell cell : cells) {
if (CellUtil.matchingColumn(cell, columnFamily, countCol)) {
newNum = Integer.valueOf(Bytes.toString(CellUtil.cloneValue(cell)));
}
}
//sum AND update Put執行個體
put.addColumn(columnFamily, countCol, Bytes.toBytes(String.valueOf(oldNum + newNum)));
}
}
/**
* 需求二
* 2. 不能直接删除unDeleteCol 删除countCol的時候将unDeleteCol一同删除
* 需要重載preDelete方法
*/
@Override
public void preDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete,
WALEdit edit,
Durability durability) throws IOException {
//判斷是否操作删除了cf列族
List<Cell> cells = delete.getFamilyCellMap().get(columnFamily);
if (cells == null || cells.size() == 0) {
return;
}
boolean deleteFlag = false;
for (Cell cell : cells) {
byte[] qualifier = CellUtil.cloneQualifier(cell);
if (Arrays.equals(qualifier, unDeleteCol)) {
throw new IOException("can not delete unDel column");
}
if (Arrays.equals(qualifier, countCol)) {
deleteFlag = true;
}
}
if (deleteFlag) {
delete.addColumn(columnFamily, unDeleteCol);
}
}
}
HBase實戰:HBase協處理器加載
- 待整理
- 配置檔案加載: 即通過hbase-site. Xml檔案配置加載, 一般這樣的協處理器是系統級别的.
--- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 - Shell加載: 可以通過alter指令來對表進行schema修改來加載協處理器
- shell加載;jar包|全類名|優先級(會自動配置設定)|協處理器相關參數
--- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 首先對regionobserver進行編譯 mvn clean install
上傳到hdfs叢集中
測試協處理器
--- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 --- HBase學習筆記 (叁)- HBase進階HBase協處理器簡介HBase實戰:開發RegionObserver協處理器HBase實戰:HBase協處理器加載 -
通過api代碼加載: 即通過api的方式來加載協處理器
配置檔案加載
Hbase解除安裝/更新協處理器
- 重複加載的第二個coprocessor執行個體不會發揮作用
- 要完成解除安裝/更新就需要重新開機JVM, 也就是重新開機regionserver