DATAREDIS-1082 - Expose cache metrics for RedisCache.
We now expose CacheStatistics for RedisCache. Each cache tracks its statistics (retrievals, hits, misses, stores, removals, lock wait) locally. CacheStatistics is exposed through RedisCacheWriter to allow for statistics customization depending on the cache writer strategy. The statistic object is a singleton per cache instance that gets updated with as the cache operates. RedisCache cache = …; CacheStatistics statistics = cache.getStatistics(); statistics.getRetrievals(); statistics.getHits(); Original Pull Request: #545
This commit is contained in:
committed by
Christoph Strobl
parent
488e658f5d
commit
6daeb1a04c
58
src/main/java/org/springframework/data/redis/cache/CacheStatistics.java
vendored
Normal file
58
src/main/java/org/springframework/data/redis/cache/CacheStatistics.java
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.redis.cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Cache statistics for a Redis Cache.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.4
|
||||
*/
|
||||
public interface CacheStatistics {
|
||||
|
||||
/**
|
||||
* @return number of put operations on the cache.
|
||||
*/
|
||||
long getStores();
|
||||
|
||||
/**
|
||||
* @return number of get operations.
|
||||
*/
|
||||
long getRetrievals();
|
||||
|
||||
/**
|
||||
* @return number of cache get hits.
|
||||
*/
|
||||
long getHits();
|
||||
|
||||
/**
|
||||
* @return number of cache get misses.
|
||||
*/
|
||||
long getMisses();
|
||||
|
||||
/**
|
||||
* @return number of cache removals.
|
||||
*/
|
||||
long getRemovals();
|
||||
|
||||
/**
|
||||
* @param unit the time unit to report the lock wait duration.
|
||||
* @return lock duration using the given {@link TimeUnit} if the cache is configured to use locking.
|
||||
*/
|
||||
long getLockWaitDuration(TimeUnit unit);
|
||||
}
|
||||
125
src/main/java/org/springframework/data/redis/cache/DefaultCacheStatistics.java
vendored
Normal file
125
src/main/java/org/springframework/data/redis/cache/DefaultCacheStatistics.java
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.data.redis.cache;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default mutable {@link CacheStatistics} implementation.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.4
|
||||
*/
|
||||
class DefaultCacheStatistics implements CacheStatistics {
|
||||
|
||||
private final LongAdder stores = new LongAdder();
|
||||
private final LongAdder retrievals = new LongAdder();
|
||||
private final LongAdder hits = new LongAdder();
|
||||
private final LongAdder misses = new LongAdder();
|
||||
private final LongAdder removals = new LongAdder();
|
||||
private final LongAdder lockWaitTimeNs = new LongAdder();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getStores()
|
||||
*/
|
||||
@Override
|
||||
public long getStores() {
|
||||
return stores.sum();
|
||||
}
|
||||
|
||||
void incrementStores() {
|
||||
stores.increment();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getRetrievals()
|
||||
*/
|
||||
@Override
|
||||
public long getRetrievals() {
|
||||
return retrievals.sum();
|
||||
}
|
||||
|
||||
void incrementRetrievals() {
|
||||
retrievals.increment();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getHits()
|
||||
*/
|
||||
@Override
|
||||
public long getHits() {
|
||||
return hits.sum();
|
||||
}
|
||||
|
||||
void incrementHits() {
|
||||
hits.increment();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getMisses()
|
||||
*/
|
||||
@Override
|
||||
public long getMisses() {
|
||||
return misses.sum();
|
||||
}
|
||||
|
||||
void incrementMisses() {
|
||||
misses.increment();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getRemovals()
|
||||
*/
|
||||
@Override
|
||||
public long getRemovals() {
|
||||
return removals.sum();
|
||||
}
|
||||
|
||||
void incrementRemovals() {
|
||||
incrementRemovals(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param x number of removals to add.
|
||||
*/
|
||||
void incrementRemovals(int x) {
|
||||
removals.add(x);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.CacheStatistics#getLockWaitDuration(java.util.concurrent.TimeUnit)
|
||||
*/
|
||||
@Override
|
||||
public long getLockWaitDuration(TimeUnit unit) {
|
||||
|
||||
Assert.notNull(unit, "TimeUnit must not be null");
|
||||
|
||||
return unit.convert(lockWaitTimeNs.sum(), TimeUnit.NANOSECONDS);
|
||||
}
|
||||
|
||||
void incrementLockWaitTime(long waitTimeNs) {
|
||||
lockWaitTimeNs.add(waitTimeNs);
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
|
||||
private final RedisConnectionFactory connectionFactory;
|
||||
private final Duration sleepTime;
|
||||
private final DefaultCacheStatistics statistics;
|
||||
|
||||
/**
|
||||
* @param connectionFactory must not be {@literal null}.
|
||||
@@ -71,6 +72,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
|
||||
this.connectionFactory = connectionFactory;
|
||||
this.sleepTime = sleepTime;
|
||||
this.statistics = new DefaultCacheStatistics();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -94,6 +96,8 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
|
||||
return "OK";
|
||||
});
|
||||
|
||||
statistics.incrementStores();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -106,7 +110,17 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
Assert.notNull(name, "Name must not be null!");
|
||||
Assert.notNull(key, "Key must not be null!");
|
||||
|
||||
return execute(name, connection -> connection.get(key));
|
||||
byte[] result = execute(name, connection -> connection.get(key));
|
||||
|
||||
statistics.incrementRetrievals();
|
||||
|
||||
if (result != null) {
|
||||
statistics.incrementHits();
|
||||
} else {
|
||||
statistics.incrementMisses();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -132,6 +146,8 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
if (shouldExpireWithin(ttl)) {
|
||||
connection.pExpire(key, ttl.toMillis());
|
||||
}
|
||||
|
||||
statistics.incrementStores();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -156,6 +172,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
Assert.notNull(key, "Key must not be null!");
|
||||
|
||||
execute(name, connection -> connection.del(key));
|
||||
statistics.incrementRemovals();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -183,6 +200,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
.toArray(new byte[0][]);
|
||||
|
||||
if (keys.length > 0) {
|
||||
statistics.incrementRemovals(keys.length);
|
||||
connection.del(keys);
|
||||
}
|
||||
} finally {
|
||||
@@ -196,6 +214,15 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.redis.cache.RedisCacheWriter#getStatistics()
|
||||
*/
|
||||
@Override
|
||||
public DefaultCacheStatistics getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Explicitly set a write lock on a cache.
|
||||
*
|
||||
@@ -262,6 +289,7 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
return;
|
||||
}
|
||||
|
||||
long lockWaitTimeNs = System.nanoTime();
|
||||
try {
|
||||
|
||||
while (doCheckLock(name, connection)) {
|
||||
@@ -274,6 +302,8 @@ class DefaultRedisCacheWriter implements RedisCacheWriter {
|
||||
|
||||
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name),
|
||||
ex);
|
||||
} finally {
|
||||
statistics.incrementLockWaitTime(System.nanoTime() - lockWaitTimeNs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -193,6 +193,17 @@ public class RedisCache extends AbstractValueAdaptingCache {
|
||||
cacheWriter.clean(name, pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CacheStatistics} for this cache instance. Statistics are accumulated per cache instance and not
|
||||
* from the backing Redis data store. Cache statistics are accumulated starting from the time a cache is created.
|
||||
*
|
||||
* @return statistics object for this {@link RedisCache}.
|
||||
* @since 2.4
|
||||
*/
|
||||
public CacheStatistics getStatistics() {
|
||||
return cacheWriter.getStatistics();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get {@link RedisCacheConfiguration} used.
|
||||
*
|
||||
|
||||
@@ -106,4 +106,13 @@ public interface RedisCacheWriter {
|
||||
* @param pattern The pattern for the keys to remove. Must not be {@literal null}.
|
||||
*/
|
||||
void clean(String name, byte[] pattern);
|
||||
|
||||
/**
|
||||
* Return the {@link CacheStatistics} for this cache instance. Statistics are accumulated per cache instance and not
|
||||
* from the backing Redis data store. Cache statistics are accumulated starting from the time a cache is created.
|
||||
*
|
||||
* @return statistics object for this {@link RedisCache}.
|
||||
* @since 2.4
|
||||
*/
|
||||
CacheStatistics getStatistics();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user