hbase參數調優


HBase參數調優

hbase.regionserver.handler.count

該設置決定了處理RPC的線程數量,默認值是10,通常可以調大,比如:150,當請求內容很大(上MB,比如大的put、使用緩存的scans)的時候,如果該值設置過大則會占用過多的內存,導致頻繁的GC,或者出現OutOfMemory,因此該值不是越大越好。

hbase.hregion.max.filesize

配置region大小,默認是10G,region大小一般控制在幾個G比較合適,可以在建表時規划好region數量,進行預分區,做到一定時間內,每個region的數據大小在一定的數據量之下,當發現有大的region,或者需要對整個表進行region擴充時再進行split操作,一般提供在線服務的hbase集群均會棄用hbase的自動split,轉而自己管理split。

hbase.hregion.majorcompaction

配置major合並的間隔時間,默認值604800000,單位ms。表示major compaction默認7天調度一次,HBase 0.96.x及之前默認為1天調度一次,設置為 0 時表示禁用自動觸發major compaction。一般major compaction持續時間較長、系統資源消耗較大,對上層業務也有比較大的影響,一般生產環境下為了避免影響讀寫請求,會禁用自動觸發major compaction,可手動或者通過腳本定期進行major合並。

hbase.hstore.compaction.min

默認值 3,一個列族下的HFile數量超過該值就會觸發Minor Compaction,這個參數默認值小了,一般情況下建議調大到5~10之間,注意相應調整下一個參數

hbase.hstore.compaction.max

默認值 10,一次Minor Compaction最多合並的HFile文件數量,這個參數基本控制着一次壓縮即Compaction的耗時。這個參數要比上一個參數hbase.hstore.compaction.min值大,通常是其2~3倍。

hbase.hstore.blockingStoreFiles

默認值 10,一個列族下HFile數量達到該值,flush操作將會受到阻塞,阻塞時間為hbase.hstore.blockingWaitTime,默認90000,即1.5分鍾,在這段時間內,如果compaction操作使得HFile下降到blockingStoreFiles配置值,則停止阻塞。另外阻塞超過時間后,也會恢復執行flush操作。這樣做可以有效地控制大量寫請求的速度,但同時這也是影響寫請求速度的主要原因之一。生產環境中默認值太小了,一般建議設置大點比如100,避免出現阻塞更新的情況

hbase.regionserver.global.memstore.size(重)

默認值0.4,RS所有memstore占用內存在總內存中的比例,當達到該值,則會從整個RS中找出最需要flush的region進行flush,直到總內存比例降至該數限制以下,並且在降至限制比例前,將阻塞所有的寫memstore的操作,在以寫為主的集群中,可以調大該配置項,不建議太大,因為block cache和memstore cache的總大小不會超過0.8,而且不建議這兩個cache的大小總和達到或者接近0.8,避免OOM,在偏向寫的業務時,可配置為0.45

hbase.regionserver.global.memstore.size.lower.limit(重)

默認值0.95,相當於上一個參數的0.95
如果有 16G 堆內存,默認情況下:

  • # 達到該值會觸發刷寫
    16 * 0.4 * 0.95 = 6.08
    # 達到該值會觸發阻塞
    16 * 0.4 = 6.4
    
新參數 老參數
hbase.regionserver.global.memstore.size hbase.regionserver.global.memstore.upperLimit
hbase.regionserver.global.memstore.size.lower.limit hbase.regionserver.global.memstore.lowerLimit

hfile.block.cache.size(重)

RS的block cache的內存大小限制,默認值0.4,在偏向讀的業務中,可以適當調大該值,具體配置時需試hbase集群服務的業務特征,結合memstore的內存占比進行綜合考慮。

hbase.hregion.memstore.flush.size(重)

默認值128M,單位字節,超過將被flush到hdfs,該值比較適中,一般不需要調整。

hbase.hregion.memstore.block.multiplier

默認值4,如果memstore的內存大小已經超過了hbase.hregion.memstore.flush.size的4倍,則會阻塞memstore的寫操作,直到降至該值以下,為避免發生阻塞,最好調大該值,比如:6,不可太大,如果太大,則會增大導致整個RS的memstore內存超過global.memstore.size限制的可能性,進而增大阻塞整個RS的寫的幾率,如果region發生了阻塞會導致大量的線程被阻塞在到該region上,從而其它region的線程數會下降,影響整體的RS服務能力。

hbase.regionserver.regionSplitLimit

控制最大的region數量,超過則不可以進行split操作,默認是Integer.MAX(2147483647),可設置為1,禁止自動的split,通過人工,或者寫腳本在集群空閑時執行。如果不禁止自動的split,則當region大小超過hbase.hregion.max.filesize時會觸發split操作(具體的split有一定的策略,不僅僅通過該參數控制,前期的split會考慮region數據量和memstore大小),每次flush或者compact之后,regionserver都會檢查是否需要Split,split會先下線老region再上線split后的region,該過程會很快,但是會存在兩個問題:1、老region下線后,新region上線前client訪問會失敗,在重試過程中會成功但是如果是提供實時服務的系統則響應時長會增加;2、split后的compact是一個比較耗資源的動作。

hbase.regionserver.maxlogs

默認值32,HLOG最大的數量

hbase.regionserver.hlog.blocksize

默認為 2 倍的HDFS block size(128MB),即256MB

JVM調整:

內存大小:master默認為1G,可增加到2G,regionserver默認1G,可調大到10G,或者更大,zk並不耗資源,可以不用調整,需要注意的是,調整了rs的內存大小后,需調整hbase.regionserver.maxlogs和hbase.regionserver.hlog.blocksize這兩個參數,WAL的最大值由hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize決定(默認32*2*128M=8G),一旦達到這個值,就會被觸發flush memstore,如果memstore的內存增大了,但是沒有調整這兩個參數,實際上對大量小文件沒有任何改進,調整策略:hbase.regionserver.hlog.blocksize * hbase.regionserver.maxlogs 設置為略大於hbase.regionserver.global.memstore.size* HBASE_HEAPSIZE。


什么時候觸發 MemStore Flush?(重)

有很多情況會觸發 MemStore 的 Flush 操作,主要有以下幾種情況:

  • Region 中任意一個 MemStore 占用的內存超過相關閾值 128MB會刷

    ​ 當一個 Region 中所有 MemStore 占用的內存大小超過刷寫閾值的時候會觸發一次刷寫,這個閾值由 hbase.hregion.memstore.flush.size 參數控制,默認為128MB。我們每次調用 put、delete 等操作都會檢查的這個條件的。

    ​ 但是如果我們的數據增加得很快,達到了 hbase.hregion.memstore.flush.size * hbase.hregion.memstore.block.multiplier 的大小,hbase.hregion.memstore.block.multiplier 默認值為4,也就是128*4=512MB的時候,那么除了觸發 MemStore 刷寫之外,HBase 還會在刷寫的時候同時阻塞所有寫入該 Store 的寫請求!這時候如果你往對應的 Store 寫數據,會出現 RegionTooBusyException 異常。

  • 整個 RegionServer 的 MemStore 占用內存總和大於相關閾值 達到40%會刷新

    ​ 如果達到了 RegionServer 級別的 Flush,那么當前 RegionServer 的所有寫操作將會被阻塞,而且這個阻塞可能會持續到分鍾級別。

  • WAL數量大於相關閾值或WAL的大小超過一定閾值 數量或者大小超過一定閾值會刷

    ​ 如果設置了 hbase.regionserver.maxlogs,那就是這個參數的值;否則是 max(32, hbase_heapsize * hbase.regionserver.global.memstore.size * 2 / logRollSize)

    (logRollSize 默認大小為:0.95 * HDFS block size)

    如果某個 RegionServer 的 WAL 數量大於 maxLogs 就會觸發 MemStore 的刷寫。

    ​ WAL的最大值由hbase.regionserver.maxlogs * hbase.regionserver.hlog.blocksize決定(默認32*2*128M=8G),一旦達到這個值,就會被觸發flush memstore,如果memstore的內存增大了,但是沒有調整這兩個參數,實際上對大量小文件沒有任何改進,調整策略:hbase.regionserver.hlog.blocksize * hbase.regionserver.maxlogs 設置為略大於hbase.regionserver.global.memstore.size* HBASE_HEAPSIZE。

  • 定期自動刷寫

    ​ 如果我們很久沒有對 HBase 的數據進行更新,這時候就可以依賴定期刷寫策略了。RegionServer 在啟動的時候會啟動一個線程 PeriodicMemStoreFlusher 每隔 hbase.server.thread.wakefrequency 時間(服務線程的sleep時間,默認10000毫秒)去檢查屬於這個 RegionServer 的 Region 有沒有超過一定時間都沒有刷寫,這個時間是由 hbase.regionserver.optionalcacheflushinterval 參數控制的,默認是 3600000,也就是1小時會進行一次刷寫。如果設定為0,則意味着關閉定時自動刷寫。

    ​ 為了防止一次性有過多的 MemStore 刷寫,定期自動刷寫會有 0 ~ 5 分鍾的延遲

  • 數據更新超過一定閾值

    如果 HBase 的某個 Region 更新的很頻繁,而且既沒有達到自動刷寫閥值,也沒有達到內存的使用限制,但是內存中的更新數量已經足夠多,比如超過 hbase.regionserver.flush.per.changes 參數配置,默認為30000000,那么也是會觸發刷寫的。

  • 手動觸發刷寫

    分別對某張表、某個 Region 進行刷寫操作。

    可以在 Shell 中執行 flush 命令


什么操作會觸發 MemStore 刷寫?

常見的 put、delete、append、incr、調用 flush 命令、Region 分裂、Region Merge、bulkLoad HFiles 以及給表做快照操作都會對上面的相關條件做檢查,以便判斷要不要做刷寫操作。

MemStore 刷寫策略(FlushPolicy)

在 HBase 1.1 之前,MemStore 刷寫是 Region 級別的。就是說,如果要刷寫某個 MemStore ,MemStore 所在的 Region 中其他 MemStore 也是會被一起刷寫的!(Flush風暴)這會造成一定的問題,比如小文件問題。可以通過 hbase.regionserver.flush.policy 參數選擇不同的刷寫策略。

目前 HBase 2.x 的刷寫策略全部都是實現 FlushPolicy 抽象類的。並且自帶三種刷寫策略:FlushAllLargeStoresPolicy、FlushNonSloppyStoresFirstPolicy 以及 FlushAllStoresPolicy。

  • FlushAllStoresPolicy

    這種刷寫策略實現最簡單,直接返回當前 Region 對應的所有 MemStore。也就是每次刷寫都是對 Region 里面所有的 MemStore 進行的,這個行為和 HBase 1.1 之前是一樣的。

  • FlushAllLargeStoresPolicy

    在 HBase 2.0 之前版本是 FlushLargeStoresPolicy,后面被拆分成分 FlushAllLargeStoresPolicy 和FlushNonSloppyStoresFirstPolicy

    這種策略會先判斷 Region 中每個 MemStore 的使用內存是否大於某個閥值,大於這個閥值的 MemStore 將會被刷寫

    hbase.hregion.percolumnfamilyflush.size.lower.bound.min 默認值為 16MB

    hbase.hregion.percolumnfamilyflush.size.lower.bound 沒有默認值,計算規則如下:

    比如當前表有3個列族,那么 flushSizeLowerBound = max((long)128 / 3, 16) = 42。

    如果 Region 中沒有 MemStore 的使用內存大於上面的閥值,FlushAllLargeStoresPolicy 策略就退化成 FlushAllStoresPolicy 策略了,也就是會對 Region 里面所有的 MemStore 進行 Flush。

  • FlushNonSloppyStoresFirstPolicy

    HBase 2.0 引入了 in-memory compaction,如果我們對相關列族hbase.hregion.compacting.memstore.type 參數的值不是 NONE,那么這個 MemStore 的 isSloppyMemStore 值就是 true,否則就是 false。

    FlushNonSloppyStoresFirstPolicy 策略將 Region 中的 MemStore 按照 isSloppyMemStore 分到兩個 HashSet 里面(sloppyStores 和 regularStores)。然后

    • 判斷 regularStores 里面是否有 MemStore 內存占用大於相關閥值的 MemStore ,有的話就會對這些 MemStore 進行刷寫,其他的不做處理,這個閥值計算和 FlushAllLargeStoresPolicy 的閥值計算邏輯一致。
    • 如果 regularStores 里面沒有 MemStore 內存占用大於相關閥值的 MemStore,這時候就開始在 sloppyStores 里面尋找是否有 MemStore 內存占用大於相關閥值的 MemStore,有的話就會對這些 MemStore 進行刷寫,其他的不做處理。
    • 如果上面 sloppyStores 和 regularStores 都沒有滿足條件的 MemStore 需要刷寫,這時候就 FlushNonSloppyStoresFirstPolicy 策略久退化成 FlushAllStoresPolicy 策略了。

hbase高可用

hbase高可用

HBase調優 BulkLoading

BulkLoading優點:

  1. 如果我們一次性入庫hbase巨量數據,處理速度慢不說,還特別占用Region資源, 一個比較高效便捷的方法就是使用 “Bulk Loading”方法,即HBase提供的HFileOutputFormat類。

  2. 它是利用hbase的數據信息按照特定格式存儲在hdfs內這一原理,直接生成這種hdfs內存儲的數據格式文件,然后上傳至合適位置,即完成巨量數據快速入庫的辦法。配合mapreduce完成,高效便捷,而且不占用region資源,增添負載。

BulkLoading限制:

  1. 僅適合初次數據導入,即表內數據為空,或者每次入庫表內都無數據的情況。

  2. HBase集群與Hadoop集群為同一集群,即HBase所基於的HDFS為生成HFile的MR的集群。

 //hbase shell建表
 create 'dianxin_bulk','info',{SPLITS=>['1|','3|','5|','7|','9|','B|','D|']}

BulkLoading代碼部分

package com.gym.HBase;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.HFileOutputFormat2;
import org.apache.hadoop.hbase.mapreduce.KeyValueSortReducer;
import org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles;
import org.apache.hadoop.hbase.mapreduce.SimpleTotalOrderPartitioner;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;



/**
 * @author 郭玉敏
 * @create 2021-12-05-17:46
 * @create 明天吃烤肉
 */
public class Demo8BulkLoad {

    //繼承TableMapper 是從hbase中讀數據
    //map端
    public static class BulkLoadMapper extends Mapper<LongWritable,Text,ImmutableBytesWritable,KeyValue>{
        @Override
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {


            String[] splits = value.toString().split(",");
            String mdn = splits[0];
            String start_time = splits[1];
            // 經度
            String longitude = splits[4];
            // 緯度
            String latitude = splits[5];

            String rowkey = mdn + "_" + start_time;

            //keyvalue相當於cell
            KeyValue lgkv = new KeyValue(rowkey.getBytes(), "info".getBytes(), "lg".getBytes(), longitude.getBytes());
            KeyValue latkv = new KeyValue(rowkey.getBytes(), "info".getBytes(), "lat".getBytes(), latitude.getBytes());


            context.write(new ImmutableBytesWritable(rowkey.getBytes()),lgkv);
            context.write(new ImmutableBytesWritable(rowkey.getBytes()),latkv);
        }
    }

    //因為不需要計算,reduce任務可以省略

    //driver端
    public static void main(String[] args) throws Exception {
        Configuration conf = HBaseConfiguration.create();
        conf.set("hbase.zookeeper.quorum","master:2181,node1:2181,node2:2181");
        Job job = Job.getInstance();
        job.setJobName("Demo8BulkLoad");
        job.setJarByClass(Demo8BulkLoad.class);

        //該配置不會生效,因為reduce任務的數量由region決定
        job.setNumReduceTasks(4);

        //配置map
        job.setMapperClass(BulkLoadMapper.class);
        job.setMapOutputKeyClass(ImmutableBytesWritable.class);
        job.setMapOutputValueClass(KeyValue.class);

        //保證每個reduce之間的數據不會有重疊,並且是有序的
        job.setPartitionerClass(SimpleTotalOrderPartitioner.class);

        //配置reduce
        //保證在reduce內部是有序的
        job.setReducerClass(KeyValueSortReducer.class);

        //配置輸入輸出路徑
        Path outputPath = new Path("/bulk_load/output1");
        FileSystem fs = FileSystem.get(conf);
        if (fs.exists(outputPath)) {
            fs.delete(outputPath,true);
        }

        FileInputFormat.addInputPath(job,new Path("/bulk_load/input"));
        FileOutputFormat.setOutputPath(job,outputPath);

        Connection conn = ConnectionFactory.createConnection(conf);
        Admin admin = conn.getAdmin();
        Table dianxin_bulk = conn.getTable(TableName.valueOf("dianxin_bulk"));
        RegionLocator regionLocator = conn.getRegionLocator(TableName.valueOf("dianxin_bulk"));

        //第一步:生成Hfile
        // 使用HFileOutputFormat2將輸出的數據按照HFile的形式格式化
        HFileOutputFormat2.configureIncrementalLoad(job,
                dianxin_bulk,
                regionLocator
                );

        boolean flag = job.waitForCompletion(true);

        if (flag){
            //第二步:加載Hfile到Hbase中
            LoadIncrementalHFiles load = new LoadIncrementalHFiles(conf);
            load.doBulkLoad(
                    outputPath,
                    admin,
                    dianxin_bulk,
                    regionLocator
            );

        }else {
            System.out.println("運行失敗");
        }

    }
}

代碼所需要的依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.gym</groupId>
    <artifactId>HBaseTest</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--<dependency>-->
            <!--<groupId>org.apache.hbase</groupId>-->
            <!--<artifactId>hbase-client</artifactId>-->
            <!--<version>1.4.6</version>-->
        <!--</dependency>-->
        <!--<dependency>-->
            <!--<groupId>org.apache.hbase</groupId>-->
            <!--<artifactId>hbase-server</artifactId>-->
            <!--<version>1.4.6</version>-->
        <!--</dependency>-->

    <dependency>
        <groupId>org.apache.phoenix</groupId>
        <artifactId>phoenix-core</artifactId>
        <version>4.15.0-HBase-1.4</version>
    </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>2.7.6</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
    <!--     將依賴打入Jar包-->
    <build>
        <plugins>

            <!-- Java Compiler -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>


            <!-- 帶依賴jar 插件-->
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

打成jar包,上傳至hdfs上,運行
hadoop jar HBaseTest-1.0-SNAPSHOT.jar com.gym.HBase.Demo8BulkLoad

說明

  1. 最終輸出結果,無論是map還是reduce,輸出部分key和value的類型必須是: < ImmutableBytesWritable, KeyValue>或者< ImmutableBytesWritable, Put>。

  2. 最終輸出部分,Value類型是KeyValue 或Put,對應的Sorter分別是KeyValueSortReducer或PutSortReducer。

  3. MR例子中HFileOutputFormat2.configureIncrementalLoad(job, dianxin_bulk, regionLocator);自動對job進行配置。SimpleTotalOrderPartitioner是需要先對key進行整體排序,然后划分到每個reduce中,保證每一個reducer中的的key最小最大值區間范圍,是不會有交集的。因為入庫到HBase的時候,作為一個整體的Region,key是絕對有序的。

  4. MR例子中最后生成HFile存儲在HDFS上,輸出路徑下的子目錄是各個列族。如果對HFile進行入庫HBase,相當於move HFile到HBase的Region中,HFile子目錄的列族內容沒有了,但不能直接使用mv命令移動,因為直接移動不能更新HBase的元數據。

  5. HFile入庫到HBase通過HBase中 LoadIncrementalHFiles的doBulkLoad方法,對生成的HFile文件入庫


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM