3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 package org
.apache
.hadoop
.hbase
.regionserver
;
21 import java
.lang
.management
.MemoryType
;
22 import java
.util
.concurrent
.ConcurrentHashMap
;
23 import java
.util
.concurrent
.ConcurrentMap
;
24 import java
.util
.concurrent
.atomic
.LongAdder
;
26 import org
.apache
.hadoop
.conf
.Configuration
;
27 import org
.apache
.yetus
.audience
.InterfaceAudience
;
28 import org
.apache
.hadoop
.hbase
.io
.util
.MemorySizeUtil
;
29 import org
.apache
.hadoop
.hbase
.util
.Pair
;
32 * RegionServerAccounting keeps record of some basic real time information about
33 * the Region Server. Currently, it keeps record the global memstore size and global memstore
34 * on-heap and off-heap overhead. It also tracks the replay edits per region.
36 @InterfaceAudience.Private
37 public class RegionServerAccounting
{
39 private final LongAdder globalMemStoreDataSize
= new LongAdder();
40 // memstore heap size.
41 private final LongAdder globalMemStoreHeapSize
= new LongAdder();
42 // memstore off-heap size.
43 private final LongAdder globalMemStoreOffHeapSize
= new LongAdder();
45 private long globalMemStoreLimit
;
46 private final float globalMemStoreLimitLowMarkPercent
;
47 private long globalMemStoreLimitLowMark
;
48 private final MemoryType memType
;
49 private long globalOnHeapMemstoreLimit
;
50 private long globalOnHeapMemstoreLimitLowMark
;
52 // encoded region name -> Pair -> read count as first, write count as second.
53 // when region close and target rs is the current server, we will put an entry,
54 // and will remove it when reigon open after recover them.
55 private ConcurrentMap
<String
, Pair
<Long
, Long
>> retainedRegionRWRequestsCnt
;
57 public RegionServerAccounting(Configuration conf
) {
58 Pair
<Long
, MemoryType
> globalMemstoreSizePair
= MemorySizeUtil
.getGlobalMemStoreSize(conf
);
59 this.globalMemStoreLimit
= globalMemstoreSizePair
.getFirst();
60 this.memType
= globalMemstoreSizePair
.getSecond();
61 this.globalMemStoreLimitLowMarkPercent
=
62 MemorySizeUtil
.getGlobalMemStoreHeapLowerMark(conf
, this.memType
== MemoryType
.HEAP
);
63 // When off heap memstore in use we configure the global off heap space for memstore as bytes
64 // not as % of max memory size. In such case, the lower water mark should be specified using the
65 // key "hbase.regionserver.global.memstore.size.lower.limit" which says % of the global upper
66 // bound and defaults to 95%. In on heap case also specifying this way is ideal. But in the past
67 // we used to take lower bound also as the % of xmx (38% as default). For backward compatibility
68 // for this deprecated config,we will fall back to read that config when new one is missing.
69 // Only for on heap case, do this fallback mechanism. For off heap it makes no sense.
70 // TODO When to get rid of the deprecated config? ie
71 // "hbase.regionserver.global.memstore.lowerLimit". Can get rid of this boolean passing then.
72 this.globalMemStoreLimitLowMark
=
73 (long) (this.globalMemStoreLimit
* this.globalMemStoreLimitLowMarkPercent
);
74 this.globalOnHeapMemstoreLimit
= MemorySizeUtil
.getOnheapGlobalMemStoreSize(conf
);
75 this.globalOnHeapMemstoreLimitLowMark
=
76 (long) (this.globalOnHeapMemstoreLimit
* this.globalMemStoreLimitLowMarkPercent
);
77 this.retainedRegionRWRequestsCnt
= new ConcurrentHashMap
<>();
80 long getGlobalMemStoreLimit() {
81 return this.globalMemStoreLimit
;
84 long getGlobalOnHeapMemStoreLimit() {
85 return this.globalOnHeapMemstoreLimit
;
88 // Called by the tuners.
89 void setGlobalMemStoreLimits(long newGlobalMemstoreLimit
) {
90 if (this.memType
== MemoryType
.HEAP
) {
91 this.globalMemStoreLimit
= newGlobalMemstoreLimit
;
92 this.globalMemStoreLimitLowMark
=
93 (long) (this.globalMemStoreLimit
* this.globalMemStoreLimitLowMarkPercent
);
95 this.globalOnHeapMemstoreLimit
= newGlobalMemstoreLimit
;
96 this.globalOnHeapMemstoreLimitLowMark
=
97 (long) (this.globalOnHeapMemstoreLimit
* this.globalMemStoreLimitLowMarkPercent
);
101 boolean isOffheap() {
102 return this.memType
== MemoryType
.NON_HEAP
;
105 long getGlobalMemStoreLimitLowMark() {
106 return this.globalMemStoreLimitLowMark
;
109 float getGlobalMemStoreLimitLowMarkPercent() {
110 return this.globalMemStoreLimitLowMarkPercent
;
114 * @return the global Memstore data size in the RegionServer
116 public long getGlobalMemStoreDataSize() {
117 return globalMemStoreDataSize
.sum();
121 * @return the global memstore heap size in the RegionServer
123 public long getGlobalMemStoreHeapSize() {
124 return this.globalMemStoreHeapSize
.sum();
128 * @return the global memstore heap size in the RegionServer
130 public long getGlobalMemStoreOffHeapSize() {
131 return this.globalMemStoreOffHeapSize
.sum();
135 * @return the retained metrics of region's read and write requests count
137 protected ConcurrentMap
<String
, Pair
<Long
, Long
>> getRetainedRegionRWRequestsCnt() {
138 return this.retainedRegionRWRequestsCnt
;
141 void incGlobalMemStoreSize(MemStoreSize mss
) {
142 incGlobalMemStoreSize(mss
.getDataSize(), mss
.getHeapSize(), mss
.getOffHeapSize());
145 public void incGlobalMemStoreSize(long dataSizeDelta
, long heapSizeDelta
, long offHeapSizeDelta
) {
146 globalMemStoreDataSize
.add(dataSizeDelta
);
147 globalMemStoreHeapSize
.add(heapSizeDelta
);
148 globalMemStoreOffHeapSize
.add(offHeapSizeDelta
);
151 public void decGlobalMemStoreSize(long dataSizeDelta
, long heapSizeDelta
, long offHeapSizeDelta
) {
152 globalMemStoreDataSize
.add(-dataSizeDelta
);
153 globalMemStoreHeapSize
.add(-heapSizeDelta
);
154 globalMemStoreOffHeapSize
.add(-offHeapSizeDelta
);
158 * Return true if we are above the memstore high water mark
159 * @return the flushtype
161 public FlushType
isAboveHighWaterMark() {
162 // for onheap memstore we check if the global memstore size and the
163 // global heap overhead is greater than the global memstore limit
164 if (memType
== MemoryType
.HEAP
) {
165 if (getGlobalMemStoreHeapSize() >= globalMemStoreLimit
) {
166 return FlushType
.ABOVE_ONHEAP_HIGHER_MARK
;
169 // If the configured memstore is offheap, check for two things
170 // 1) If the global memstore off-heap size is greater than the configured
171 // 'hbase.regionserver.offheap.global.memstore.size'
172 // 2) If the global memstore heap size is greater than the configured onheap
173 // global memstore limit 'hbase.regionserver.global.memstore.size'.
174 // We do this to avoid OOME incase of scenarios where the heap is occupied with
175 // lot of onheap references to the cells in memstore
176 if (getGlobalMemStoreOffHeapSize() >= globalMemStoreLimit
) {
177 // Indicates that global memstore size is above the configured
178 // 'hbase.regionserver.offheap.global.memstore.size'
179 return FlushType
.ABOVE_OFFHEAP_HIGHER_MARK
;
180 } else if (getGlobalMemStoreHeapSize() >= this.globalOnHeapMemstoreLimit
) {
181 // Indicates that the offheap memstore's heap overhead is greater than the
182 // configured 'hbase.regionserver.global.memstore.size'.
183 return FlushType
.ABOVE_ONHEAP_HIGHER_MARK
;
186 return FlushType
.NORMAL
;
190 * Return true if we're above the low watermark
192 public FlushType
isAboveLowWaterMark() {
193 // for onheap memstore we check if the global memstore size and the
194 // global heap overhead is greater than the global memstore lower mark limit
195 if (memType
== MemoryType
.HEAP
) {
196 if (getGlobalMemStoreHeapSize() >= globalMemStoreLimitLowMark
) {
197 return FlushType
.ABOVE_ONHEAP_LOWER_MARK
;
200 if (getGlobalMemStoreOffHeapSize() >= globalMemStoreLimitLowMark
) {
201 // Indicates that the offheap memstore's size is greater than the global memstore
203 return FlushType
.ABOVE_OFFHEAP_LOWER_MARK
;
204 } else if (getGlobalMemStoreHeapSize() >= globalOnHeapMemstoreLimitLowMark
) {
205 // Indicates that the offheap memstore's heap overhead is greater than the global memstore
206 // onheap lower limit
207 return FlushType
.ABOVE_ONHEAP_LOWER_MARK
;
210 return FlushType
.NORMAL
;
214 * @return the flush pressure of all stores on this regionserver. The value should be greater than
215 * or equal to 0.0, and any value greater than 1.0 means we enter the emergency state that
216 * global memstore size already exceeds lower limit.
218 public double getFlushPressure() {
219 if (memType
== MemoryType
.HEAP
) {
220 return (getGlobalMemStoreHeapSize()) * 1.0 / globalMemStoreLimitLowMark
;
222 return Math
.max(getGlobalMemStoreOffHeapSize() * 1.0 / globalMemStoreLimitLowMark
,
223 getGlobalMemStoreHeapSize() * 1.0 / globalOnHeapMemstoreLimitLowMark
);