はじめに
こんにちは、メディアプラットフォーム事業部エンジニアの岡崎です。最近、ローカルキャッシュの導入を行いました。今回はその時のことを備忘録としてブログに残します。
前提
今回の要件として一番大切なことは、できるだけユーザーがページを見ることができる状態にすることでした。
これを前提として、今までの実装を見ていきましょう。
最初、キャッシュはRedisに保存するような構成になっていました。
この場合、もしDBに障害が起きたとしても、Redisに保存しているデータがあった場合は、そこから取得することができます。
しかし、Redisに障害が起きてしまったら、データが取得できなくなり、クライアントではページを表示できなくなってしまいます。
今回は要件で、できるだけユーザーがページを見れる状態にしたかったので、他にもっといい方法がないか模索することになりました。
そこで、キャッシュしたデータを保存する場所をRedisからローカルに変更しました。
こうすることで、DBに障害が起きたとしても、ローカルサーバーにデータがある限りは、データを取得できます。
環境
openjdk version "21.0.2" 2024-01-16 LTS OpenJDK Runtime Environment Corretto-21.0.2.13.1 (build 21.0.2+13-LTS) OpenJDK 64-Bit Server VM Corretto-21.0.2.13.1 (build 21.0.2+13-LTS, mixed mode, sharing)
- Spring Boot
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v3.2.2)
- build.gradleに以下の依存関係を追加する
implementation "com.github.ben-manes.caffeine:caffeine:3.1.8"
実装
まずは、ローカルキャッシュを使うための準備を行いました。
必要なものは以下の通りです。
- ローカル用のキャッシュマネージャー
- Redis用のキャッシュマネージャー
- ローカルのキャッシュキー
これらを、それぞれのファイルに実装していきました。
その時の実装例を以下に示します。
CacheConfig
ここでは、ローカルキャッシュのキャッシュマネージャーの設定を行っています。
@Configuration public class CacheConfig { /** * ローカルキャッシュ用のキャッシュマネージャーを設定する * * @return キャッシュマネージャー */ @Bean(CacheLocalKeyType.LOCAL_CACHE_MANAGER_NAME) public CacheManager localCacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); Arrays.stream(CacheLocalKeyType.values()).forEach(e -> { Cache<Object, Object> cache = Caffeine .newBuilder() .expireAfterWrite(Duration.ofSeconds(e.getTtl())) .build(); cacheManager.registerCustomCache(e.getKey(), cache); }); return cacheManager; } }
CacheLocalKeyType
ローカルのキャッシュキーの実装例です。
public enum CacheLocalKeyType { WEB_GET_TOP(CacheLocalKeyType.WEB_TOP_KEY, TimeUnit.HOURS.toSeconds(1)); @Getter private final String key; @Getter private final Long ttl; /** * ローカルキャッシュのキータイプ * * @param cacheName キャッシュ名 * @param ttl キャッシュ時間 */ CacheLocalKeyType(String cacheName, Long ttl) { this.key = cacheName; this.ttl = ttl; } public static final String SAMPLE_KEY = "sampleKey"; public static final String LOCAL_CACHE_MANAGER_NAME = "localCacheManager"; }
Redis.config
Redis.configにキャッシュマネージャーがない場合、実装する必要があります。
今回は、Redisのキャッシュをデフォルトの設定にしたいため、@Primary
をつけます。
/** * Redisのキャッシュマネージャーを設定する * * @param redisConnectionFactory redisConnectionFactory * @return キャッシュマネージャー */ @Bean @Primary public CacheManager cacheManager(LettuceConnectionFactory redisConnectionFactory) { Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>(); Arrays.stream(CacheKeyType.values()).forEach(e -> cacheConfigurations.put( e.getKey(), RedisCacheConfiguration .defaultCacheConfig() .entryTtl(Duration.ofSeconds(e.getTtl())) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(this.serializer())) ) ); return RedisCacheManager .builder(redisConnectionFactory) .withInitialCacheConfigurations(cacheConfigurations) .build(); }
以上で、ローカルキャッシュを使う準備は整いました。
それでは、実際にローカルキャッシュを使ってみましょう。実装例は以下の通りです。
@Override // キャッシュマネージャーを指定しない場合、デフォルトの設定が使われます @Cacheable(cacheNames = CacheKeyType.SAMPLE_KEY, cacheManager = CacheLocalKeyType.LOCAL_CACHE_MANAGER_NAME) public String getIdList() { // 以下略 }
これで完成です!
最後に
今回は、ローカルキャッシュを導入したので、簡単に紹介しました。簡単に実装ができるので、ぜひローカルキャッシュの実装の導入を検討してみてください。
最後に、採用情報のお知らせです。エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。
募集職種一覧はこちらになります!