Redisson

JavaキャッシュライブラリRedis分散システムNettyインメモリ

GitHub概要

redisson/redisson

Redisson - Valkey & Redis Java client. Real-Time Data Platform. Sync/Async/RxJava/Reactive API. Over 50 Valkey and Redis based Java objects and services: Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Spring, Tomcat, Scheduler, JCache API, Hibernate, RPC, local cache..

スター24,074
ウォッチ871
フォーク5,483
作成日:2014年1月11日
言語:Java
ライセンス:Apache License 2.0

トピックス

cachedistributeddistributed-locksexecutorhibernatejavajsonlockmapmicronautquarkusqueueredisredis-clientschedulersessionspringtomcatvalkeyvalkey-client

スター履歴

redisson/redisson Star History
データ取得日時: 2025/10/22 10:04

キャッシュライブラリ

Redisson

概要

RedissonはJava向けのRedis/Valkeyクライアントライブラリで、50以上の分散オブジェクトとサービスを提供し、Nettyベースの非同期イベント駆動フレームワーク上に構築された高性能なリアルタイムデータプラットフォームです。

詳細

Redisson(レディッソン)は、RedisおよびValkeyサーバーと連携するJava向けのクライアントライブラリで、インメモリデータグリッドとして50以上の分散オブジェクトとサービスを提供します。Set、Multimap、SortedSet、Map、List、Queue、Deque、Semaphore、Lock、AtomicLong、MapReduce、Bloomフィルター、Spring統合、Tomcat統合、スケジューラー、JCache API、Hibernate、RPC、ローカルキャッシュなどの豊富な機能を備えています。Netty非同期イベント駆動クライアント・サーバーフレームワークを基盤とし、Redis 2.8以上およびJDK 1.8以上と互換性があります。同期/非同期/RxJava/ReactiveAPIをサポートし、馴染みのあるJavaコレクションとデータ構造をRedis上で利用できるため、標準インターフェースを知っているJava開発者にとって学習コストがほぼゼロです。Spring framework、Spring Boot Starter、Spring Cache、Spring Session、Spring Transaction Manager、Spring Cloud Stream、Spring Data Redisとの統合を提供し、Amazon ElastiCache、Amazon MemoryDB、Azure Cache for Redis、Redis Enterprise、Google Cloud Memorystore、その他多数のクラウドプロバイダーに対応しています。ベンチマークテストによると、Redisson PROはJedisよりも高速で、Redisの性能を55,000-75,000 ops/secから100,000-213,000 ops/secまで向上させることができます。

メリット・デメリット

メリット

  • 高性能: Nettyベースで非同期処理による高速な操作
  • 豊富な機能: 50以上の分散オブジェクトとサービスを提供
  • 学習コスト低: 標準のJavaコレクションインターフェースを使用
  • 多API対応: 同期、非同期、RxJava、Reactiveの全てをサポート
  • フレームワーク統合: Spring、Hibernate等との深い統合
  • クラウド対応: 主要クラウドプロバイダーとの完全互換性
  • 分散機能: 分散ロック、セマフォ、MapReduce等の高度な機能

デメリット

  • 複雑性: 豊富な機能により設定や使用方法が複雑になる場合がある
  • メモリ使用量: Nettyとオブジェクト管理により比較的多くのメモリを使用
  • 学習曲線: 高度な分散機能の習得には時間が必要
  • 依存関係: Nettyやその他の依存ライブラリが必要
  • オーバーヘッド: 軽量なクライアントと比較して初期化コストが高い

主要リンク

書き方の例

インストールと基本設定

<!-- Maven依存関係 -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.30.0</version>
</dependency>

<!-- Spring Boot統合の場合 -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson-spring-boot-starter</artifactId>
    <version>3.30.0</version>
</dependency>
// 基本的な接続設定
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;

public class RedissonExample {
    public static void main(String[] args) {
        // 設定オブジェクトの作成
        Config config = new Config();
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              .setPassword("password")
              .setDatabase(0)
              .setConnectionMinimumIdleSize(10)
              .setConnectionPoolSize(64)
              .setIdleConnectionTimeout(10000)
              .setConnectTimeout(10000)
              .setTimeout(3000)
              .setRetryAttempts(3)
              .setRetryInterval(1500);

        // Redissonクライアントの作成
        RedissonClient redisson = Redisson.create(config);
        
        // 使用後はシャットダウン
        redisson.shutdown();
    }
}

基本的なオブジェクト操作

import org.redisson.api.*;

public class BasicOperations {
    private RedissonClient redisson;
    
    public void basicOperations() {
        // RBucket - 単一値の保存
        RBucket<String> bucket = redisson.getBucket("myBucket");
        bucket.set("Hello, Redisson!");
        String value = bucket.get();
        System.out.println(value); // "Hello, Redisson!"
        
        // 期限付きオブジェクト
        bucket.set("temporary", 60, TimeUnit.SECONDS);
        
        // RMap - Mapインターフェース
        RMap<String, String> map = redisson.getMap("myMap");
        map.put("key1", "value1");
        map.put("key2", "value2");
        
        // ローカルMapのようにアクセス
        String val = map.get("key1");
        boolean exists = map.containsKey("key2");
        map.remove("key1");
        
        // RList - Listインターフェース
        RList<String> list = redisson.getList("myList");
        list.add("item1");
        list.add("item2");
        list.add(0, "first");
        
        String first = list.get(0);
        list.remove("item1");
        
        // RSet - Setインターフェース
        RSet<String> set = redisson.getSet("mySet");
        set.add("element1");
        set.add("element2");
        boolean added = set.add("element1"); // false - 既に存在
        
        // RQueue - Queueインターフェース
        RQueue<String> queue = redisson.getQueue("myQueue");
        queue.offer("task1");
        queue.offer("task2");
        String task = queue.poll(); // "task1"
    }
}

非同期操作

import org.redisson.api.*;
import java.util.concurrent.CompletableFuture;

public class AsyncOperations {
    private RedissonClient redisson;
    
    public void asyncOperations() {
        RBucket<String> bucket = redisson.getBucket("asyncBucket");
        
        // 非同期でセット
        RFuture<Void> setFuture = bucket.setAsync("async value");
        setFuture.whenComplete((result, exception) -> {
            if (exception == null) {
                System.out.println("Set completed successfully");
            } else {
                System.err.println("Set failed: " + exception.getMessage());
            }
        });
        
        // 非同期でゲット
        RFuture<String> getFuture = bucket.getAsync();
        getFuture.thenAccept(value -> {
            System.out.println("Retrieved value: " + value);
        });
        
        // チェーンした非同期操作
        bucket.setAsync("initial")
              .thenCompose(v -> bucket.getAsync())
              .thenCompose(value -> {
                  System.out.println("Current value: " + value);
                  return bucket.setAsync("updated");
              })
              .thenRun(() -> System.out.println("All operations completed"));
    }
}

分散ロック

import org.redisson.api.*;
import java.util.concurrent.TimeUnit;

public class DistributedLocking {
    private RedissonClient redisson;
    
    public void lockExample() {
        RLock lock = redisson.getLock("myLock");
        
        try {
            // ロック取得(ブロッキング)
            lock.lock();
            
            // クリティカルセクション
            System.out.println("Critical section executed");
            Thread.sleep(1000);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // ロック解放
            lock.unlock();
        }
    }
    
    public void tryLockExample() {
        RLock lock = redisson.getLock("myTryLock");
        
        try {
            // タイムアウト付きロック取得
            boolean acquired = lock.tryLock(100, 10, TimeUnit.SECONDS);
            
            if (acquired) {
                try {
                    // クリティカルセクション
                    System.out.println("Lock acquired, executing critical section");
                    
                } finally {
                    lock.unlock();
                }
            } else {
                System.out.println("Failed to acquire lock within timeout");
            }
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    public void multiLockExample() {
        RLock lock1 = redisson.getLock("lock1");
        RLock lock2 = redisson.getLock("lock2");
        RLock lock3 = redisson.getLock("lock3");
        
        // 複数のロックを同時に取得
        RLock multiLock = redisson.getMultiLock(lock1, lock2, lock3);
        
        try {
            multiLock.lock();
            
            // 全てのロックが取得された状態での処理
            System.out.println("All locks acquired");
            
        } finally {
            multiLock.unlock();
        }
    }
}

セマフォとカウントダウンラッチ

import org.redisson.api.*;

public class SynchronizationPrimitives {
    private RedissonClient redisson;
    
    public void semaphoreExample() {
        RSemaphore semaphore = redisson.getSemaphore("mySemaphore");
        
        try {
            // 許可数を設定(初期化)
            semaphore.trySetPermits(3);
            
            // 許可を取得
            semaphore.acquire();
            
            // リソースを使用
            System.out.println("Using limited resource");
            Thread.sleep(1000);
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 許可を解放
            semaphore.release();
        }
    }
    
    public void countDownLatchExample() {
        RCountDownLatch latch = redisson.getCountDownLatch("myLatch");
        
        // ラッチの初期カウントを設定
        latch.trySetCount(3);
        
        // 別スレッドでカウントダウン
        new Thread(() -> {
            try {
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 1 completed");
                
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 2 completed");
                
                Thread.sleep(1000);
                latch.countDown();
                System.out.println("Task 3 completed");
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }).start();
        
        try {
            // 全てのタスクの完了を待機
            latch.await();
            System.out.println("All tasks completed!");
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

Reactive/RxJava操作

import org.redisson.api.*;
import org.redisson.api.redissonrx.*;
import reactor.core.publisher.Mono;
import io.reactivex.rxjava3.core.Single;

public class ReactiveOperations {
    private RedissonClient redisson;
    
    public void reactiveExample() {
        // Reactiveクライアントの取得
        RedissonReactiveClient reactiveClient = redisson.reactive();
        
        RBucketReactive<String> bucket = reactiveClient.getBucket("reactiveBucket");
        
        // Reactive操作のチェーン
        Mono<Void> operation = bucket.set("reactive value")
            .then(bucket.get())
            .doOnNext(value -> System.out.println("Value: " + value))
            .then(bucket.delete())
            .then();
        
        // 実行
        operation.subscribe(
            result -> System.out.println("Operation completed"),
            error -> System.err.println("Error: " + error.getMessage())
        );
    }
    
    public void rxJavaExample() {
        // RxJavaクライアントの取得
        RedissonRxClient rxClient = redisson.rxJava();
        
        RBucketRx<String> bucket = rxClient.getBucket("rxBucket");
        
        // RxJava操作のチェーン
        Single<String> operation = bucket.set("rx value")
            .andThen(bucket.get())
            .doOnSuccess(value -> System.out.println("RxJava Value: " + value));
        
        // 実行
        operation.subscribe(
            result -> System.out.println("RxJava operation completed: " + result),
            error -> System.err.println("RxJava error: " + error.getMessage())
        );
    }
}

Pub/Sub機能

import org.redisson.api.*;

public class PubSubOperations {
    private RedissonClient redisson;
    
    public void publishSubscribe() {
        // パブリッシャー
        RTopic topic = redisson.getTopic("myTopic");
        
        // サブスクライバー
        topic.addListener(String.class, (channel, msg) -> {
            System.out.println("Received message: " + msg + " from channel: " + channel);
        });
        
        // メッセージ送信
        topic.publish("Hello, subscribers!");
        
        // パターンマッチングサブスクリプション
        RPatternTopic patternTopic = redisson.getPatternTopic("news.*");
        patternTopic.addListener(String.class, (pattern, channel, msg) -> {
            System.out.println("Pattern: " + pattern + ", Channel: " + channel + ", Message: " + msg);
        });
        
        // パターンにマッチするチャンネルに送信
        redisson.getTopic("news.sports").publish("Sports news update");
        redisson.getTopic("news.tech").publish("Tech news update");
    }
    
    public void reliableTopic() {
        // 信頼性のあるトピック(メッセージの永続化)
        RReliableTopic topic = redisson.getReliableTopic("reliableTopic");
        
        String listenerId = topic.addListener(String.class, (channel, msg) -> {
            System.out.println("Reliable message: " + msg);
        });
        
        // メッセージ送信
        topic.publish("Reliable message 1");
        topic.publish("Reliable message 2");
        
        // リスナー削除
        topic.removeListener(listenerId);
    }
}

トランザクション処理

import org.redisson.api.*;

public class TransactionOperations {
    private RedissonClient redisson;
    
    public void transactionExample() {
        RTransaction transaction = redisson.createTransaction(TransactionOptions.defaults());
        
        try {
            // トランザクション内での操作
            RBucket<String> bucket = transaction.getBucket("txBucket");
            RMap<String, String> map = transaction.getMap("txMap");
            
            bucket.set("transaction value");
            map.put("key1", "value1");
            map.put("key2", "value2");
            
            // トランザクションのコミット
            transaction.commit();
            System.out.println("Transaction committed successfully");
            
        } catch (Exception e) {
            // エラー時はロールバック
            transaction.rollback();
            System.err.println("Transaction rolled back: " + e.getMessage());
        }
    }
    
    public void batchOperations() {
        // バッチ操作(パイプライニング)
        RBatch batch = redisson.createBatch();
        
        RBucketAsync<String> bucket1 = batch.getBucket("batch1");
        RBucketAsync<String> bucket2 = batch.getBucket("batch2");
        RMapAsync<String, String> map = batch.getMap("batchMap");
        
        // バッチに操作を追加
        bucket1.setAsync("batch value 1");
        bucket2.setAsync("batch value 2");
        map.putAsync("batchKey", "batchValue");
        
        // バッチ実行
        BatchResult<?> results = batch.execute();
        System.out.println("Batch executed, results count: " + results.getResponses().size());
    }
}

MapReduce処理

import org.redisson.api.*;
import org.redisson.mapreduce.*;

public class MapReduceOperations {
    private RedissonClient redisson;
    
    public void mapReduceExample() {
        RMap<String, String> map = redisson.getMap("sourceMap");
        
        // テストデータの挿入
        map.put("line1", "Alice was beginning to get very tired");
        map.put("line2", "of sitting by her sister on the bank");
        map.put("line3", "and of having nothing to do");
        
        // MapReduceタスクの設定
        RMapReduce<String, String, String, Integer> mapReduce = map
            .<String, Integer>mapReduce()
            .mapper(new WordMapper())
            .reducer(new WordReducer());
        
        // 実行
        Map<String, Integer> result = mapReduce.execute();
        
        result.forEach((word, count) -> 
            System.out.println(word + ": " + count));
    }
    
    // Mapperクラス
    public static class WordMapper implements RMapper<String, String, String, Integer> {
        @Override
        public void map(String key, String value, RCollector<String, Integer> collector) {
            String[] words = value.toLowerCase().split("\\W+");
            for (String word : words) {
                if (!word.isEmpty()) {
                    collector.emit(word, 1);
                }
            }
        }
    }
    
    // Reducerクラス
    public static class WordReducer implements RReducer<String, Integer> {
        @Override
        public Integer reduce(String key, Iterator<Integer> values) {
            int sum = 0;
            while (values.hasNext()) {
                sum += values.next();
            }
            return sum;
        }
    }
}

Spring Boot統合

// application.yml
/*
spring:
  redis:
    redisson:
      config: |
        singleServerConfig:
          address: "redis://localhost:6379"
          password: null
          database: 0
          connectionMinimumIdleSize: 10
          connectionPoolSize: 64
          idleConnectionTimeout: 10000
          connectTimeout: 10000
          timeout: 3000
*/

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.redisson.api.*;

@Service
public class RedissonService {
    
    @Autowired
    private RedissonClient redissonClient;
    
    public void cacheUserData(String userId, Object userData) {
        RBucket<Object> bucket = redissonClient.getBucket("user:" + userId);
        bucket.set(userData, 1, TimeUnit.HOURS);
    }
    
    public Object getUserData(String userId) {
        RBucket<Object> bucket = redissonClient.getBucket("user:" + userId);
        return bucket.get();
    }
    
    public void addToUserSessions(String userId, String sessionId) {
        RSet<String> sessions = redissonClient.getSet("sessions:" + userId);
        sessions.add(sessionId);
        sessions.expire(24, TimeUnit.HOURS);
    }
    
    public boolean isUserOnline(String userId) {
        RSet<String> sessions = redissonClient.getSet("sessions:" + userId);
        return !sessions.isEmpty();
    }
}

パフォーマンス最適化

public class PerformanceOptimization {
    
    public RedissonClient createOptimizedClient() {
        Config config = new Config();
        
        // 単一サーバー設定の最適化
        config.useSingleServer()
              .setAddress("redis://localhost:6379")
              // 接続プール設定
              .setConnectionPoolSize(64)
              .setConnectionMinimumIdleSize(10)
              // タイムアウト設定
              .setConnectTimeout(10000)
              .setTimeout(3000)
              .setIdleConnectionTimeout(10000)
              // リトライ設定
              .setRetryAttempts(3)
              .setRetryInterval(1500)
              // DNS監視無効化(パフォーマンス向上)
              .setDnsMonitoringInterval(-1);
        
        // パフォーマンス設定
        config.setThreads(16); // NIOスレッド数
        config.setNettyThreads(32); // Nettyスレッド数
        config.setCodec(org.redisson.codec.KryoCodec.INSTANCE); // 高速シリアライゼーション
        
        return Redisson.create(config);
    }
    
    public void localCacheExample() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://localhost:6379");
        
        RedissonClient redisson = Redisson.create(config);
        
        // ローカルキャッシュ付きMap
        LocalCachedMapOptions<String, String> options = LocalCachedMapOptions.<String, String>defaults()
            .evictionPolicy(LocalCachedMapOptions.EvictionPolicy.LRU)
            .cacheSize(1000)
            .timeToLive(10, TimeUnit.MINUTES)
            .maxIdle(5, TimeUnit.MINUTES);
        
        RLocalCachedMap<String, String> map = redisson.getLocalCachedMap("cachedMap", options);
        
        // 初回はRedisから取得、以降はローカルキャッシュから
        map.put("key1", "value1");
        String value = map.get("key1"); // ローカルキャッシュから高速取得
    }
}