こんにちは。今日はCaffeineでキャッシュのエントリに対して
キャッシュ有効時間に対してランダムな揺らぎを導入する方法をここに書いておきます。
キャッシュに対してランダムな揺らぎを入れる必要性に関してはこちらの記事を読むと一部書いてあると思います。
また、AWS Architecture Blogにある「Exponential Backoff and Jitter」を読むと良いかもしれません。
こちらはこちらで面白いですが、キャッシュの話は関係ないです。
アクセス負荷を平滑する手法について、シミュレーションとその結果から生成されるグラフについて紹介してくれています。
この記事ではキャッシュそのものについて説明しません。
Caffeineとは
CaffeineとはGuavaにあるCacheライクなAPIを持つインメモリキャッシュのためのライブラリです。
高速らしいです。
Caffeine自体の使い方については以下のブログを参照してください
実装方針
Caffeineにはいつからか、Expiryというインターフェースが用意されており以下のようなインターフェースになっています。
public interface Expiry<K, V> {
long expireAfterCreate(@NonNull K key, @NonNull V value, long currentTime);
long expireAfterUpdate(@NonNull K key, @NonNull V value,
long currentTime, @NonNegative long currentDuration);
long expireAfterRead(@NonNull K key, @NonNull V value,
long currentTime, @NonNegative long currentDuration);
}
また、以下のように、CacheのビルダーにexpireAfterにExpiryを渡すことが出来るようになっています。
Caffeine.newBuilder()
.expireAfter(new MyExpiry<>())
.build();
実装してみます
今回の10分をベースに25%の範囲(7.5分〜12.5分)で揺らぎのあるExpiryを書いてみます。
以下のような形になりました。
7.5分〜12.5分の間で揺らぎのあるExpiry
public class MyExpiry<K, V> implements Expiry<K, V> {
public final Random = new Random();
public final long base = TimeUnit.NANOSECONDS.convert(10, TimeUnit.MINUTES);
public final double jitterFactor = 0.25;
@Override
public long expireAfterCreate(K key, V value, long currentTime) {
return return (long) (base + jitterFactor * base * (2 * rand.nextDouble() - 1));;
}
@Override
public long expireAfterUpdate(K key, V value, long currentTime,
long currentDuration) {
return currentDuration;
}
@Override
public long expireAfterRead(K key, V value, long currentTime,
long currentDuration) {
return currentDuration;
}
expireAfterCreateを実装して他はcurrentDurationを返すだけです。
今回はLRUではなく固定サイズ、固定期間キャッシュするようなイメージの物を実装したので
expireAfterReadはcurrentDurationを返すようにしています
また、今回自分の用途ではupdateをしないので、expireAfterUpdateもcurrentDurationを返すようにしています。
利用する際は、必要に応じてこれらのメソッドを適切に実装してください。
まとめ
今回は簡単にCaffeineでキャッシュの有効期間に対してランダム性をもたせることで
負荷を平滑化しようとしてこの記事で書いたような実装を書きました。
メモ書きに近いですが、誰かの訳に立てると幸いです。
負荷試験はこれからです。