redis-redisson-patterns について
redis-redisson-patternsは、JavaおよびSpring開発者向けのキャッシュと分散ロックの実践ガイドです。Redisの設定、キャッシュ障害の防止、シリアライズ方式、Redissonのロックパターンを扱います。
主な機能
- 01キャッシュキーの命名規則
- 02TTLとシリアライズ方式の選択
- 03Redisson分散ロックのパターン
- 04キャッシュ貫通・雪崩・集中失効への対策
- 05CaffeineとRedisの選択
- 06RedisTemplateのJSON設定
活用シーン
- 01Redisオブジェクトキャッシュの設定
- 02ホットデータ向けローカル・共有キャッシュの設計
- 03自動延長付き分散ロックの実装
- 04キャッシュの同時失効リスクの低減
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ full-stack-skills/ java-skills --skill redis-redisson-patternsインストール後、Claude Code で/redis-redisson-patternsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
agents/openai.yamlexamples/redis-realworld.mdreferences/redis-kafka-resources.md詳細
Redis + Redisson キャッシュと分散ロック
出典:https://redisson.org/docs/
GitHub:https://github.com/redisson/redisson
Redis:https://redis.io/documentation
対応範囲
✅ 得意分野
- キャッシュKeyの規約 — 形式は
{業務名}:{種類}:{ID}、プレフィックスを統一 - 有効期限の原則 — ホットデータは長いTTL、非ホットデータは短いTTL、-1は設定しない
- シリアライズ方式の選択 — JSON、JDK、Stringの3方式を比較し、設定
- Redisson分散ロック — tryLock/watchDog/leaseTime/再入可能/公平ロック/Redlock
- キャッシュの三大問題への対策 — キャッシュ貫通(ブルームフィルター/空値)/キャッシュスタンピード(相互排他ロック)/キャッシュ雪崩(ランダムTTL)
- CaffeineとRedisの使い分け — ローカルキャッシュとRedisを使う場面
- RedisTemplateの適切な設定 — Key/Valueのシリアライズを統一
❌ 対象外
- メッセージキュー/パブリッシュ・サブスクライブ → kafka / RabbitMQ
- Spring Sessionの共有 → spring-security
- Jedis/Lettuceクライアントの選択 → 本ドキュメントではLettuceを推奨(Spring Bootのデフォルト)
シリアライズ方式の選択
| 方式 | メリット | デメリット | 適用シーン |
|---|---|---|---|
| StringRedisTemplate | シンプルで読みやすい | Stringしか保存できず、オブジェクトは手動でシリアライズが必要 | 文字列のみのキャッシュ |
| RedisTemplate + Jackson2JsonRedisSerializer | 読みやすく、言語をまたいで利用可能 | パフォーマンスがやや低い | ✅ 推奨(ほとんどのシーンに適しています) |
| RedisTemplate + JdkSerializationRedisSerializer | デフォルト(型情報を含む) | 読み取れず、サイズが大きく、Java専用 | ❌ 非推奨(デフォルトがこれです) |
| RedisTemplate + GenericJackson2JsonRedisSerializer | @class型情報を含む | 冗長なフィールドが多い | 複雑なオブジェクトのキャッシュ |
LLMがよく犯す間違い
| # | 間違い | 正しい方法 |
|---|---|---|
| 1 | キャッシュに有効期限を設定しない(永久) | メモリ不足を防ぐため、必ずTTLを設定する |
| 2 | StringRedisTemplateとRedisTemplateを混在させる | どちらかに統一し、RedisTemplate + JSONシリアライズを推奨 |
| 3 | キャッシュ貫通(存在しないデータの検索がそのままDBに到達) | 空値をキャッシュ(Boolean.FALSE、TTL 5分)するか、ブルームフィルターを使う |
| 4 | Redisを高頻度のホットキャッシュに使う(毎秒1000qps以上) | Caffeineのローカルキャッシュ層を追加する(L1ローカル + L2 Redis) |
| 5 | lock.lock() をtry-finallyで囲まない | 必ず finally { lock.unlock() } にする |
| 6 | キャッシュKeyに命名規約がない | 形式を統一する:saas:user:10001、saas:order:list |
| 7 | RedissonでleaseTimeを指定しながら、Watchdogによる延長を期待する | leaseTimeを指定するとWatchdogは機能しません! |
| 8 | キャッシュ雪崩に対処しない(大量のKeyが同時に期限切れになる) | TTLにランダム値(±30%)を加える |
| 9 | ホットKeyのキャッシュスタンピード | 相互排他ロック、または有効期限を設けず非同期で更新する |
| 10 | RedisTemplateのデフォルトであるJDKシリアライズを使う | JSONシリアライズに変更する(読みやすく、言語をまたいで利用可能) |
コアパターン
パターン 1: RedisTemplateの統一設定(JSONシリアライズ)
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// ✅ 推荐:Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(LazySerializationTypeValidator.getDefaultTyper(),
ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
template.setKeySerializer(new StringRedisSerializer()); // Key: String
template.setValueSerializer(serializer); // Value: JSON
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
パターン 2: キャッシュ貫通対策(空値キャッシュ)
public User getUser(Long id) {
String key = String.format("saas:user:%s", id);
User user = (User) redisTemplate.opsForValue().get(key);
// 空值标记,直接返回
if (user == NULL_PLACEHOLDER) return null;
// 缓存命中
if (user != null) return user;
// 查询DB
user = userMapper.selectById(id);
if (user == null) {
// ✅ 空值缓存(防穿透),TTL 5分钟
redisTemplate.opsForValue().set(key, NULL_PLACEHOLDER, 5, TimeUnit.MINUTES);
return null;
}
// ✅ 正常缓存,30分钟
redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES);
return user;
}
パターン 3: Redisson分散ロックの3つのパターン
パターンA: tryLock + watchDog(推奨)— 待機時間あり + 自動延長
RLock lock = redissonClient.getLock("lock:order:" + orderId);
// ✅ 只指定 waitTime,不指定 leaseTime → watchDog 生效(默认30s续期)
if (lock.tryLock(10, TimeUnit.SECONDS)) { // 等10秒获取锁
try {
// 业务处理(可能超过30秒,watchDog自动续期)
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
パターンB: tryLock + leaseTime — ハードタイムアウト(Watchdogは機能しません)
RLock lock = redissonClient.getLock("lock:order:" + orderId);
// ⚠️ 指定了 leaseTime → watchDog 不生效
if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
try {
// 必须在30秒内完成,否则锁自动释放
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
パターンC: lock() — ブロッキング待機 + watchDog
RLock lock = redissonClient.getLock("lock:order:" + orderId);
lock.lock(); // 阻塞直到获取锁,watchDog 生效
try {
// 业务处理
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
パターン 4: キャッシュ雪崩対策(ランダムTTL)
// 相同业务场景的缓存 TTL 加随机值,避免同时过期
int baseTtl = 3600; // 1小时
int randomTtl = baseTtl + new Random().nextInt(600); // +0~10分钟随机
redisTemplate.opsForValue().set(key, value, randomTtl, TimeUnit.SECONDS);
パターン 5: キャッシュKeyの規約
// 命名格式: {业务}:{领域}:{实体}:{唯一标识}
private static final String USER_CACHE_KEY = "saas:user:detail:%s";
private static final String ORDER_LIST_KEY = "saas:order:list:%s:%d"; // userId + page
private static final String CONFIG_KEY = "saas:config:global";
String key = String.format(USER_CACHE_KEY, userId);
注意点
- キャッシュには必ず有効期限を設定する — TTLを設定しないとメモリリークが発生します
- Redissonのロックはtry-finallyでunlockする — そうしないとデッドロックが発生します
- watchDogによる自動延長 — leaseTimeを指定しない場合、デフォルトは30秒で、10秒ごとに延長されます
- leaseTimeを指定するとWatchdogは機能しない — 自動延長が必要ならleaseTimeを指定しないでください
- Redisクラスターでは一括mgetを使えない(Slotをまたぐ場合) — getをループするか、hash tagでSlotを固定してください
- キャッシュ雪崩:同時に大量のKeyが期限切れになる — TTLにランダム値(±30%)を加える
- キャッシュスタンピード:ホットKeyの期限切れ直後に大量のリクエストが貫通する — 相互排他ロック、または有効期限を設けず非同期で更新する
- Caffeineは単一サービスの高頻度キャッシュに適しています — Redisは分散共有に、Caffeineはローカルでの高速化に使います
- unlockの前にisHeldByCurrentThread()を確認する — IllegalMonitorStateExceptionを防ぎます
- RedisTemplateのデフォルトはJDKシリアライズ — JSONシリアライズに変更する(読みやすく、言語をまたいで利用可能)
- Lettuce(Spring Bootのデフォルト)はJedisより推奨 — 非同期、コネクションプール、活発なコミュニティ
- ブルームフィルター(RedissonBloomFilter)はキャッシュ貫通対策に使う — Key数が多く、100%の精度が求められない場合に適しています
データプライバシー
本スキルは、ユーザーデータを収集、保存、送信しません。
コメント
Markdown 対応