wave
wave copied to clipboard
Add distributed lazy-loading cache
Wave uses a lazy-loading cache in several components. See #589.
In some case it's needed to share the content of the cache across backend replicas. This has been recently implemented by #588 for the RegistryAuthServiceImpl
. However it requires some custom code.
The goal of this issue is to implement a lazy-loading cache that implement the logic to persist item into a shared store such Redis.
A draft implementation could be the following
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import redis.clients.jedis.Jedis;
import java.util.concurrent.TimeUnit;
public class HybridCache<K, V> {
private final Cache<K, V> caffeineCache;
private final Jedis jedis;
public HybridCache() {
this.caffeineCache = Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(100)
.build();
this.jedis = new Jedis("localhost", 6379);
}
public void put(K key, V value) {
// Put in Caffeine
caffeineCache.put(key, value);
// Put in Redis
jedis.set(key.toString(), value.toString());
}
public V get(K key, Class<V> clazz) {
// Try to get from Caffeine
V value = caffeineCache.getIfPresent(key);
if (value != null) {
return value;
}
// If not in Caffeine, try to get from Redis
String redisValue = jedis.get(key.toString());
if (redisValue != null) {
// Optionally, convert the Redis value from String to the desired type
// For simplicity, assuming V is String. Modify as needed.
value = clazz.cast(redisValue);
// Put in Caffeine for faster subsequent access
caffeineCache.put(key, value);
}
return value;
}
public void invalidate(K key) {
// Invalidate in Caffeine
caffeineCache.invalidate(key);
// Remove from Redis
jedis.del(key.toString());
}
}
Requirement
- Use Caffeine as implementation for the loading cache
- Use EncodingStrategy and CacheProvider to persist the data into the shared memory using a similar pattern for AbstractCacheStore