Redissonの分散タスクスケジューリング:スケジュールされたタスクと周期タスク
分散システムにおいて、従来のスケジュールされたタスクはいくつかの重要な課題に直面します。単一障害点によるタスクの中断、クラスタ環境での重複実行、タスク状態の追跡の困難さなどが挙げられます。RedissonはRedisを基盤とした分散タスクスケジューリング機能を提供し、RScheduledExecutorServiceインターフェースを通じて高可用性のスケジューリングを実現し、これらの問題を解決します。本記事では、実際のユースケースに基づき、2種類のタスクの実装方法とベストプラクティスを詳しく解説します。
コア機能の解説
Redissonの分散タスクスケジューリングは、RedisのPub/SubメカニズムとSorted Setデータ構造を利用してタスクの分散調整を実現しています。主な利点は以下の通りです。
- 高可用性:タスクのメタデータをRedisクラスタに保存し、単一障害点を回避します。
- 分散ロック:クラスタ環境下でタスクが一度だけ実行されることを保証します。
- 柔軟なスケジューリング:Cron式に基づく複雑な周期スケジューリングをサポートします。
- 状態追跡:タスクの実行状態のクエリと結果の取得を提供します。
主要なインターフェースの設計は以下の通りです。
// 分散スケジューラサービスの取得
RScheduledExecutorService scheduler = redisson.getExecutorService("myScheduler");
// スケジュールされたタスクの実行
scheduler.schedule(myTask, 10, TimeUnit.MINUTES);
// Cron式による周期タスク
scheduler.schedule(myTask, CronSchedule.of("0 */2 * * * ?"));
スケジュールされたタスクの実装
スケジュールされたタスクは、指定された遅延後に一度だけ実行されるシナリオに適しています。例えば、注文のタイムアウト処理や会議のリマインダーなどです。実装手順は以下の通りです。
1. Redissonクライアントの作成
Spring Bootの自動設定クラスRedissonAutoConfigurationを利用してRedissonClientインスタンスを初期化します。
@Autowired
private RedissonClient redisson;
2. タスクロジックの定義
Runnableインターフェースを実装したタスククラスを作成し、具体的なビジネスロジックを記述します。
public class PaymentExpirationTask implements Runnable {
private Long paymentId;
@Override
public void run() {
// 支払い期限切れの処理を実行
paymentService.processExpiredPayment(paymentId);
}
}
3. スケジュールされたタスクの送信
RScheduledExecutorServiceを使用して遅延タスクを送信します。
// スケジューラサービスのインスタンスを取得
RScheduledExecutorService scheduler = redisson.getExecutorService("paymentScheduler");
// 15分後に実行されるタスクを送信
scheduler.schedule(
new PaymentExpirationTask(67890L),
15,
TimeUnit.MINUTES
);
周期タスクの実装
周期タスクは、データバックアップやレポート生成など、繰り返し実行されるビジネスシナリオに適しています。Redissonは、固定間隔実行とCron式スケジューリングの2種類の周期スケジューリングを提供します。
固定間隔スケジューリング
scheduleAtFixedRateメソッドを使用して固定頻度で実行します。
// 初期遅延5秒、その後30秒ごとに実行
scheduler.scheduleAtFixedRate(
new CacheRefreshTask(),
5,
30,
TimeUnit.SECONDS
);
Cron式スケジューリング
複雑なスケジューリング要件には、CronScheduleクラスを使用してCron式を構築します。
// 毎日午前2時にデータアーカイブを実行
scheduler.schedule(
new LogCleanupTask(),
CronSchedule.dailyAtHourAndMinute(2, 0)
);
// 月曜、水曜、金曜の午後3時に売上レポートを生成
scheduler.schedule(
new SalesReportTask(),
CronSchedule.of("0 0 15 ? * MON,WED,FRI")
);
高度な機能とベストプラクティス
タスク状態の管理
RScheduledFutureインターフェースを通じてタスクの状態を追跡できます。
RScheduledFuture> scheduledFuture = scheduler.schedule(myTask, 5, TimeUnit.SECONDS);
// タスクのキャンセル
scheduledFuture.cancel(true);
// タスク状態のクエリ
if (scheduledFuture.isDone()) {
System.out.println("タスクは完了しました");
}
タスクの永続化設定
Spring Boot環境では、設定クラスを使用してスケジューラのプロパティをカスタマイズできます。
@Configuration
public class CustomRedissonSchedulerConfig {
@Bean
public RedissonAutoConfigurationCustomizer schedulerCustomizer() {
return config -> {
// タスク実行スレッドプールのサイズを設定
config.useExecutorService()
.setCorePoolSize(8)
.setMaximumPoolSize(16);
};
}
}
障害復旧メカニズム
タスク実行ノードに障害が発生した場合でも、Redis内のタスクメタデータは失われません。RedissonExecutorServiceの障害検出メカニズムにより、他のノードが自動的に実行を引き継ぎます。
// タスクタイムアウト検出を有効化(デフォルト30秒)
scheduler.setTaskTimeout(45000);
典型的なユースケース
電子商取引注文システム
- シナリオ:注文作成後30分以内に支払いが完了しない場合、自動的にキャンセルする。
- 実装:スケジュールされたタスクを使用し、Redisの分散ロックと組み合わせて重複キャンセルを防止する。
- キーコード:RedissonExecutorService.schedule
データ同期サービス
- シナリオ:毎時、異なる地域のデータベースデータを同期する。
- 実装:CronScheduleで「0 0 */1 * * ?」を設定して周期実行する。
- コアクラス:CronSchedule.monthlyOnDayAndHourAndMinute
まとめと注意点
Redissonの分散タスクスケジューリングは、redisson-spring-boot-starterモジュールを通じてSpringエコシステムとシームレスに統合されます。実際の使用においては、以下の点に注意する必要があります。
- タスククラスは
Serializableインターフェースを実装し、シリアル化可能であることを確認してください。 - タスク内での長時間ブロッキング操作の実行は避けてください。
- 高並行シナリオでは、適切なスレッドプールパラメータを設定することを推奨します。
- 重要なタスクはべき等性設計を実装し、重複実行を防ぐ必要があります。
完全なAPIドキュメントはRedissonの公式ドキュメントを参照してください。より多くのサンプルコードはredisson-spring-boot-starter/src/test/java/org/redisson/spring/starterのテストケースにあります。Redissonの分散タスクスケジューリング機能を適切に活用することで、システムの信頼性と拡張性を大幅に向上させることができます。