Redis

📢 この記事は gemini-3-flash-preview によって翻訳されました

Redisの基礎:この記事
Redis分散キャッシュ: https://blog.yexca.net/ja/archives/225/

Redisはメモリベースのkey-value構造のデータベースで、インターネット技術の分野で最も広く使われているストレージミドルウェアなんだ。

Redisはメモリにデータを保存するから読み書きのパフォーマンスがすごく高くて、ホットデータ(商品情報、ニュース、お知らせとか)の保存に向いているよ。C言語で開発されたオープンソースの高性能なキーバリューストアで、扱える値(value)の型が豊富なことから「構造化されたNoSQL(Not Only SQL)」データベースとも呼ばれているんだ。

NoSQLは非リレーショナルデータベースの総称で、リレーショナルデータベースを置き換えるものではなく、それを補完するものとして使われるよ。

リレーショナルデータベース (RDBMS):

  • MySQL
  • Oracle
  • DB2
  • SQLServer

非リレーショナルデータベース (NoSQL):

  • Redis
  • MongoDB
  • MemCached

Redisのダウンロード・インストールと実行

ダウンロード先:

Windows版は解凍するだけで使えるよ。Linux版の手順はこんな感じ:

  1. 解凍する:tar -zxvf redis-4.0.0.tar.gz -C /usr/local
  2. 依存環境をインストールする:yum install gcc-c++
  3. インストールディレクトリに入ってコンパイルする:make
  4. redisのsrcディレクトリに入ってインストールする:make install

関連ファイルの解説:

  • /usr/local/redis-4.0.0/src/redis-server:Redisサーバーの起動スクリプト
  • /usr/local/redis-4.0.0/src/redis-cli:Redisクライアントのスクリプト
  • /usr/local/redis-4.0.0/redis.conf:Redisの設定ファイル

サーバーの起動について。Windows版を例にすると、起動コマンドはこれ:

1
redis-server.exe redis.windows.conf

デフォルトのポート番号は6379で、パスワードは設定されていないよ。起動したらクライアントで接続できる。

  • コマンドラインでの接続

redis-cli.exe を使って接続するよ。

1
redis-cli.exe -h ip -p port -a password

省略した場合は 127.0.0.1:6379 が使われるよ。

設定ファイル (redis.windows.conf) を書き換えてパスワードを設定することもできる。

1
requirepass 123456

書き換えた後は再起動すれば有効になるよ。

  • GUIツールでの接続

Github: https://github.com/qishibo/AnotherRedisDesktopManager

ダウンロードしてインストールしたら、新規接続を作成して情報を入力すれば接続できるよ。


Dockerでのデプロイ

イメージのプル

1
docker pull redis

設定ファイルの取得。対応するバージョンをダウンロードして中身を取り出せばOK。Linuxなら redis.conf だね。

Redisのデータマッピング用フォルダを作成する。例えばこんな感じ:

1
2
mkdir /home/redis
mkdir /home/redis/data

設定ファイルを修正して、デプロイ先のサーバーに送る。例えば Windows から Linux へ scp で送るなら:

1
scp pathOfFile root@IP:/PathOfFile

起動

1
docker run -p 6379:6379 --name redis -v /home/redis/redis.conf:/etc/redis/redis.conf  -v /home/redis/data:/data -d redis redis-server /etc/redis/redis.conf

参考資料: https://cloud.tencent.com/developer/article/1670205


Redisのデータ型

Redisのキー(key)は文字列型だけど、バリュー(value)にはよく使われる5つのデータ型があるよ。

  • 文字列 (string):普通の文字列
  • ハッシュ (hash):連想配列みたいなもの
  • リスト (list):挿入順に並ぶ。重複要素OK
  • セット (set):順序のない集合。重複要素NG
  • ソート済みセット (sorted set/zset):各要素にスコア (score) が紐付いていて、スコア順に並ぶ

Redis データ型

Redisのよく使うコマンド

Redisはコマンドの大文字・小文字を区別しないよ。

文字列操作のよく使うコマンド:

1
2
3
4
5
6
7
8
# 指定したキーの値をセット
SET key value
# 指定したキーの値を取得
GET key
# 指定したキーの値をセットし、有効期限をseconds秒に設定
SETEX key seconds value
# キーが存在しない場合のみ、値をセット
SETNX key value

hashは文字列型のフィールド(field)と値(value)のマップで、オブジェクトを保存するのにぴったりなんだ。よく使うコマンド:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ハッシュ表 key の field に value をセット
HSET key field value
# ハッシュ表に保存されている指定フィールドの値を取得
HGET key field
# ハッシュ表に保存されている指定フィールドを削除
HDEL key field
# ハッシュ表にある全フィールドを取得
HKEYS key
# ハッシュ表にある全値を取得
HVALS key

リストは単純な文字列のリストで、挿入順に並ぶよ。よく使うコマンド:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1つまたは複数の値をリストの先頭に挿入
LPUSH key value1 [value2]
# リストの指定範囲の要素を取得
LRANGE key start stop
# リストの最後の要素を取り出して取得
RPOP key
# リストの長さを取得
LLEN key
# リストの最後の要素を取り出して取得。
# リストが空なら要素が見つかるかタイムアウトするまでブロックする
BRPOP key1 [key2] timeout

キュー(Queue)みたいに、先入れ先出し(FIFO)の動きだね。

セットは文字列型の順序のない集合で、メンバーは一意だよ。よく使うコマンド:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 集合に1つまたは複数のメンバーを追加
SADD key member1 [member2]
# 集合の全メンバーを返す
SMEMBERS key
# 集合のメンバー数を取得
SCARD key
# 指定した全集合の積集合(共通部分)を返す
SINTER key2 [key2]
# 指定した全集合の和集合を返す
SUNION key1 [key2]
# 集合から1つまたは複数のメンバーを削除
SREM key member1 [member2]

ソート済みセットは文字列要素の集合で、各メンバーに double 型のスコアが紐付いているよ。よく使うコマンド:

1
2
3
4
5
6
7
8
# ソート済みセットに1つまたは複数のメンバーを追加
ZADD key score1 member1 [score2 member2]
# インデックス範囲で指定した範囲のメンバーを返す
ZRANGE key start stop [WITHSCORES]
# 指定したメンバーのスコアに increment を加算
ZINCRBY key increment member
# ソート済みセットから1つまたは複数のメンバーを削除
ZREM key member1 [member2]

各データ型専用のコマンド以外に、どの型でも使える共通コマンドもあるよ:

1
2
3
4
5
6
7
8
# パターン(pattern)に一致する全キーを探す
KEYS pattern # patternには * とかが使える
# 指定したキーが存在するか確認
EXISTS key
# キーに保存されている値の型を返す
TYPE key
# キーが存在すれば削除
DEL key

JavaでRedisを操作する

JDBCを使ってMySQLを操作するのと同じように、RedisもJava用のクライアントを使って操作する必要があるんだ。

RedisのJavaクライアントはたくさんあるけど、有名なのはこのあたり:

  • Jedis
  • Lettuce
  • Spring Data Redis

Jedisはカプセル化が一番しっかりしていて、Redisのコマンドと同じ感覚で使えるから公式でも推奨されているよ。Lettuceはスレッド呼び出しの扱いが上手くてパフォーマンスが良いのが特徴。Springはこれらのクライアントを統合してSpring Data Redisを提供していて、Spring Bootプロジェクトなら専用のStarter(spring-boot-starter-data-redis)も用意されているよ。

Spring Data Redis

Spring Data RedisはSpringプロジェクトの一部で、簡単な設定だけでRedisサーバーにアクセスできるように、低レイヤーのライブラリを高度にカプセル化してくれているんだ。SpringプロジェクトでRedisを楽に扱いたいならこれを使おう。サイト: https://spring.io/projects/spring-data-redis

Mavenの依存関係:

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Spring Data Redisでは、RedisTemplate という高度にカプセル化されたクラスが提供されていて、操作のタイプごとに専用のインターフェースにまとめられているよ:

  • ValueOperations:string型のデータ操作
  • SetOperations:set型のデータ操作
  • ZSetOperations:zset型のデータ操作
  • HashOperations:hash型のデータ操作
  • ListOperations:list型のデータ操作

Redisデータソースの設定(設定ファイル):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# application
spring:
  profiles:
    active: dev
  redis:
    host: ${sky.redis.host}
    port: ${sky.redis.port}
    password: ${sky.redis.password}
    database: ${sky.redis.database}

# -dev
sky:
  redis:
    host: localhost
    port: 6379
    password: 123456
    # どのデータベースを使うか。指定しない場合は 0
    database: 10 

Redisはデフォルトで16個のデータベース(0-15)を持っていて、設定でその数を変更することもできるよ。

設定クラスを書いて、RedisTemplateオブジェクトを作成する:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Configuration
@Slf4j
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        log.info("Redisオブジェクトの作成を開始します");
        RedisTemplate redisTemplate = new RedisTemplate();
        // redisの接続ファクトリをセット
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // redisキーのシリアライザをセット
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

この設定クラスは必須じゃないんだ。SpringBootが自動で RedisTemplate を自動構成してくれるけど、デフォルトのシリアライザが JdkSerializationRedisSerializer だから、Redisに保存されたデータが元のデータと少し違って見えることがあるんだよね。

文字列型のデータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@SpringBootTest
public class RedisTest {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    public void testString(){
        // set
        redisTemplate.opsForValue().set("name", "Tom");
        // get
        String name =(String) redisTemplate.opsForValue().get("name");
        System.out.println(name);
        // setex
        redisTemplate.opsForValue().set("code", "1234", 2, TimeUnit.MINUTES);
        // setnx
        redisTemplate.opsForValue().setIfAbsent("lock","1");
        redisTemplate.opsForValue().setIfAbsent("lock","2");
    }
}

ハッシュ型のデータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Test
public void testHash(){
    HashOperations hashOperations = redisTemplate.opsForHash();
    // hset
    hashOperations.put("100", "name", "Jerry");
    hashOperations.put("100", "age", "20");
    // hget
    String name =(String) hashOperations.get("100", "name");
    System.out.println(name);
    // hkeys
    Set keys = hashOperations.keys("100");
    System.out.println(keys);
    // hvals
    List values = hashOperations.values("100");
    System.out.println(values);
    // hdel
    hashOperations.delete("100", "name");
}

リスト型のデータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Test
public void testList(){
    ListOperations listOperations = redisTemplate.opsForList();
    // lpush
    listOperations.leftPushAll("mylist", "a", "b", "c");
    listOperations.leftPush("mylist", "d");
    // lrange
    List mylist = listOperations.range("mylist", 0, -1);
    System.out.println(mylist);
    // rpop
    listOperations.rightPop("mylist");
    // llen
    Long size = listOperations.size("mylist");
    System.out.println(size);
}

セット型のデータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void testSet(){
    SetOperations setOperations = redisTemplate.opsForSet();
    // sadd
    setOperations.add("set1","a","b","c","d");
    setOperations.add("set2","a","b","x","y");
    // smembers
    Set members = setOperations.members("set1");
    System.out.println(members);
    // scard
    Long size = setOperations.size("set1");
    System.out.println(size);
    // sinter
    Set intersect = setOperations.intersect("set1", "set2");
    System.out.println(intersect);
    // sunion
    Set union = setOperations.union("set1", "set2");
    System.out.println(union);
    // srem
    setOperations.remove("set1", "a", "b");
}

ソート済みセット型のデータ

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@Test
public void testZset(){
    ZSetOperations zSetOperations = redisTemplate.opsForZSet();
    // zadd
    zSetOperations.add("zset1", "a", 10);
    zSetOperations.add("zset1", "b", 12);
    zSetOperations.add("zset1", "c", 9);
    // zrange
    Set zset = zSetOperations.range("zset1", 0, -1);
    System.out.println(zset);
    // zincrby
    zSetOperations.incrementScore("zset1", "c", 10);
    // zrem
    zSetOperations.remove("zset1", "a", "b");
}

共通コマンドの操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Test
public void testCommon(){
    // keys
    Set keys = redisTemplate.keys("*");
    System.out.println(keys);
    // exists
    Boolean name = redisTemplate.hasKey("name");
    System.out.println(name);
    // type
    for (Object key : keys) {
        DataType type = redisTemplate.type(key);
        System.out.println(type.name());
    }
    // del
    redisTemplate.delete("set2");
}

Visits Since 2025-02-28

Hugo で構築されています。 | テーマ StackJimmy によって設計されています。