文章目錄
什麼導致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;
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常優用化
-預先分區 -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文件配置加載, 一般這樣的協處理器是系統級別的.
-
Shell加載: 可以通過alter命令來對錶進行schema修改來加載協處理器
-
shell加載;jar包|全類名|優先級(會自動分配)|協處理器相關參數
首先對regionobserver進行編譯 mvn clean install
上傳到hdfs集羣中
測試協處理器
-
通過api代碼加載: 即通過api的方式來加載協處理器
配置文件加載
Hbase卸載/更新協處理器
- 重複加載的第二個coprocessor實例不會發揮作用
- 要完成卸載/更新就需要重啓JVM, 也就是重啓regionserver