001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.regionserver; 019 020import java.io.Closeable; 021import java.io.IOException; 022import java.util.HashMap; 023import java.util.Map; 024import java.util.Set; 025import java.util.concurrent.ConcurrentHashMap; 026import java.util.concurrent.ScheduledExecutorService; 027import java.util.concurrent.ScheduledFuture; 028import java.util.concurrent.TimeUnit; 029import org.apache.hadoop.hbase.CompatibilitySingletonFactory; 030import org.apache.hadoop.hbase.HConstants; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.metrics2.MetricsExecutor; 033import org.apache.yetus.audience.InterfaceAudience; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037import org.apache.hbase.thirdparty.com.google.common.collect.Sets; 038 039@InterfaceAudience.Private 040public class MetricsTableWrapperAggregateImpl implements MetricsTableWrapperAggregate, Closeable { 041 private static final Logger LOG = LoggerFactory.getLogger(MetricsTableWrapperAggregateImpl.class); 042 private final HRegionServer regionServer; 043 private ScheduledExecutorService executor; 044 private Runnable runnable; 045 private long period; 046 private ScheduledFuture<?> tableMetricsUpdateTask; 047 private ConcurrentHashMap<TableName, MetricsTableValues> metricsTableMap = 048 new ConcurrentHashMap<>(); 049 050 public MetricsTableWrapperAggregateImpl(final HRegionServer regionServer) { 051 this.regionServer = regionServer; 052 this.period = regionServer.getConfiguration().getLong(HConstants.REGIONSERVER_METRICS_PERIOD, 053 HConstants.DEFAULT_REGIONSERVER_METRICS_PERIOD) + 1000; 054 this.executor = CompatibilitySingletonFactory.getInstance(MetricsExecutor.class).getExecutor(); 055 this.runnable = new TableMetricsWrapperRunnable(); 056 this.tableMetricsUpdateTask = 057 this.executor.scheduleWithFixedDelay(this.runnable, period, period, TimeUnit.MILLISECONDS); 058 } 059 060 public class TableMetricsWrapperRunnable implements Runnable { 061 062 @Override 063 public void run() { 064 // The executor only reschedules this task (scheduleWithFixedDelay) if run() returns 065 // normally. Any Throwable that escapes here (e.g. an NPE from a region closing mid-scan) 066 // is swallowed by the underlying ScheduledFutureTask with no log output anywhere, and this 067 // task permanently stops running. Catch everything so a failure is visible AND the next 068 // scheduled run still happens. 069 try { 070 Map<TableName, MetricsTableValues> localMetricsTableMap = new HashMap<>(); 071 for (Region r : regionServer.getOnlineRegionsLocalContext()) { 072 TableName tbl = r.getTableDescriptor().getTableName(); 073 MetricsTableValues mt = localMetricsTableMap.get(tbl); 074 if (mt == null) { 075 mt = new MetricsTableValues(); 076 localMetricsTableMap.put(tbl, mt); 077 } 078 long memstoreReadCount = 0L; 079 long mixedReadCount = 0L; 080 String tempKey = null; 081 if (r.getStores() != null) { 082 String familyName = null; 083 for (Store store : r.getStores()) { 084 familyName = store.getColumnFamilyName(); 085 086 mt.storeFileCount += store.getStorefilesCount(); 087 mt.maxStoreFileCount = Math.max(mt.maxStoreFileCount, store.getStorefilesCount()); 088 final MemStoreSize memstoreSize = store.getMemStoreSize(); 089 mt.memstoreSize += memstoreSize.getDataSize(); 090 mt.memstoreHeapSize += memstoreSize.getHeapSize(); 091 mt.memstoreOffHeapSize += memstoreSize.getOffHeapSize(); 092 mt.storeFileSize += store.getStorefilesSize(); 093 mt.referenceFileCount += store.getNumReferenceFiles(); 094 if (store.getMaxStoreFileAge().isPresent()) { 095 mt.maxStoreFileAge = 096 Math.max(mt.maxStoreFileAge, store.getMaxStoreFileAge().getAsLong()); 097 } 098 if (store.getMinStoreFileAge().isPresent()) { 099 mt.minStoreFileAge = 100 Math.min(mt.minStoreFileAge, store.getMinStoreFileAge().getAsLong()); 101 } 102 if (store.getAvgStoreFileAge().isPresent()) { 103 mt.totalStoreFileAge += 104 (long) (store.getAvgStoreFileAge().getAsDouble() * store.getStorefilesCount()); 105 } 106 mt.storeCount += 1; 107 108 mt.staticIndexSize += store.getTotalStaticIndexSize(); 109 mt.staticBloomSize += store.getTotalStaticBloomSize(); 110 111 mt.bloomRequestsCount += store.getBloomFilterRequestsCount(); 112 mt.bloomNegativeResultsCount += store.getBloomFilterNegativeResultsCount(); 113 mt.bloomEligibleRequestsCount += store.getBloomFilterEligibleRequestsCount(); 114 115 tempKey = tbl.getNameAsString() + HASH + familyName; 116 Long tempVal = mt.perStoreMemstoreOnlyReadCount.get(tempKey); 117 if (tempVal == null) { 118 tempVal = 0L; 119 } 120 memstoreReadCount = store.getMemstoreOnlyRowReadsCount() + tempVal; 121 tempVal = mt.perStoreMixedReadCount.get(tempKey); 122 if (tempVal == null) { 123 tempVal = 0L; 124 } 125 mixedReadCount = store.getMixedRowReadsCount() + tempVal; 126 // accumulate the count 127 mt.perStoreMemstoreOnlyReadCount.put(tempKey, memstoreReadCount); 128 mt.perStoreMixedReadCount.put(tempKey, mixedReadCount); 129 mt.perStoreFileSize.merge(tempKey, store.getStorefilesSize(), Long::sum); 130 } 131 132 mt.regionCount += 1; 133 134 mt.readRequestCount += r.getReadRequestsCount(); 135 mt.filteredReadRequestCount += r.getFilteredReadRequestsCount(); 136 mt.writeRequestCount += r.getWriteRequestsCount(); 137 } 138 } 139 140 for (Map.Entry<TableName, MetricsTableValues> entry : localMetricsTableMap.entrySet()) { 141 TableName tbl = entry.getKey(); 142 if (metricsTableMap.get(tbl) == null) { 143 // this will add the Wrapper to the list of TableMetrics 144 CompatibilitySingletonFactory.getInstance(MetricsRegionServerSourceFactory.class) 145 .getTableAggregate() 146 .getOrCreateTableSource(tbl.getNameAsString(), MetricsTableWrapperAggregateImpl.this); 147 } 148 metricsTableMap.put(entry.getKey(), entry.getValue()); 149 } 150 Set<TableName> existingTableNames = Sets.newHashSet(metricsTableMap.keySet()); 151 existingTableNames.removeAll(localMetricsTableMap.keySet()); 152 MetricsTableAggregateSource agg = CompatibilitySingletonFactory 153 .getInstance(MetricsRegionServerSourceFactory.class).getTableAggregate(); 154 for (TableName table : existingTableNames) { 155 agg.deleteTableSource(table.getNameAsString()); 156 if (metricsTableMap.get(table) != null) { 157 metricsTableMap.remove(table); 158 } 159 } 160 } catch (Throwable t) { 161 LOG.error("Failed to compute per-table metrics; will retry on next scheduled run", t); 162 } 163 } 164 } 165 166 @Override 167 public long getReadRequestCount(String table) { 168 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 169 if (metricsTable == null) { 170 return 0; 171 } else { 172 return metricsTable.readRequestCount; 173 } 174 } 175 176 @Override 177 public Map<String, Long> getMemstoreOnlyRowReadsCount(String table) { 178 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 179 if (metricsTable == null) { 180 return null; 181 } else { 182 return metricsTable.perStoreMemstoreOnlyReadCount; 183 } 184 } 185 186 @Override 187 public Map<String, Long> getMixedRowReadsCount(String table) { 188 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 189 if (metricsTable == null) { 190 return null; 191 } else { 192 return metricsTable.perStoreMixedReadCount; 193 } 194 } 195 196 @Override 197 public Map<String, Long> getStoreFileSizePerStore(String table) { 198 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 199 if (metricsTable == null) { 200 return null; 201 } else { 202 return metricsTable.perStoreFileSize; 203 } 204 } 205 206 @Override 207 public long getCpRequestsCount(String table) { 208 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 209 if (metricsTable == null) { 210 return 0; 211 } else { 212 return metricsTable.cpRequestCount; 213 } 214 } 215 216 public long getFilteredReadRequestCount(String table) { 217 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 218 if (metricsTable == null) { 219 return 0; 220 } 221 return metricsTable.filteredReadRequestCount; 222 } 223 224 @Override 225 public long getWriteRequestCount(String table) { 226 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 227 if (metricsTable == null) { 228 return 0; 229 } else { 230 return metricsTable.writeRequestCount; 231 } 232 } 233 234 @Override 235 public long getTotalRequestsCount(String table) { 236 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 237 if (metricsTable == null) { 238 return 0; 239 } else { 240 return metricsTable.readRequestCount + metricsTable.writeRequestCount; 241 } 242 } 243 244 @Override 245 public long getMemStoreSize(String table) { 246 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 247 if (metricsTable == null) { 248 return 0; 249 } else { 250 return metricsTable.memstoreSize; 251 } 252 } 253 254 @Override 255 public long getMemStoreHeapSize(String table) { 256 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 257 if (metricsTable == null) { 258 return 0; 259 } else { 260 return metricsTable.memstoreHeapSize; 261 } 262 } 263 264 @Override 265 public long getMemStoreOffHeapSize(String table) { 266 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 267 if (metricsTable == null) { 268 return 0; 269 } else { 270 return metricsTable.memstoreOffHeapSize; 271 } 272 } 273 274 @Override 275 public long getStoreFileSize(String table) { 276 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 277 if (metricsTable == null) { 278 return 0; 279 } else { 280 return metricsTable.storeFileSize; 281 } 282 } 283 284 @Override 285 public long getTableSize(String table) { 286 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 287 if (metricsTable == null) { 288 return 0; 289 } else { 290 return metricsTable.memstoreSize + metricsTable.storeFileSize; 291 } 292 } 293 294 public long getNumRegions(String table) { 295 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 296 if (metricsTable == null) { 297 return 0; 298 } 299 return metricsTable.regionCount; 300 } 301 302 @Override 303 public long getNumStores(String table) { 304 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 305 if (metricsTable == null) { 306 return 0; 307 } 308 return metricsTable.storeCount; 309 } 310 311 @Override 312 public long getNumStoreFiles(String table) { 313 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 314 if (metricsTable == null) { 315 return 0; 316 } 317 return metricsTable.storeFileCount; 318 } 319 320 @Override 321 public long getMaxStoreFiles(String table) { 322 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 323 if (metricsTable == null) { 324 return 0; 325 } 326 return metricsTable.maxStoreFileCount; 327 } 328 329 @Override 330 public long getMaxStoreFileAge(String table) { 331 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 332 if (metricsTable == null) { 333 return 0; 334 } 335 return metricsTable.maxStoreFileAge; 336 } 337 338 @Override 339 public long getMinStoreFileAge(String table) { 340 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 341 if (metricsTable == null) { 342 return 0; 343 } 344 return metricsTable.minStoreFileAge == Long.MAX_VALUE ? 0 : metricsTable.minStoreFileAge; 345 } 346 347 @Override 348 public long getAvgStoreFileAge(String table) { 349 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 350 if (metricsTable == null) { 351 return 0; 352 } 353 354 return metricsTable.storeFileCount == 0 355 ? 0 356 : (metricsTable.totalStoreFileAge / metricsTable.storeFileCount); 357 } 358 359 @Override 360 public long getStaticIndexSize(String table) { 361 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 362 if (metricsTable == null) { 363 return 0; 364 } 365 366 return metricsTable.staticIndexSize; 367 } 368 369 @Override 370 public long getStaticBloomSize(String table) { 371 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 372 if (metricsTable == null) { 373 return 0; 374 } 375 376 return metricsTable.staticBloomSize; 377 } 378 379 @Override 380 public long getBloomFilterRequestsCount(String table) { 381 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 382 if (metricsTable == null) { 383 return 0; 384 } 385 386 return metricsTable.bloomRequestsCount; 387 } 388 389 @Override 390 public long getBloomFilterNegativeResultsCount(String table) { 391 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 392 if (metricsTable == null) { 393 return 0; 394 } 395 396 return metricsTable.bloomNegativeResultsCount; 397 } 398 399 @Override 400 public long getBloomFilterEligibleRequestsCount(String table) { 401 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 402 if (metricsTable == null) { 403 return 0; 404 } 405 406 return metricsTable.bloomEligibleRequestsCount; 407 } 408 409 @Override 410 public long getNumReferenceFiles(String table) { 411 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 412 if (metricsTable == null) { 413 return 0; 414 } 415 return metricsTable.referenceFileCount; 416 } 417 418 @Override 419 public long getAvgRegionSize(String table) { 420 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 421 if (metricsTable == null) { 422 return 0; 423 } 424 return metricsTable.regionCount == 0 425 ? 0 426 : (metricsTable.memstoreSize + metricsTable.storeFileSize) / metricsTable.regionCount; 427 } 428 429 public long getCpRequestCount(String table) { 430 MetricsTableValues metricsTable = metricsTableMap.get(TableName.valueOf(table)); 431 if (metricsTable == null) { 432 return 0; 433 } 434 return metricsTable.cpRequestCount; 435 } 436 437 @Override 438 public void close() throws IOException { 439 tableMetricsUpdateTask.cancel(true); 440 } 441 442 private static class MetricsTableValues { 443 long readRequestCount; 444 long filteredReadRequestCount; 445 long writeRequestCount; 446 long memstoreSize; 447 long memstoreHeapSize; 448 long memstoreOffHeapSize; 449 long regionCount; 450 long storeCount; 451 long storeFileCount; 452 long maxStoreFileCount; 453 long storeFileSize; 454 long maxStoreFileAge; 455 long minStoreFileAge = Long.MAX_VALUE; 456 long totalStoreFileAge; 457 458 long staticIndexSize; 459 460 long staticBloomSize; 461 long referenceFileCount; 462 463 long bloomRequestsCount; 464 long bloomNegativeResultsCount; 465 long bloomEligibleRequestsCount; 466 long cpRequestCount; 467 Map<String, Long> perStoreMemstoreOnlyReadCount = new HashMap<>(); 468 Map<String, Long> perStoreMixedReadCount = new HashMap<>(); 469 Map<String, Long> perStoreFileSize = new HashMap<>(); 470 } 471 472}