001/* 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 */ 019package org.apache.hadoop.hbase.regionserver; 020 021import java.lang.management.MemoryType; 022import java.util.concurrent.atomic.LongAdder; 023 024import org.apache.hadoop.conf.Configuration; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.apache.hadoop.hbase.io.util.MemorySizeUtil; 027import org.apache.hadoop.hbase.util.Pair; 028 029/** 030 * RegionServerAccounting keeps record of some basic real time information about 031 * the Region Server. Currently, it keeps record the global memstore size and global memstore 032 * on-heap and off-heap overhead. It also tracks the replay edits per region. 033 */ 034@InterfaceAudience.Private 035public class RegionServerAccounting { 036 // memstore data size 037 private final LongAdder globalMemStoreDataSize = new LongAdder(); 038 // memstore heap size. 039 private final LongAdder globalMemStoreHeapSize = new LongAdder(); 040 // memstore off-heap size. 041 private final LongAdder globalMemStoreOffHeapSize = new LongAdder(); 042 043 private long globalMemStoreLimit; 044 private final float globalMemStoreLimitLowMarkPercent; 045 private long globalMemStoreLimitLowMark; 046 private final MemoryType memType; 047 private long globalOnHeapMemstoreLimit; 048 private long globalOnHeapMemstoreLimitLowMark; 049 050 public RegionServerAccounting(Configuration conf) { 051 Pair<Long, MemoryType> globalMemstoreSizePair = MemorySizeUtil.getGlobalMemStoreSize(conf); 052 this.globalMemStoreLimit = globalMemstoreSizePair.getFirst(); 053 this.memType = globalMemstoreSizePair.getSecond(); 054 this.globalMemStoreLimitLowMarkPercent = 055 MemorySizeUtil.getGlobalMemStoreHeapLowerMark(conf, this.memType == MemoryType.HEAP); 056 // When off heap memstore in use we configure the global off heap space for memstore as bytes 057 // not as % of max memory size. In such case, the lower water mark should be specified using the 058 // key "hbase.regionserver.global.memstore.size.lower.limit" which says % of the global upper 059 // bound and defaults to 95%. In on heap case also specifying this way is ideal. But in the past 060 // we used to take lower bound also as the % of xmx (38% as default). For backward compatibility 061 // for this deprecated config,we will fall back to read that config when new one is missing. 062 // Only for on heap case, do this fallback mechanism. For off heap it makes no sense. 063 // TODO When to get rid of the deprecated config? ie 064 // "hbase.regionserver.global.memstore.lowerLimit". Can get rid of this boolean passing then. 065 this.globalMemStoreLimitLowMark = 066 (long) (this.globalMemStoreLimit * this.globalMemStoreLimitLowMarkPercent); 067 this.globalOnHeapMemstoreLimit = MemorySizeUtil.getOnheapGlobalMemStoreSize(conf); 068 this.globalOnHeapMemstoreLimitLowMark = 069 (long) (this.globalOnHeapMemstoreLimit * this.globalMemStoreLimitLowMarkPercent); 070 } 071 072 long getGlobalMemStoreLimit() { 073 return this.globalMemStoreLimit; 074 } 075 076 long getGlobalOnHeapMemStoreLimit() { 077 return this.globalOnHeapMemstoreLimit; 078 } 079 080 // Called by the tuners. 081 void setGlobalMemStoreLimits(long newGlobalMemstoreLimit) { 082 if (this.memType == MemoryType.HEAP) { 083 this.globalMemStoreLimit = newGlobalMemstoreLimit; 084 this.globalMemStoreLimitLowMark = 085 (long) (this.globalMemStoreLimit * this.globalMemStoreLimitLowMarkPercent); 086 } else { 087 this.globalOnHeapMemstoreLimit = newGlobalMemstoreLimit; 088 this.globalOnHeapMemstoreLimitLowMark = 089 (long) (this.globalOnHeapMemstoreLimit * this.globalMemStoreLimitLowMarkPercent); 090 } 091 } 092 093 boolean isOffheap() { 094 return this.memType == MemoryType.NON_HEAP; 095 } 096 097 long getGlobalMemStoreLimitLowMark() { 098 return this.globalMemStoreLimitLowMark; 099 } 100 101 float getGlobalMemStoreLimitLowMarkPercent() { 102 return this.globalMemStoreLimitLowMarkPercent; 103 } 104 105 /** 106 * @return the global Memstore data size in the RegionServer 107 */ 108 public long getGlobalMemStoreDataSize() { 109 return globalMemStoreDataSize.sum(); 110 } 111 112 /** 113 * @return the global memstore heap size in the RegionServer 114 */ 115 public long getGlobalMemStoreHeapSize() { 116 return this.globalMemStoreHeapSize.sum(); 117 } 118 119 /** 120 * @return the global memstore heap size in the RegionServer 121 */ 122 public long getGlobalMemStoreOffHeapSize() { 123 return this.globalMemStoreOffHeapSize.sum(); 124 } 125 126 void incGlobalMemStoreSize(MemStoreSize mss) { 127 incGlobalMemStoreSize(mss.getDataSize(), mss.getHeapSize(), mss.getOffHeapSize()); 128 } 129 130 public void incGlobalMemStoreSize(long dataSizeDelta, long heapSizeDelta, long offHeapSizeDelta) { 131 globalMemStoreDataSize.add(dataSizeDelta); 132 globalMemStoreHeapSize.add(heapSizeDelta); 133 globalMemStoreOffHeapSize.add(offHeapSizeDelta); 134 } 135 136 public void decGlobalMemStoreSize(long dataSizeDelta, long heapSizeDelta, long offHeapSizeDelta) { 137 globalMemStoreDataSize.add(-dataSizeDelta); 138 globalMemStoreHeapSize.add(-heapSizeDelta); 139 globalMemStoreOffHeapSize.add(-offHeapSizeDelta); 140 } 141 142 /** 143 * Return true if we are above the memstore high water mark 144 * @return the flushtype 145 */ 146 public FlushType isAboveHighWaterMark() { 147 // for onheap memstore we check if the global memstore size and the 148 // global heap overhead is greater than the global memstore limit 149 if (memType == MemoryType.HEAP) { 150 if (getGlobalMemStoreHeapSize() >= globalMemStoreLimit) { 151 return FlushType.ABOVE_ONHEAP_HIGHER_MARK; 152 } 153 } else { 154 // If the configured memstore is offheap, check for two things 155 // 1) If the global memstore off-heap size is greater than the configured 156 // 'hbase.regionserver.offheap.global.memstore.size' 157 // 2) If the global memstore heap size is greater than the configured onheap 158 // global memstore limit 'hbase.regionserver.global.memstore.size'. 159 // We do this to avoid OOME incase of scenarios where the heap is occupied with 160 // lot of onheap references to the cells in memstore 161 if (getGlobalMemStoreOffHeapSize() >= globalMemStoreLimit) { 162 // Indicates that global memstore size is above the configured 163 // 'hbase.regionserver.offheap.global.memstore.size' 164 return FlushType.ABOVE_OFFHEAP_HIGHER_MARK; 165 } else if (getGlobalMemStoreHeapSize() >= this.globalOnHeapMemstoreLimit) { 166 // Indicates that the offheap memstore's heap overhead is greater than the 167 // configured 'hbase.regionserver.global.memstore.size'. 168 return FlushType.ABOVE_ONHEAP_HIGHER_MARK; 169 } 170 } 171 return FlushType.NORMAL; 172 } 173 174 /** 175 * Return true if we're above the low watermark 176 */ 177 public FlushType isAboveLowWaterMark() { 178 // for onheap memstore we check if the global memstore size and the 179 // global heap overhead is greater than the global memstore lower mark limit 180 if (memType == MemoryType.HEAP) { 181 if (getGlobalMemStoreHeapSize() >= globalMemStoreLimitLowMark) { 182 return FlushType.ABOVE_ONHEAP_LOWER_MARK; 183 } 184 } else { 185 if (getGlobalMemStoreOffHeapSize() >= globalMemStoreLimitLowMark) { 186 // Indicates that the offheap memstore's size is greater than the global memstore 187 // lower limit 188 return FlushType.ABOVE_OFFHEAP_LOWER_MARK; 189 } else if (getGlobalMemStoreHeapSize() >= globalOnHeapMemstoreLimitLowMark) { 190 // Indicates that the offheap memstore's heap overhead is greater than the global memstore 191 // onheap lower limit 192 return FlushType.ABOVE_ONHEAP_LOWER_MARK; 193 } 194 } 195 return FlushType.NORMAL; 196 } 197 198 /** 199 * @return the flush pressure of all stores on this regionserver. The value should be greater than 200 * or equal to 0.0, and any value greater than 1.0 means we enter the emergency state that 201 * global memstore size already exceeds lower limit. 202 */ 203 public double getFlushPressure() { 204 if (memType == MemoryType.HEAP) { 205 return (getGlobalMemStoreHeapSize()) * 1.0 / globalMemStoreLimitLowMark; 206 } else { 207 return Math.max(getGlobalMemStoreOffHeapSize() * 1.0 / globalMemStoreLimitLowMark, 208 getGlobalMemStoreHeapSize() * 1.0 / globalOnHeapMemstoreLimitLowMark); 209 } 210 } 211}