> For the complete documentation index, see [llms.txt](https://www.selinux.tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://www.selinux.tech/java/core/jvm-hbase.md).

# JVM 与 Hbase

* [HBase 调整G1GC](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#hbase-调整g1gc)
  * [HBase的G1GC](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#hbase的g1gc)
  * [参数配置](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#参数配置)
  * [如何调整HBase集群](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#如何调整hbase集群)
    * [开始之前: GC and HBase monitoring](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#开始之前-gc-and-hbase-monitoring)
    * [Step 0：推荐默认值](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#step-0推荐默认值)
    * [Step 1:确定预期的HBase最大使用率](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#step-1确定预期的hbase最大使用率)
    * [Step 2: 设置堆大小，IHOP和Eden大小](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#step-2-设置堆大小ihop和eden大小)
    * [Step 3:根据使用上限调整HBase配置](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#step-3根据使用上限调整hbase配置)
    * [Step 4: 配置其他建议的参数以提高GC的性能](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#step-4-配置其他建议的参数以提高gc的性能)
    * [Run it](/java/core/jvm-hbase.md#run-it)
  * [其他参考](https://www.selinux.tech/java/core/pages/-LggfkvjQQpeojTzey2Q#其他参考)

前面我们介绍过，G1GC 是现在比较流行的JVM 垃圾回收。所以，我们就结合G1GC 来讨论下Hadoop的GC。

## HBase的G1GC

首先，我们本篇文章的主要依据就是官方的blog。<https://blogs.apache.org/hbase/entry/tuning_g1gc_for_your_hbase>

鉴于已经有官方blog作为资料，并且实验环境并不是很充足，所以我们直接叙述结论。

## 参数配置

首先看下，我们实际工作中的HBase的参数配置。以及各项参数的实际含义。

| 参数                               | 含义                                                                                 |
| -------------------------------- | ---------------------------------------------------------------------------------- |
| -XX:+UseG1GC                     | 显式地要求使用G1 GC                                                                       |
| -Xms64G                          | 设置JVM初始堆内存为64G                                                                     |
| -Xmx64G                          | 设置JVM最大可用内存为64G                                                                    |
| -XX:PermSize=256m                | JVM初始分配的非堆内存                                                                       |
| -XX:G1NewSizePercent=4           | 新生代最小值，默认值5%                                                                       |
| -XX:MaxGCPauseMillis=200         | 设置G1收集过程目标时间，默认值200ms，不是硬性条件                                                       |
| -XX:ParallelGCThreads=16         | STW期间，并行GC线程数                                                                      |
| -XX:MaxTenuringThreshold=4       | 年龄阈值，默认15（对象被复制的次数）                                                                |
| -XX:+UnlockExperimentalVMOptions | 与+UseG1GC 一起使用,来解锁参数,应该是一种安全机制                                                     |
| -XX:+ParallelRefProcEnabled      | 默认为false，并行的处理Reference对象，如WeakReference，除非在GC log里出现Reference处理时间较长的日志，否则效果不会很明显。 |
| -XX:-ResizePLAB                  | 是否启动动态修改                                                                           |

## 如何调整HBase集群

### 开始之前: GC and HBase monitoring

可以使用任何工具跟踪收集 `block cache`, `memstore` 和 `static index size` 这些指标，可以从 `RegionServer JMX metrics` 中找到。

* “memStoreSize”
* “blockCacheSize”
* “staticIndexSize”

还可以使用官方的 `collectd` 插件来跟踪一段时间内的G1GC性能,并使用 `gc_log_visualizer`来了解特定的GC日志。要使用这些内容就要在 RegionServers 上跟踪这些信息。

* -Xloggc:$GC\_LOG\_PATH
* -verbosegc
* -XX:+PrintGC
* -XX:+PrintGCDateStamps
* -XX:+PrintAdaptiveSizePolicy
* -XX:+PrintGCDetails
* -XX:+PrintGCApplicationStoppedTime
* -XX:+PrintTenuringDistribution

还建议使用某种GC日志轮换，例如:

* -XX：+ UseGCLogFileRotation
* -XX：NumberOfGCLogFiles = 5
* -XX：GCLogFileSize = 20M

### Step 0：推荐默认值

建议将以下JVM参数和值作为HBase RegionServers的默认值:

* -XX：+ UseG1GC
* -XX：+ UnlockExperimentalVMOptions
* -XX：MaxGCPauseMillis = 50
* -XX：-OmitStackTraceInFastThrow
* -XX：ParallelGCThreads = 8+（逻辑处理器-8）
* -XX：+ ParallelRefProcEnabled
* -XX：+ PerfDisableSharedMem
* -XX：-ResizePLAB

### Step 1:确定预期的HBase最大使用率

使用上面提到的RegionServer JMX指标，查找整个集群中每个指标的最大值

* Maximum block cache size.
* Maximum memstore size.
* Maximum static index size.

将每个最大值扩展到 110%，以适应最大使用值的轻微增幅。这是该指标的使用上限: 例如最大10 GB记录的memstore→11 GB memstore上限.

理想情况下，在过去一周或一个月内跟踪这些指标，就可以找到该时间段内的最大值。如果不是，在计算 memstore和static index size 上限时要比110％ 更高一些。尤其是 Memstore，随着时间的推移，可能会变的更大。

### Step 2: 设置堆大小，IHOP和Eden大小

先从比较低的 Eden 大小开始设置：如果不是很确定，8% 的堆的大小就可以。

```java
-XX:G1NewSizePercent = 8
```

* 增加Eden大小会增加单个GC pause 时间，但会略微减少GC中花费的总时间。
* 减小Eden大小会产生相反的效果：GC pause 时间越短，GC中的总体时间略长。

用Step 1中的Eden大小和使用上限确定必要的堆大小:

Heap ≥ (M + B + O + E) ÷ 0.7

* M = memstore cap, GB
* B = block cache cap, GB
* O = static index cap, GB
* E = Eden size, GB

根据计算的值设置固定堆大小的JVM参数,例如：

```java
-Xms40960m -Xmx40960m
```

根据使用上限和堆大小在JVM中设置IHOP:

* IHOP = (memstore cap’s % heap + block cache cap’s % heap + overhead cap’s % heap + 20)
* -XX:InitiatingHeapOccupancyPercent = IHOP

### Step 3:根据使用上限调整HBase配置

根据使用上限和总堆大小,在 HBase 配置中设置 `block cache` 上限 和 `memstore` 上限比率:

* hfile.block.cache.size → block cache cap ÷ heap size
* hbase.regionserver.global.memstore.size → memstore cap ÷ heap size

### Step 4: 配置其他建议的参数以提高GC的性能

* -XX:MaxTenuringThreshold = 1
* -XX:G1HeapWastePercent = 10
* -XX:G1MixedGCCountTarget = 16
* -XX:G1HeapRegionSize = #M  #必须是2的幂，在\[1..32]范围内,理想情况下，＃是这样的：堆大小÷＃MB = 2048个region。

### Run it

应用这些配置，然后重启RegionServers，看看他们的表现。

* 可以如上所述调整Eden大小，以优化较短的单个GC或减少GC中的总时间,如果这样做，请确保Eden +IHOP≤90％。
* 如果HBase客户端可能有非常突发的流量，可以考虑在IHOP和Eden之外添加堆空间（例如，IHOP + Eden加起来高达80％.

## 其他参考

* [G1GC Fundamentals (HubSpot blog)](https://product.hubspot.com/blog/g1gc-fundamentals-lessons-from-taming-garbage-collection)
* [Understanding G1GC Logs (Oracle blog)](https://blogs.oracle.com/poonam/entry/understanding_g1_gc_logs)
* [Tuning HBase Garbage Collection (Intel blog)](https://blogs.oracle.com/poonam/understanding-g1-gc-logs)
