- Published on
Redisクラスターアーキテクチャと高可用性運用ガイド: Sentinel·Clusterモード·メモリ最適化·障害復旧
- Authors
- Name
- はじめに
- Redisデプロイモード比較: Standalone vs Sentinel vs Cluster
- Sentinelアーキテクチャとクォーラムメカニズム
- Clusterハッシュスロットとリシャーディング
- レプリケーション(Replication)とPSYNC
- メモリ管理と退去ポリシー
- 永続化: RDBとAOF
- スローログ分析
- メモリフラグメンテーション対応
- 障害シナリオと復旧手順
- 運用監視と主要メトリクス
- 運用時の注意事項
- まとめ
- 参考資料

はじめに
Redisはインメモリデータストアとして、キャッシュ、セッションストア、メッセージブローカーなど様々な用途で使用されている。単一インスタンスでの運用開始は容易だが、本番環境で高可用性(HA)と水平スケーリングを実現するには、SentinelまたはClusterモードの十分な理解が不可欠である。メモリベースのシステムであるため、メモリ管理、退去ポリシー、永続化戦略、そして障害時の復旧手順まで、運用全般を網羅する知識が必要となる。
本記事では、Redisの3つのデプロイモード(Standalone、Sentinel、Cluster)の比較から始め、Sentinelのクォーラムメカニズム、Clusterのハッシュスロット分散、レプリケーションプロトコル(PSYNC)、メモリ最適化戦略、永続化(RDB/AOF)、スローログ分析、そして代表的な障害シナリオ(Split-brain、OOM)と復旧手順を実践例とともに解説する。
Redisデプロイモード比較: Standalone vs Sentinel vs Cluster
デプロイモード比較表
| 項目 | Standalone | Sentinel | Cluster |
|---|---|---|---|
| ノード数 | 1(+ オプションのレプリカ) | 最小3 Sentinel + 1 Master + N Replica | 最小6(3 Master + 3 Replica) |
| データ分散 | 不可 | 不可(単一マスター) | ハッシュスロットベースの自動分散 |
| 自動フェイルオーバー | 不可 | 可能(クォーラムベース) | 可能(過半数投票) |
| 書き込みスケーリング | 不可 | 不可 | 可能(マルチマスター) |
| 読み取りスケーリング | レプリカREADONLY | レプリカREADONLY | レプリカREADONLY |
| クライアント複雑度 | 低い | 中程度(Sentinel対応) | 高い(MOVED/ASKリダイレクション) |
| 適用シナリオ | 開発/小規模 | HA必要な単一データセット | 大規模データ + HA |
選択基準
# 意思決定フロー
# 1. データが単一ノードのメモリに収まるか?
# - YES → Sentinel(HA必要時)またはStandalone
# - NO → Cluster必須
#
# 2. 書き込み性能のスケーリングが必要か?
# - YES → Cluster(マルチマスター)
# - NO → Sentinelで十分
#
# 3. 運用の複雑さを許容できるか?
# - 小規模チーム → Sentinelを優先検討
# - 専任インフラチーム → Cluster導入可能
Sentinelアーキテクチャとクォーラムメカニズム
Sentinelの役割
Redis Sentinelは、Redisインスタンスを監視し、マスター障害時に自動的にレプリカを昇格させる分散監視システムである。Sentinelプロセス自体も分散されており、単一障害点(SPOF)を防止する。
# Sentinel設定ファイル (sentinel.conf)
port 26379
sentinel monitor mymaster 192.168.1.10 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
# sentinel monitor <master-name> <ip> <port> <quorum>
# quorum = 障害判定に必要な最小Sentinel合意数
クォーラム(Quorum)と過半数(Majority)
クォーラムと過半数は異なる概念である。クォーラムは障害を検知するために必要な最小合意数であり、過半数は実際のフェイルオーバーを実行するための要件である。
# 3台Sentinel構成の例
# quorum = 2(2台が同意すればODOWN判定)
# majority = 2(3台中2台 = 過半数)
# 5台Sentinel構成の例
# quorum = 3(3台が同意すればODOWN判定)
# majority = 3(5台中3台 = 過半数)
# Sentinelステータス確認
redis-cli -p 26379 SENTINEL masters
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
redis-cli -p 26379 SENTINEL replicas mymaster
フェイルオーバーの順序
# 1. SDOWN (Subjective Down) - 個別Sentinelがマスター無応答を検知
# down-after-milliseconds経過後に発生
# 2. ODOWN (Objective Down) - quorum数以上のSentinelがSDOWNに同意
# この時点でフェイルオーバープロセス開始
# 3. Leader Election - Sentinel中の1つがリーダーに選出
# majority以上の投票が必要(Raft類似アルゴリズム)
# 4. Replica選択 - リーダーSentinelが最適なレプリカを選択
# 優先順位: replica-priority → レプリケーションオフセット → runid
# 5. Failover実行
# 選択されたレプリカにSLAVEOF NO ONEコマンド
# 他のレプリカを新マスターに再接続
# フェイルオーバー進行状況監視
redis-cli -p 26379 SENTINEL failover-status mymaster
Clusterハッシュスロットとリシャーディング
ハッシュスロット分配
Redis Clusterはキースペース全体を16384個のハッシュスロットに分割して管理する。各マスターノードはスロットの一部を担当し、キーのCRC16ハッシュ値を16384で割った余りでスロットが決定される。
# クラスター作成(最小6ノード: 3 Master + 3 Replica)
redis-cli --cluster create \
192.168.1.10:7000 192.168.1.11:7001 192.168.1.12:7002 \
192.168.1.10:7003 192.168.1.11:7004 192.168.1.12:7005 \
--cluster-replicas 1
# スロット分配確認
redis-cli -c -h 192.168.1.10 -p 7000 CLUSTER SLOTS
# 個別キーのスロット確認
redis-cli -c CLUSTER KEYSLOT mykey
# (integer) 14687
# ハッシュタグを使用して同一スロットに配置
# 波括弧内の文字列のみでスロットが決定される
redis-cli -c SET "user:1001:profile" "data1"
redis-cli -c SET "user:1001:session" "data2"
# 上記2つのキーは異なるスロットに配置される可能性がある
# ハッシュタグ使用時は同一スロットに配置可能
# CLUSTER KEYSLOTコマンドで確認
redis-cli CLUSTER KEYSLOT "user:1001"
リシャーディング(Resharding)
# オンラインリシャーディング - サービス中断なしでスロット移動
redis-cli --cluster reshard 192.168.1.10:7000 \
--cluster-from <source-node-id> \
--cluster-to <target-node-id> \
--cluster-slots 1000 \
--cluster-yes
# リシャーディング進行状況確認
redis-cli -c -h 192.168.1.10 -p 7000 CLUSTER INFO
# クラスターヘルスチェック
redis-cli --cluster check 192.168.1.10:7000
# スロットリバランシング(自動均等分配)
redis-cli --cluster rebalance 192.168.1.10:7000 \
--cluster-threshold 2
MOVEDとASKリダイレクション
# Python redis-py-cluster例
import redis
# ClusterModeクライアントはMOVED/ASKを自動処理
rc = redis.RedisCluster(
host='192.168.1.10',
port=7000,
decode_responses=True,
skip_full_coverage_check=True
)
# 通常の使用 - リダイレクション自動処理
rc.set('session:abc123', 'user_data')
value = rc.get('session:abc123')
# パイプライン使用時は同一スロットのキーのみバッチ可能
# ハッシュタグを活用すれば同一スロットに配置可能
pipe = rc.pipeline()
pipe.set('order:1001:status', 'pending')
pipe.set('order:1001:total', '50000')
pipe.execute()
# MOVED: キーが別ノードにある場合(永久移動)
# ASK: リシャーディング中に一時的に別ノードにある場合
レプリケーション(Replication)とPSYNC
レプリケーション設定とPSYNCプロトコル
# レプリカ設定
# redis.conf(レプリカノード)
replicaof 192.168.1.10 6379
masterauth your_password
# PSYNCプロトコル動作:
# 1. Full Sync(全体同期)
# - レプリカが初めて接続された場合またはbacklogが不足している場合
# - マスターがRDBスナップショットを生成して送信
# - 転送中の変更分は別バッファに保存後追加送信
# 2. Partial Sync(部分同期) - PSYNC2
# - レプリカが短い断絶後に再接続した場合
# - replication backlogに保存された差分のみ送信
# - はるかに高速で効率的
# backlogサイズ設定(デフォルト1MB、本番環境では増加推奨)
repl-backlog-size 256mb
repl-backlog-ttl 3600
# レプリケーション状態確認
redis-cli INFO replication
レプリケーション監視
# マスターでレプリケーション状態確認
redis-cli INFO replication
# role:master
# connected_slaves:2
# slave0:ip=192.168.1.11,port=6379,state=online,offset=1234567,lag=0
# slave1:ip=192.168.1.12,port=6379,state=online,offset=1234567,lag=1
# master_replid:abc123def456...
# master_repl_offset:1234567
# repl_backlog_active:1
# repl_backlog_size:268435456
# レプリケーションラグ監視 - lagが継続的に高い場合は対策が必要
# lag > 10 : ネットワークまたはレプリカ性能確認
# lag > 60 : 緊急対策必要(フルシンク発生の可能性)
# レプリカで読み取り専用確認
redis-cli -h 192.168.1.11 CONFIG GET replica-read-only
メモリ管理と退去ポリシー
maxmemory設定
# maxmemory設定 (redis.conf)
maxmemory 8gb
# ランタイム変更
redis-cli CONFIG SET maxmemory 8589934592
# 現在のメモリ使用量確認
redis-cli INFO memory
# used_memory:4294967296
# used_memory_human:4.00G
# used_memory_rss:4831838208
# used_memory_rss_human:4.50G
# mem_fragmentation_ratio:1.12
# maxmemory:8589934592
# maxmemory_human:8.00G
# maxmemory_policy:allkeys-lru
退去ポリシー比較
| ポリシー | 対象キー | アルゴリズム | 適用シナリオ |
|---|---|---|---|
| noeviction | なし(書き込み拒否) | - | データ損失不可 |
| allkeys-lru | 全キー | LRU | 一般キャッシュ(最も一般的) |
| allkeys-lfu | 全キー | LFU | 人気度ベースのキャッシュ |
| allkeys-random | 全キー | ランダム | 均等アクセスパターン |
| volatile-lru | TTL設定キーのみ | LRU | キャッシュ + 永続データ混合 |
| volatile-lfu | TTL設定キーのみ | LFU | TTLキー中の頻度ベース削除 |
| volatile-ttl | TTL設定キーのみ | 残りTTL短い順 | 期限切れ間近のキー優先削除 |
| volatile-random | TTL設定キーのみ | ランダム | TTLキーランダム削除 |
# 退去ポリシー設定
redis-cli CONFIG SET maxmemory-policy allkeys-lfu
# LFUカウンター設定(Redis 4.0+)
# lfu-log-factor: カウンター増加速度(デフォルト10、高いほど遅く増加)
# lfu-decay-time: カウンター減少周期(分、デフォルト1)
redis-cli CONFIG SET lfu-log-factor 10
redis-cli CONFIG SET lfu-decay-time 1
# 特定キーのLFU頻度確認
redis-cli OBJECT FREQ mykey
# 退去統計確認
redis-cli INFO stats | grep evicted
# evicted_keys:12345
メモリ最適化技法
# 1. データ構造最適化 - ziplist/listpack活用
# 小規模ハッシュにziplist使用(メモリ最大10倍節約)
redis-cli CONFIG SET hash-max-ziplist-entries 128
redis-cli CONFIG SET hash-max-ziplist-value 64
# 小規模リストにlistpack使用(Redis 7.0+)
redis-cli CONFIG SET list-max-listpack-size -2
# 小規模Sorted Setにziplist使用
redis-cli CONFIG SET zset-max-ziplist-entries 128
redis-cli CONFIG SET zset-max-ziplist-value 64
# 2. キー命名最適化 - 短いキー名使用
# Bad: user:session:authentication:token:1001
# Good: u:s:t:1001
# 3. メモリ使用量分析
redis-cli MEMORY USAGE mykey
redis-cli MEMORY DOCTOR
# 4. 大きなキー(Big Key)検出
redis-cli --bigkeys --memkeys
# 5. Lazy Free設定(バックグラウンド削除でブロッキング防止)
redis-cli CONFIG SET lazyfree-lazy-eviction yes
redis-cli CONFIG SET lazyfree-lazy-expire yes
redis-cli CONFIG SET lazyfree-lazy-server-del yes
永続化: RDBとAOF
RDB vs AOF比較
| 項目 | RDB(Snapshot) | AOF(Append Only File) |
|---|---|---|
| 方式 | 特定時点の全体スナップショット | 全書き込みコマンドの順次記録 |
| データ損失 | 最後のスナップショット以降損失可能 | fsync設定により最小化 |
| ファイルサイズ | 小(バイナリ圧縮) | 大(コマンドテキスト、rewriteで縮小) |
| 復旧速度 | 高速 | 低速(コマンド再実行) |
| 性能影響 | fork()時の瞬間的遅延 | fsync頻度に応じた継続的影響 |
| 推奨用途 | バックアップ | データ安全性 |
# RDB設定 (redis.conf)
save 900 1 # 900秒(15分)内1個以上変更時スナップショット
save 300 10 # 300秒(5分)内10個以上変更時スナップショット
save 60 10000 # 60秒(1分)内10000個以上変更時スナップショット
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /var/lib/redis
# AOF設定
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec # 推奨: 1秒ごとにfsync(性能と安全性のバランス)
# appendfsync always # 毎コマンドfsync(最も安全、性能低下)
# appendfsync no # OSに委任(最速だがデータ損失リスク)
# AOF Rewrite設定
auto-aof-rewrite-percentage 100 # AOFが前回rewrite比100%大きくなったら
auto-aof-rewrite-min-size 64mb # 最小64MB以上の場合にrewrite実行
# 本番推奨: RDB + AOF同時使用
# RDB: 高速復旧 + バックアップ
# AOF: データ損失最小化
AOF再書き込みと管理
# 手動AOF Rewrite実行
redis-cli BGREWRITEAOF
# AOFステータス確認
redis-cli INFO persistence
# aof_enabled:1
# aof_rewrite_in_progress:0
# aof_last_rewrite_time_sec:2
# aof_current_size:134217728
# aof_base_size:67108864
# AOF整合性検査
redis-check-aof --fix appendonly.aof
# RDB整合性検査
redis-check-rdb dump.rdb
# 手動バックアップ(BGSAVE使用)
redis-cli BGSAVE
# バックグラウンドでRDBスナップショット生成
# dump.rdbファイルを安全なストレージにコピー
スローログ分析
# スローログ設定
redis-cli CONFIG SET slowlog-log-slower-than 10000 # 10ms以上を記録
redis-cli CONFIG SET slowlog-max-len 128 # 最大128項目保持
# スローログ照会
redis-cli SLOWLOG GET 10
# 1) 1) (integer) 14 # ログID
# 2) (integer) 1710230400 # タイムスタンプ
# 3) (integer) 15230 # 実行時間(マイクロ秒)
# 4) 1) "KEYS" # コマンド
# 2) "*session*"
# 5) "192.168.1.50:54321" # クライアントアドレス
# 6) ""
# スローログ統計
redis-cli SLOWLOG LEN
redis-cli SLOWLOG RESET
# 本番環境で必ず避けるべきO(N)コマンド:
# KEYS * → SCANで代替
# SMEMBERS → SSCANで代替
# HGETALL → HSCANで代替
# LRANGE 0 -1 → ページネーション適用
SCANベースの安全なキー探索
# KEYSの代わりにSCAN使用(ノンブロッキング)
redis-cli SCAN 0 MATCH "session:*" COUNT 100
# 1) "17920" # 次のカーソル
# 2) 1) "session:abc123"
# 2) "session:def456"
# ...
# カーソルが0になるまで繰り返しスキャン
redis-cli SCAN 17920 MATCH "session:*" COUNT 100
メモリフラグメンテーション対応
# フラグメンテーション比率確認
redis-cli INFO memory | grep frag
# mem_fragmentation_ratio:1.45
# mem_fragmentation_bytes:536870912
# mem_fragmentation_ratioの解釈:
# 1.0 ~ 1.5 : 正常範囲
# 1.5以上 : 深刻なフラグメンテーション、対策が必要
# 1.0未満 : スワップ使用中(非常に危険)
# Active Defragmentation有効化(Redis 4.0+)
redis-cli CONFIG SET activedefrag yes
redis-cli CONFIG SET active-defrag-enabled yes
# フラグメンテーション閾値設定
redis-cli CONFIG SET active-defrag-ignore-bytes 100mb
redis-cli CONFIG SET active-defrag-threshold-lower 10 # 10%以上で開始
redis-cli CONFIG SET active-defrag-threshold-upper 100 # 100%以上で最大努力
redis-cli CONFIG SET active-defrag-cycle-min 1 # CPU最小1%使用
redis-cli CONFIG SET active-defrag-cycle-max 25 # CPU最大25%使用
# jemalloc統計確認
redis-cli MEMORY MALLOC-STATS
障害シナリオと復旧手順
シナリオ1: Split-brain(スプリットブレイン)
ネットワークパーティションが発生すると、Sentinelクラスターが分裂し、2つのマスターが同時に存在する可能性がある。これはデータ不整合を引き起こす最も危険な障害である。
# Split-brain予防設定
# マスターが最小N個のレプリカと接続されていない場合書き込み拒否
redis-cli CONFIG SET min-replicas-to-write 1
redis-cli CONFIG SET min-replicas-max-lag 10
# 発生時の復旧手順:
# 1. 全Redisインスタンスの状態確認
redis-cli -h 192.168.1.10 -p 6379 INFO replication
redis-cli -h 192.168.1.11 -p 6379 INFO replication
# 2. どのマスターが最新データを持っているか確認
redis-cli -h 192.168.1.10 -p 6379 INFO replication | grep master_repl_offset
redis-cli -h 192.168.1.11 -p 6379 INFO replication | grep master_repl_offset
# 3. 古いマスターをレプリカに降格
redis-cli -h 192.168.1.11 -p 6379 REPLICAOF 192.168.1.10 6379
# 4. Sentinel状態リセット
redis-cli -p 26379 SENTINEL RESET mymaster
# 5. データ整合性検証
redis-cli -h 192.168.1.10 DBSIZE
redis-cli -h 192.168.1.11 DBSIZE
シナリオ2: OOM(Out of Memory)
# OOM予防監視
redis-cli INFO memory
# used_memory_peak:8589934592
# used_memory_peak_human:8.00G
# OOM Killerによる終了確認
# システムログ確認
# dmesgまたは/var/log/syslogでOOM関連ログを確認
# 緊急復旧手順:
# 1. maxmemory確認および調整
redis-cli CONFIG SET maxmemory 12gb
# 2. 退去ポリシーがnoevictionの場合変更
redis-cli CONFIG GET maxmemory-policy
redis-cli CONFIG SET maxmemory-policy allkeys-lru
# 3. 大きなキーの特定とクリーンアップ
redis-cli --bigkeys
redis-cli --memkeys --memkeys-samples 100
# 4. 不要なキーに有効期限設定
redis-cli SCAN 0 MATCH "temp:*" COUNT 1000
# 必要なキーにTTL設定
redis-cli EXPIRE "temp:old-data" 3600
# 5. 今後の予防のためアラート設定(maxmemoryの80%で警告)
シナリオ3: Clusterノード障害
# クラスター状態確認
redis-cli -c CLUSTER INFO
# cluster_state:ok
# cluster_slots_assigned:16384
# cluster_slots_ok:16384
# cluster_slots_pfail:0
# cluster_slots_fail:0
# 障害ノード確認
redis-cli -c CLUSTER NODES
# 障害ノードに"fail"フラグが表示される
# ノード交換手順:
# 1. 新しいRedisインスタンス起動
redis-server /etc/redis/7006.conf
# 2. クラスターに新ノード追加
redis-cli --cluster add-node 192.168.1.13:7006 192.168.1.10:7000
# 3. 新ノードを特定マスターのレプリカに指定
redis-cli --cluster add-node 192.168.1.13:7006 192.168.1.10:7000 \
--cluster-slave --cluster-master-id <master-node-id>
# 4. 障害ノード削除
redis-cli --cluster del-node 192.168.1.10:7000 <failed-node-id>
# 5. スロット再割当(マスター障害時)
redis-cli --cluster fix 192.168.1.10:7000
運用監視と主要メトリクス
# 総合状態確認スクリプト
redis-cli INFO ALL | grep -E "used_memory_human|mem_fragmentation_ratio|connected_clients|blocked_clients|instantaneous_ops_per_sec|hit_rate|evicted_keys|keyspace_misses"
# 主要監視メトリクス:
# 1. メモリ: used_memory / maxmemory比率
# 2. フラグメンテーション: mem_fragmentation_ratio
# 3. キャッシュヒット率: keyspace_hits / (keyspace_hits + keyspace_misses)
# 4. 接続数: connected_clients
# 5. スループット: instantaneous_ops_per_sec
# 6. 退去数: evicted_keys(急増時に警告)
# 7. レプリケーションラグ: master_repl_offset vs slave_repl_offset
# レイテンシ監視
redis-cli --latency
redis-cli --latency-history
# レイテンシイベント監視(Redis 2.8.13+)
redis-cli CONFIG SET latency-monitor-threshold 100
redis-cli LATENCY LATEST
redis-cli LATENCY HISTORY event-name
運用時の注意事項
メモリオーバーコミット: Linuxで
vm.overcommit_memory=1設定が必要である。fork()ベースのRDB/AOF rewrite時にメモリ不足で失敗する可能性がある。Transparent Huge Pages(THP)無効化: THPはRedisのfork性能に悪影響を及ぼすため、必ず無効化する。
maxmemoryマージン: 物理メモリの70-80%に設定し、レプリケーションバッファ、AOF rewrite、OSキャッシュなどに余裕を持たせる。
ClusterモードでのMULTI/EXEC: トランザクション内の全キーが同じスロットに存在する必要がある。ハッシュタグを活用すること。
Sentinel配置場所: SentinelインスタンスをRedisノードとは異なる物理サーバーまたはアベイラビリティゾーンに配置し、同時障害を防止する。
KEYSコマンド禁止: 本番環境でKEYSコマンドはO(N)ブロッキングを引き起こす。SCANで代替し、rename-commandで無効化すること。
# 本番環境カーネルチューニング
# /etc/sysctl.conf
# vm.overcommit_memory = 1
# net.core.somaxconn = 65535
# net.ipv4.tcp_max_syn_backlog = 65535
# THP無効化
# echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 危険コマンド無効化 (redis.conf)
# rename-command KEYS ""
# rename-command FLUSHDB ""
# rename-command FLUSHALL ""
# rename-command DEBUG ""
まとめ
Redisの高可用性運用は、単にSentinelやClusterを設定するだけにとどまらない。メモリ管理、退去ポリシー、永続化戦略、レプリケーション監視、そして障害シナリオへの事前準備が全て揃って初めて、安定した本番運用が可能となる。
核心は3つである。第一に、ワークロードに合ったデプロイモードを選択すること。第二に、メモリ上限と退去ポリシーを必ず設定すること。第三に、障害シナリオごとの復旧手順を文書化し、定期的に訓練すること。この3つが揃えば、Redisは超高速インメモリストアとしての強みを安定的に発揮できる。