以下の内容はhttps://thinkami.hatenablog.com/entry/2026/02/02/202424より取得しました。


Rails8.1系で、レプリカのあるRedis(スタンドアロンやクラスター)をセッションストアに設定してみた

前々回、前回と、Redisクラスターを使ったセッションストア設定などを試してきました。

 
これらの記事ではRedisにはレプリカはありませんでした。

そこで今回は、レプリカのあるRedis(スタンドアロンクラスター)をセッションストアに設定してみたことから、メモを残します。

 
目次

 

環境

  • mac
  • RubyMine 2025.3.2
  • docker compose
    • 次の各構成のRedisを用意
    • Redisのバージョンは8.4
  • Ruby 3.4.8
  • Rails 8.1.2
  • redis 5.4.1
  • redis-actionpack 5.5.0
  • redis-clustering 5.4.1

 
なお、今回のRedisはいずれも --protected-mode no としているため、開発用途であることに注意してください。

 

レプリカありのスタンドアロンRedisをセッションストアにする

まずは、docker composeでレプリカありのスタンドアロンRedisを用意します。

services:
  redis-master:
    image: redis:8.4.0-bookworm
    container_name: redis-master
    ports:
      - "17000:6379"
    command: ["redis-server", "--save", "", "--appendonly", "no", "--protected-mode", "no"]
    restart: unless-stopped
    networks:
      - redis-network

  redis-replica:
    image: redis:8.4.0-bookworm
    container_name: redis-replica
    depends_on:
      - redis-master
    ports:
      - "17001:6379"
    command:
      - "redis-server"
      - "--save"
      - ""
      - "--appendonly"
      - "no"
      - "--protected-mode"
      - "no"
      - "--replicaof"
      - "redis-master"
      - "6379"
    restart: unless-stopped
    networks:
      - redis-network

networks:
  redis-network:
    name: redis-network

 
スタンドアロンRedisを config.session_store へ設定する方法としては、次の2つがあります。

  • redis + redis-actionpack による :redis_store
  • redis gemによる :cache_store

 
それぞれ見ていきます。

 

redis gem + redis-actionpack gemによる :redis_store

まずは、以前見た通り、 redis-rails で紹介されていた redis-actionpack を使います。

 
bundle add します。

% bundle add redis-actionpack 
...
Installing redis-client 0.26.4
Installing redis 5.4.1
Installing redis-store 1.11.0
Installing redis-rack 3.0.0
Installing redis-actionpack 5.5.0

 
config.session_store:redis_store を指定します。セッションへの書き込みはマスターが担うため、 host にはマスターのみ記載します。

Rails.application.config.session_store :redis_store,
                                       servers: [
                                         {
                                           host: "redis-master",
                                           port: 6379,
                                           db: 0,
                                           namespace: "session"
                                         }
                                       ],
                                       expire_after: 90.minutes,
                                       key: "_redis_session"

 
セッションストアの準備ができたため、 curl で動作確認します。

% curl -X POST http://localhost:3000/hellos -c cookies.txt

% curl -b cookies.txt http://localhost:3000/hellos
{
"current_timestamp":"2026/02/01 09:09:41",
"session_timestamp":"session -> 2026/02/01 09:09:18"
}

 
RubyMineでRedisを確認します。マスターとレプリカの両方にデータが保存されていました。

 
続いて、Redis CLIで確認します。まずはマスターから。

$ redis-cli -c -h redis-master -p 6379 --scan
"session:2::a14166c3a800c290a64b1cb55e828499f911cf51e87e9d7c8f187909ba101131"

$ redis-cli -c -h redis-master -p 6379 get "session:2::a14166c3a800c290a64b1cb55e828499f911cf51e87e9d7c8f187909ba101131"
"\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 09:09:18\x06;\x00T"

 
続いてレプリカを確認します。マスターとレプリカとも、同じ値が保存されていました。

$ redis-cli -c -h redis-replica -p 6379 --scan
"session:2::a14166c3a800c290a64b1cb55e828499f911cf51e87e9d7c8f187909ba101131"

$ redis-cli -c -h redis-replica -p 6379 get "session:2::a14166c3a800c290a64b1cb55e828499f911cf51e87e9d7c8f187909ba101131"
"\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 09:09:18\x06;\x00T"

 

redis gemによる :cache_store

以前の記事で、セッションストアに :cache_store を指定してRedisクラスターへ接続しました。
Rails8.1系で、Redisクラスターをセッションストアとして設定してみた - メモ的な思考的な

しかし、Redisクラスターでなくても :cache_store を使えそうな気がしたので、今回試してみます。

 
まず、 redis-actionpack の影響を受けないよう、Gemfileから redis-actionpack を削除します。

次に、 config.session_store:cache_store を使うように設定します。 redis-actionpack の時と同様の内容として、ポート 6379 、DB番号 0 としたURLを url へ設定します。

Rails.application.config.session_store :cache_store,
                                       cache: ActiveSupport::Cache::RedisCacheStore.new(
                                         url: "redis://redis-master:6379/0",
                                       ),
                                       expire_after: 90.minutes,
                                       key: "_redis_session"

 
この状態で起動しようとしたところ、次のエラーになり、Railsが起動できませんでした。

The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem "redis", ">= 4.0.1"`
/home/vscode/.local/share/mise/installs/ruby/3.4.8/lib/ruby/3.4.0/bundler/rubygems_integration.rb:215:in 'block (2 levels) in Kernel#replace_gem': redis is not part of the bundle. Add it to your Gemfile. (Gem::LoadError)

 
エラーメッセージにある通り、 redis gemを追加します。

$ bundle add redis

 
続いて bin/rails s によりRailsを起動できたことから、動作を確認します。セッションへ保存できたようです。

% curl -X POST http://localhost:3000/hellos -c cookies.txt

% curl -b cookies.txt http://localhost:3000/hellos
{
"current_timestamp":"2026/02/01 12:55:24",
"session_timestamp":"session -> 2026/02/01 12:55:19"
}

 
この時のCookieの中身である cookies.txt は次のようになっていました。 key で指定した _redis_session が存在します。

# Netscape HTTP Cookie File
# https://curl.se/docs/http-cookies.html
# This file was generated by libcurl! Edit at your own risk.

#HttpOnly_localhost FALSE   /   FALSE   1769955919  _redis_session  0672f5df97a0ad2a01ba341fc40408cc

 
保存できたデータを確認します。

RubyMineで確認したところ、マスターとレプリカ両方に同じデータが保存されていました。

 
続いて、Redis CLIでも確認します。まずはマスター。

$ redis-cli -c -h redis-master -p 6379 --scan
"_session_id:2::cd13db8f939847990bacc6475ab8aa198ee83e72205fb24b09684134a8db4ca5"

$ redis-cli -c -h redis-master -p 6379 get "_session_id:2::cd13db8f939847990bacc6475ab8aa198ee83e72205fb24b09684134a8db4ca5"
"\x00\x11\x01AT\x06\x95\xd8_\xdaA\xff\xff\xff\xff\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 12:55:19\x06;\x00T"

 
続いてレプリカです。マスターと同じ値でした。

$ redis-cli -c -h redis-replica -p 6379 --scan
"_session_id:2::cd13db8f939847990bacc6475ab8aa198ee83e72205fb24b09684134a8db4ca5"

$ redis-cli -c -h redis-replica -p 6379 get "_session_id:2::cd13db8f939847990bacc6475ab8aa198ee83e72205fb24b09684134a8db4ca5"
"\x00\x11\x01AT\x06\x95\xd8_\xdaA\xff\xff\xff\xff\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 12:55:19\x06;\x00T"

 
これより、 config.session_store:cache_store を設定するのであれば、必要なgemは redis だけにできそうです。

 

レプリカありのRedisクラスターをセッションストアにする

続いて、レプリカのあるRedisクラスターをセッションストアにしてみます。

 

マスターノードが1つだけではRedisクラスターを構成できない

Redisクラスターを構成するためには、最低いくつのノードを用意すればよいか調べたところ、公式ドキュメントに次の記述がありました。

Note that the minimal cluster that works as expected must contain at least three master nodes. For deployment, we strongly recommend a six-node cluster, with three masters and three replicas.

Requirements to create a Redis Cluster | Scale with Redis Cluster | Docs

 
では、実際にマスターノードが1つしかない場合、どのような挙動になるのか試してみます。

まずは compose-one-node.yml ファイルを用意します。

services:
  redis-cluster-master:
    image: redis:8.4.0-bookworm
    container_name: redis-cluster-master
    ports:
      - "17010:6379"
    command:
      - "redis-server"
      - "--save"
      - ""
      - "--appendonly"
      - "no"
      - "--protected-mode"
      - "no"
      - "--cluster-enabled"
      - "yes"
      - "--cluster-config-file"
      - "nodes.conf"
      - "--cluster-node-timeout"
      - "5000"
    restart: unless-stopped
    networks:
      - redis-network

  redis-cluster-replica:
    image: redis:8.4.0-bookworm
    container_name: redis-cluster-replica
    ports:
      - "17011:6379"
    command:
      - "redis-server"
      - "--save"
      - ""
      - "--appendonly"
      - "no"
      - "--protected-mode"
      - "no"
      - "--cluster-enabled"
      - "yes"
      - "--cluster-config-file"
      - "nodes.conf"
      - "--cluster-node-timeout"
      - "5000"
    restart: unless-stopped
    networks:
      - redis-network

  redis-cluster-init:
    image: redis:8.4.0-bookworm
    container_name: redis-cluster-init
    depends_on:
      - redis-cluster-master
      - redis-cluster-replica
    command:
      - "sh"
      - "-c"
      - |
        until redis-cli -h redis-cluster-master ping; do sleep 1; done
        until redis-cli -h redis-cluster-replica ping; do sleep 1; done
        redis-cli --cluster create \
          redis-cluster-master:6379 \
          redis-cluster-replica:6379 \
          --cluster-replicas 1 --cluster-yes
    restart: "no"
    networks:
      - redis-network

networks:
  redis-network:
    name: redis-network

 
これを docker compose -f compose-one-node.yml up -d で起動します。

Redis CLIで確認したところ、cluster_stateが fail していました。クラスターが適切に作成できなかったようです。

$ redis-cli -c -h redis-cluster-master -p 6379 cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
total_cluster_links_buffer_limit_exceeded:0
cluster_slot_migration_active_tasks:0
cluster_slot_migration_active_trim_running:0
cluster_slot_migration_active_trim_current_job_keys:0
cluster_slot_migration_active_trim_current_job_trimmed:0
cluster_slot_migration_stats_active_trim_started:0
cluster_slot_migration_stats_active_trim_completed:0
cluster_slot_migration_stats_active_trim_cancelled:0

 

マスターノード3つ(ノードごとにレプリカ1つ)でRedisクラスターを構成する

docker composeによるRedisクラスター構築

次に、最低限のマスターノードでRedisクラスターを構成してみます。

まずは compose-cluster.yml ファイルを用意します。なお、マスターとレプリカで共通する部分は x-redis-cluster-common として切り出しています。

x-redis-cluster-common: &redis_cluster_common  
  image: redis:8.4.0-bookworm  
  command: &redis_cluster_command  
    - "redis-server"  
    - "--save"  
    - ""  
    - "--appendonly"  
    - "no"  
    - "--protected-mode"  
    - "no"  
    - "--cluster-enabled"  
    - "yes"  
    - "--cluster-config-file"  
    - "nodes.conf"  
    - "--cluster-node-timeout"  
    - "5000"  
  restart: unless-stopped  
  networks:  
    - redis-network  
  
services:  
  redis-cluster-master-1:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-master-1  
    ports:  
      - "17020:6379"  
  
  redis-cluster-master-2:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-master-2  
    ports:  
      - "17021:6379"  
  
  redis-cluster-master-3:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-master-3  
    ports:  
      - "17022:6379"  
  
  redis-cluster-replica-1:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-replica-1  
    ports:  
      - "17023:6379"  
  
  redis-cluster-replica-2:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-replica-2  
    ports:  
      - "17024:6379"  
  
  redis-cluster-replica-3:  
    <<: *redis_cluster_common  
    container_name: redis-cluster-replica-3  
    ports:  
      - "17025:6379"  
  
  redis-cluster-init:  
    image: redis:8.4.0-bookworm  
    container_name: redis-cluster-init  
    depends_on:  
      - redis-cluster-master-1  
      - redis-cluster-master-2  
      - redis-cluster-master-3  
      - redis-cluster-replica-1  
      - redis-cluster-replica-2  
      - redis-cluster-replica-3  
    command:  
      - "sh"  
      - "-c"  
      - |  
        until redis-cli -h redis-cluster-master-1 ping; do sleep 1; done  
        until redis-cli -h redis-cluster-master-2 ping; do sleep 1; done  
        until redis-cli -h redis-cluster-master-3 ping; do sleep 1; done  
        until redis-cli -h redis-cluster-replica-1 ping; do sleep 1; done  
        until redis-cli -h redis-cluster-replica-2 ping; do sleep 1; done  
        until redis-cli -h redis-cluster-replica-3 ping; do sleep 1; done  
        redis-cli --cluster create \  
          redis-cluster-master-1:6379 \  
          redis-cluster-master-2:6379 \  
          redis-cluster-master-3:6379 \  
          redis-cluster-replica-1:6379 \  
          redis-cluster-replica-2:6379 \  
          redis-cluster-replica-3:6379 \  
          --cluster-replicas 1 --cluster-yes  
    restart: "no"  
    networks:  
      - redis-network  
  
networks:  
  redis-network:  
    name: redis-network

 
docker composeでRedisクラスターを起動します。

% docker compose -f compose-cluster.yml up -d
 ✔ Container redis-cluster-replica-3  Started
 ✔ Container redis-cluster-master-2   Started
 ✔ Container redis-cluster-master-1   Started
 ✔ Container redis-cluster-replica-2  Started
 ✔ Container redis-cluster-master-3   Started
 ✔ Container redis-cluster-replica-1  Started
 ✔ Container redis-cluster-init       Started

 
Redis CLIで状態を確認します。 cluster_state:ok となっており、Redisクラスターとして動作してそうです。

$ redis-cli -c -h redis-cluster-master-1 -p 6379 cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:315
cluster_stats_messages_pong_sent:317
cluster_stats_messages_sent:632
cluster_stats_messages_ping_received:312
cluster_stats_messages_pong_received:315
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:632
total_cluster_links_buffer_limit_exceeded:0
cluster_slot_migration_active_tasks:0
cluster_slot_migration_active_trim_running:0
cluster_slot_migration_active_trim_current_job_keys:0
cluster_slot_migration_active_trim_current_job_trimmed:0
cluster_slot_migration_stats_active_trim_started:0
cluster_slot_migration_stats_active_trim_completed:0
cluster_slot_migration_stats_active_trim_cancelled:0

 

redis gemによる :cache_store

RailsからRedisクラスターへ接続するには redis-clusteringが必要なため、bundle add します。

$ bundle add redis-clustering
...
Installing redis-cluster-client 0.13.7
Installing redis-clustering 5.4.1

 
Redisクラスター向けにsession_store.rbを修正します。

なお、 nodes へ指定するのはマスターノードのみで良いです。Redisクラスターへの書き込みはマスターノードのみ行うためです。

Rails.application.config.session_store :cache_store,
                                       cache: ActiveSupport::Cache::RedisCacheStore.new(
                                         redis: Redis::Cluster.new(nodes: %w[
                                           redis://redis-cluster-master-1:6379
                                           redis://redis-cluster-master-2:6379
                                           redis://redis-cluster-master-3:6379
                                         ]),
                                         namespace: "my_namespace"
                                       ),
                                       expire_after: 90.minutes,
                                       key: "_redis_cluster_session"

 
動作確認します。セッションへデータが保存されてそうです。

% curl -X POST http://localhost:3000/hellos -c cookies.txt

% curl -b cookies.txt http://localhost:3000/hellos        
{
"current_timestamp":"2026/02/01 23:59:11",
"session_timestamp":"session -> 2026/02/01 23:59:07"
}

 
RubyMineでRedisクラスターを確認すると、マスター・レプリカそれぞれに同じデータが保存されていました。

 
Redis CLIで確認します。redis-cluster-master-1redis-cluster-replica-2 にキーが保存されていました。

# マスター系
$ redis-cli -c -h redis-cluster-master-1 -p 6379 --scan
"my_namespace:_session_id:2::4ff7a1cfb59cf23187e32793f956beac87b7a57b2a6c8c8e03ab2030805182e0"

$ redis-cli -c -h redis-cluster-master-2 -p 6379 --scan
# (キーがないので空行)

$ redis-cli -c -h redis-cluster-master-3 -p 6379 --scan
# (キーがないので空行)


# レプリカ系
$ redis-cli -c -h redis-cluster-replica-1 -p 6379 --scan
# (キーがないので空行)

$ redis-cli -c -h redis-cluster-replica-2 -p 6379 --scan
"my_namespace:_session_id:2::4ff7a1cfb59cf23187e32793f956beac87b7a57b2a6c8c8e03ab2030805182e0"

$ redis-cli -c -h redis-cluster-replica-3 -p 6379 --scan
# (キーがないので空行)

 
redis-cluster-master-1redis-cluster-replica-2 の中身を確認すると、同じものが保存されていました。良さそうです。

# マスター
$ redis-cli -c -h redis-cluster-master-1 -p 6379 get "my_namespace:_session_id:2::4ff7a1cfb59cf23187e32793f956beac87b7a57b2a6c8c8e03ab2030805182e0"
"\x00\x11\x01o\xbb\xfay\xff_\xdaA\xff\xff\xff\xff\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 23:59:07\x06;\x00T"


# レプリカ
$ redis-cli -c -h redis-cluster-replica-2 -p 6379 get "my_namespace:_session_id:2::4ff7a1cfb59cf23187e32793f956beac87b7a57b2a6c8c8e03ab2030805182e0"
"\x00\x11\x01o\xbb\xfay\xff_\xdaA\xff\xff\xff\xff\x04\b{\x06I\"\x16session_timestamp\x06:\x06EFI\"#session -> 2026/02/01 23:59:07\x06;\x00T"

 

ソースコード

GitHubに上げました。
https://github.com/thinkAmi-sandbox/rails_session_with_redis_replication-example

 
スタンドアロンRedisで redis gemだけを使っているプルリクはこちら。
https://github.com/thinkAmi-sandbox/rails_session_with_redis_replication-example/pull/1

なお、スタンドアロンRedisで redis gem + redis-actionpack gemの場合は、こちらのコミットです。
https://github.com/thinkAmi-sandbox/rails_session_with_redis_replication-example/commit/7557bc6c51915c0385dfb7fd342d4bd54f140bce

 
Redisクラスターのプルリクはこちら。
https://github.com/thinkAmi-sandbox/rails_session_with_redis_replication-example/pull/2




以上の内容はhttps://thinkami.hatenablog.com/entry/2026/02/02/202424より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14