/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cassandra.metrics; import java.util.concurrent.TimeUnit; import com.yammer.metrics.Metrics; import com.yammer.metrics.core.*; import com.yammer.metrics.util.RatioGauge; import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.io.sstable.SSTableMetadata; import org.apache.cassandra.io.sstable.SSTableReader; import org.apache.cassandra.utils.EstimatedHistogram; /** * Metrics for {@link ColumnFamilyStore}. */ public class ColumnFamilyMetrics { /** Total amount of data stored in the memtable, including column related overhead. */ public final Gauge<Long> memtableDataSize; /** Total number of columns present in the memtable. */ public final Gauge<Long> memtableColumnsCount; /** Number of times flush has resulted in the memtable being switched out. */ public final Counter memtableSwitchCount; /** Current compression ratio for all SSTables */ public final Gauge<Double> compressionRatio; /** Histogram of estimated row size (in bytes). */ public final Gauge<long[]> estimatedRowSizeHistogram; /** Histogram of estimated number of columns. */ public final Gauge<long[]> estimatedColumnCountHistogram; /** Histogram of the number of sstable data files accessed per read */ public final Histogram sstablesPerReadHistogram; /** (Local) read metrics */ public final LatencyMetrics readLatency; /** (Local) write metrics */ public final LatencyMetrics writeLatency; /** Estimated number of tasks pending for this column family */ public final Gauge<Integer> pendingTasks; /** Number of SSTables on disk for this CF */ public final Gauge<Integer> liveSSTableCount; /** Disk space used by SSTables belonging to this CF */ public final Counter liveDiskSpaceUsed; /** Total disk space used by SSTables belonging to this CF, including obsolete ones waiting to be GC'd */ public final Counter totalDiskSpaceUsed; /** Size of the smallest compacted row */ public final Gauge<Long> minRowSize; /** Size of the largest compacted row */ public final Gauge<Long> maxRowSize; /** Size of the smallest compacted row */ public final Gauge<Long> meanRowSize; /** Number of false positives in bloom filter */ public final Gauge<Long> bloomFilterFalsePositives; /** Number of false positives in bloom filter from last read */ public final Gauge<Long> recentBloomFilterFalsePositives; /** False positive ratio of bloom filter */ public final Gauge<Double> bloomFilterFalseRatio; /** False positive ratio of bloom filter from last read */ public final Gauge<Double> recentBloomFilterFalseRatio; /** Disk space used by bloom filter */ public final Gauge<Long> bloomFilterDiskSpaceUsed; /** Key cache hit rate for this CF */ public final Gauge<Double> keyCacheHitRate; /** Tombstones scanned in queries on this CF */ public final Histogram tombstoneScannedHistogram; /** Live cells scanned in queries on this CF */ public final Histogram liveScannedHistogram; public final Timer coordinatorReadLatency; public final Timer coordinatorScanLatency; private final MetricNameFactory factory; public final Counter speculativeRetries; // for backward compatibility @Deprecated public final EstimatedHistogram sstablesPerRead = new EstimatedHistogram(35); @Deprecated public final EstimatedHistogram recentSSTablesPerRead = new EstimatedHistogram(35); /** * Creates metrics for given {@link ColumnFamilyStore}. * * @param cfs ColumnFamilyStore to measure metrics */ public ColumnFamilyMetrics(final ColumnFamilyStore cfs) { factory = new ColumnFamilyMetricNameFactory(cfs); memtableColumnsCount = Metrics.newGauge(factory.createMetricName("MemtableColumnsCount"), new Gauge<Long>() { public Long value() { return cfs.getDataTracker().getMemtable().getOperations(); } }); memtableDataSize = Metrics.newGauge(factory.createMetricName("MemtableDataSize"), new Gauge<Long>() { public Long value() { return cfs.getDataTracker().getMemtable().getLiveSize(); } }); memtableSwitchCount = Metrics.newCounter(factory.createMetricName("MemtableSwitchCount")); estimatedRowSizeHistogram = Metrics.newGauge(factory.createMetricName("EstimatedRowSizeHistogram"), new Gauge<long[]>() { public long[] value() { long[] histogram = new long[90]; for (SSTableReader sstable : cfs.getSSTables()) { long[] rowSize = sstable.getEstimatedRowSize().getBuckets(false); for (int i = 0; i < histogram.length; i++) histogram[i] += rowSize[i]; } return histogram; } }); estimatedColumnCountHistogram = Metrics.newGauge(factory.createMetricName("EstimatedColumnCountHistogram"), new Gauge<long[]>() { public long[] value() { long[] histogram = new long[90]; for (SSTableReader sstable : cfs.getSSTables()) { long[] columnSize = sstable.getEstimatedColumnCount().getBuckets(false); for (int i = 0; i < histogram.length; i++) histogram[i] += columnSize[i]; } return histogram; } }); sstablesPerReadHistogram = Metrics.newHistogram(factory.createMetricName("SSTablesPerReadHistogram")); compressionRatio = Metrics.newGauge(factory.createMetricName("CompressionRatio"), new Gauge<Double>() { public Double value() { double sum = 0; int total = 0; for (SSTableReader sstable : cfs.getSSTables()) { if (sstable.getCompressionRatio() != SSTableMetadata.NO_COMPRESSION_RATIO) { sum += sstable.getCompressionRatio(); total++; } } return total != 0 ? (double) sum / total : 0; } }); readLatency = new LatencyMetrics(factory, "Read"); writeLatency = new LatencyMetrics(factory, "Write"); pendingTasks = Metrics.newGauge(factory.createMetricName("PendingTasks"), new Gauge<Integer>() { public Integer value() { // TODO this actually isn't a good measure of pending tasks return Keyspace.switchLock.getQueueLength(); } }); liveSSTableCount = Metrics.newGauge(factory.createMetricName("LiveSSTableCount"), new Gauge<Integer>() { public Integer value() { return cfs.getDataTracker().getSSTables().size(); } }); liveDiskSpaceUsed = Metrics.newCounter(factory.createMetricName("LiveDiskSpaceUsed")); totalDiskSpaceUsed = Metrics.newCounter(factory.createMetricName("TotalDiskSpaceUsed")); minRowSize = Metrics.newGauge(factory.createMetricName("MinRowSize"), new Gauge<Long>() { public Long value() { long min = 0; for (SSTableReader sstable : cfs.getSSTables()) { if (min == 0 || sstable.getEstimatedRowSize().min() < min) min = sstable.getEstimatedRowSize().min(); } return min; } }); maxRowSize = Metrics.newGauge(factory.createMetricName("MaxRowSize"), new Gauge<Long>() { public Long value() { long max = 0; for (SSTableReader sstable : cfs.getSSTables()) { if (sstable.getEstimatedRowSize().max() > max) max = sstable.getEstimatedRowSize().max(); } return max; } }); meanRowSize = Metrics.newGauge(factory.createMetricName("MeanRowSize"), new Gauge<Long>() { public Long value() { long sum = 0; long count = 0; for (SSTableReader sstable : cfs.getSSTables()) { sum += sstable.getEstimatedRowSize().mean(); count++; } return count > 0 ? sum / count : 0; } }); bloomFilterFalsePositives = Metrics.newGauge(factory.createMetricName("BloomFilterFalsePositives"), new Gauge<Long>() { public Long value() { long count = 0L; for (SSTableReader sstable: cfs.getSSTables()) count += sstable.getBloomFilterFalsePositiveCount(); return count; } }); recentBloomFilterFalsePositives = Metrics.newGauge(factory.createMetricName("RecentBloomFilterFalsePositives"), new Gauge<Long>() { public Long value() { long count = 0L; for (SSTableReader sstable: cfs.getSSTables()) count += sstable.getRecentBloomFilterFalsePositiveCount(); return count; } }); bloomFilterFalseRatio = Metrics.newGauge(factory.createMetricName("BloomFilterFalseRatio"), new Gauge<Double>() { public Double value() { long falseCount = 0L; long trueCount = 0L; for (SSTableReader sstable: cfs.getSSTables()) { falseCount += sstable.getBloomFilterFalsePositiveCount(); trueCount += sstable.getBloomFilterTruePositiveCount(); } if (falseCount == 0L && trueCount == 0L) return 0d; return (double) falseCount / (trueCount + falseCount); } }); recentBloomFilterFalseRatio = Metrics.newGauge(factory.createMetricName("RecentBloomFilterFalseRatio"), new Gauge<Double>() { public Double value() { long falseCount = 0L; long trueCount = 0L; for (SSTableReader sstable: cfs.getSSTables()) { falseCount += sstable.getRecentBloomFilterFalsePositiveCount(); trueCount += sstable.getRecentBloomFilterTruePositiveCount(); } if (falseCount == 0L && trueCount == 0L) return 0d; return (double) falseCount / (trueCount + falseCount); } }); bloomFilterDiskSpaceUsed = Metrics.newGauge(factory.createMetricName("BloomFilterDiskSpaceUsed"), new Gauge<Long>() { public Long value() { long total = 0; for (SSTableReader sst : cfs.getSSTables()) total += sst.getBloomFilterSerializedSize(); return total; } }); speculativeRetries = Metrics.newCounter(factory.createMetricName("SpeculativeRetries")); keyCacheHitRate = Metrics.newGauge(factory.createMetricName("KeyCacheHitRate"), new RatioGauge() { protected double getNumerator() { long hits = 0L; for (SSTableReader sstable : cfs.getSSTables()) hits += sstable.getKeyCacheHit(); return hits; } protected double getDenominator() { long requests = 0L; for (SSTableReader sstable : cfs.getSSTables()) requests += sstable.getKeyCacheRequest(); return Math.max(requests, 1); // to avoid NaN. } }); tombstoneScannedHistogram = Metrics.newHistogram(factory.createMetricName("TombstoneScannedHistogram")); liveScannedHistogram = Metrics.newHistogram(factory.createMetricName("LiveScannedHistogram")); coordinatorReadLatency = Metrics.newTimer(factory.createMetricName("CoordinatorReadLatency"), TimeUnit.MICROSECONDS, TimeUnit.SECONDS); coordinatorScanLatency = Metrics.newTimer(factory.createMetricName("CoordinatorScanLatency"), TimeUnit.MICROSECONDS, TimeUnit.SECONDS); } public void updateSSTableIterated(int count) { sstablesPerReadHistogram.update(count); recentSSTablesPerRead.add(count); sstablesPerRead.add(count); } /** * Release all associated metrics. */ public void release() { readLatency.release(); writeLatency.release(); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MemtableColumnsCount")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MemtableDataSize")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MemtableSwitchCount")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("CompressionRatio")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("EstimatedRowSizeHistogram")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("EstimatedColumnCountHistogram")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("SSTablesPerReadHistogram")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("PendingTasks")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("LiveSSTableCount")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("LiveDiskSpaceUsed")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("TotalDiskSpaceUsed")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MinRowSize")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MaxRowSize")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("MeanRowSize")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("BloomFilterFalsePositives")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("RecentBloomFilterFalsePositives")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("BloomFilterFalseRatio")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("RecentBloomFilterFalseRatio")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("BloomFilterDiskSpaceUsed")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("KeyCacheHitRate")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("SpeculativeRetry")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("TombstoneScannedHistogram")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("LiveScannedHistogram")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("CoordinatorReadLatency")); Metrics.defaultRegistry().removeMetric(factory.createMetricName("CoordinatorScanLatency")); } class ColumnFamilyMetricNameFactory implements MetricNameFactory { private final String keyspaceName; private final String columnFamilyName; private final boolean isIndex; ColumnFamilyMetricNameFactory(ColumnFamilyStore cfs) { this.keyspaceName = cfs.keyspace.getName(); this.columnFamilyName = cfs.name; isIndex = cfs.isIndex(); } public MetricName createMetricName(String metricName) { String groupName = ColumnFamilyMetrics.class.getPackage().getName(); String type = isIndex ? "IndexColumnFamily" : "ColumnFamily"; StringBuilder mbeanName = new StringBuilder(); mbeanName.append(groupName).append(":"); mbeanName.append("type=").append(type); mbeanName.append(",keyspace=").append(keyspaceName); mbeanName.append(",scope=").append(columnFamilyName); mbeanName.append(",name=").append(metricName); return new MetricName(groupName, type, metricName, keyspaceName + "." + columnFamilyName, mbeanName.toString()); } } }