Redis 分散キャッシュ

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

Redis 基礎: https://blog.yexca.net/ja/archives/157/
Redis 分散キャッシュ: 本文

はじめに

結局この2つの記事、同時に書いたのに1年も経ってから投稿してるんだよね

実は当時書きたいものが3つあったんだけど、思い出すたびに何を書こうとしてたか忘れちゃって、気づいたら1年近く経ってたっていう。。。

問題点

スタンドアロン(単一インスタンス)の Redis には以下の課題がある。

  • データの紛失:Redis データの永続化を実現する必要がある
  • 並行処理能力の問題:主従(マスター・スレーブ)クラスタを構築し、読み書き分離を実現する必要がある
  • ストレージ容量の問題:シャーディング(分片)クラスタを構築し、スロット・メカニズムを利用して動的スケーリングを実現する必要がある
  • 障害復旧の問題:Redis センチネル(Sentinel)を利用して、ヘルスチェックと自動復旧を実現する必要がある

Redis の永続化

Redis の永続化には RDB と AOF の2つの方法がある。

RDB 永続化

RDB の正式名称は Redis Database Backup file(Redis データバックアップファイル)。Redis データスナップショットとも呼ばれる。簡単に言うと、メモリ内のすべてのデータをディスクに記録すること。Redis インスタンスが故障して再起動したとき、ディスクからスナップショットファイルを読み込んでデータを復元する。スナップショットファイルは RDB ファイルと呼ばれ、デフォルトでは実行ディレクトリに保存される。

RDB は以下の4つのケースで実行される:

  • save コマンド:即座に実行される。メインプロセスが RDB を実行するため、他のすべてのコマンドがブロックされる。データ移行時にのみ使われる可能性がある。
  • bgsave コマンド:非同期で実行される。独立したプロセスを開始して RDB を完了させるため、メインプロセスは影響を受けずにユーザーのリクエストを処理し続けられる。
  • Redis 停止時:停止時に save コマンドが1回実行される。
  • RDB 発動条件に達したとき:設定ファイルで以下のように設定する。
1
2
3
4
# 900秒以内に少なくとも1つのキーが変更されたらbgsaveを実行。save "" ならRDB無効
save 900 1  
save 300 10  
save 60 10000 

その他の設定

1
2
3
4
5
6
7
8
# 圧縮するかどうか。CPUを消費するのでオフを推奨。ディスクは安いしね
rdbcompression yes

# RDBファイル名
dbfilename dump.rdb  

# ファイル保存ディレクトリ
dir ./ 

RDB の原理

bgsave が始まると、メインプロセスが fork して子プロセスを作成する。子プロセスはメインプロセスのメモリデータを共有する。fork 完了後、メモリデータを読み取って RDB ファイルに書き込む。

fork は copy-on-write 技術を採用している:

  • メインプロセスが読み取り操作を行うときは、共有メモリにアクセスする。
  • メインプロセスが書き込み操作を行うときは、データのコピーを作成してから書き込みを行う。

image

RDB の欠点:

  • 実行間隔が長く、2回の RDB の間に書き込まれたデータが失われるリスクがある。
  • 子プロセスの fork、圧縮、RDB ファイルの書き出しに時間がかかる。

AOF 永続化

AOF の正式名称は Append Only File(追加専用ファイル)。Redis が処理するすべての書き込みコマンドを記録するファイルで、コマンドログファイルのようなもの。

AOF はデフォルトでオフになっているので、設定ファイルを変更して有効にする。

1
2
3
4
# AOF機能を有効にするか。デフォルトはno
appendonly yes
# AOFファイル名
appendfilename "appendonly.aof"

記録の頻度も redis.conf で設定できる。

1
2
3
4
5
6
# 書き込みコマンドが実行されるたびに、すぐにAOFファイルに記録する
appendfsync always 
# 書き込みコマンド実行後、まずAOFバッファに入れ、1秒ごとにバッファの内容をAOFファイルに書き込む。デフォルト設定
appendfsync everysec 
# 書き込みコマンド実行後、まずAOFバッファに入れ、OSがディスクに書き戻すタイミングを決める
appendfsync no

設定項目の比較:

設定項目ディスク書き込みのタイミングメリットデメリット
always同期書き込み信頼性が高く、データがほぼ失われないパフォーマンスへの影響が大きい
everysec毎秒書き込みパフォーマンスはそこそこ最大1秒分のデータが失われる可能性がある
noOSが制御パフォーマンスが最高信頼性が低く、大量のデータが失われる可能性がある

ファイルの書き換え(Rewrite)

コマンドを記録するため、AOF ファイルは RDB よりかなり大きくなる。また、同じキーに対する複数の書き込みもすべて記録されるが、実際には最後の書き込みだけが意味を持つ。bgrewriteaof コマンドを実行することで、AOF ファイルを書き換え、最小限のコマンドで同じ状態を再現できるようになる。

例えば、元のコマンドが:

1
2
3
set num 123
set name jack
set num 666

書き換え後は:

1
mset name jack num 666

Redis は閾値に達したときにも自動的に AOF を書き換える。設定ファイルで指定する:

1
2
3
4
# AOFファイルが前回のファイルより何パーセント増加したら書き換えを実行するか
auto-aof-rewrite-percentage 100
# AOFファイルが最低でもどれくらいのサイズになったら書き換えを実行するか
auto-aof-rewrite-min-size 64mb 

RDB と AOF の比較

RDB と AOF にはそれぞれメリット・デメリットがある。データの安全性を重視する場合、実際の開発では両方を組み合わせて使うことが多い。

RDBAOF
永続化方式定期的にメモリ全体のスナップショットを作成実行されたすべてのコマンドを記録
データの完全性不完全。バックアップの合間にデータが失われる比較的完全。書き込み戦略に依存する
ファイルサイズ圧縮されるため、ファイルサイズは小さいコマンドを記録するため、サイズは非常に大きくなる
復旧速度非常に速い遅い
データ復旧の優先順位低い。データの完全性が AOF に劣るため高い。データの完全性がより高いため
システムリソース占有高い。大量の CPU とメモリを消費低い。主にディスク I/O リソース
ただし AOF 書き換え時は大量の CPU とメモリを消費
使用シーン数分間のデータ紛失が許容でき、高速な起動を求める場合データの安全性を高く求められる一般的なケース

Redis 主従アーキテクチャ

単一ノードの Redis の並行処理能力には限界がある。さらに向上させるには、主従(マスター・スレーブ)クラスタを構築して読み書き分離を実現する必要がある。

image

クラスタ構築

CentOS7 ベースでの手順。

上の図を参考に、合計3つのノードを同一マシン内に配置する。ポートは 7001(master)、7002、7003 とする。

まずディレクトリを作成。

1
2
cd /tmp
mkdir 7001 7002 7003

設定を変更している場合は、デフォルトの RDB モードに戻しておく。

1
2
3
4
5
6
7
8
# RDBを有効化
# save ""
save 3600 1
save 300 100
save 60 10000

# AOFを無効化
appendonly no

設定ファイルを各インスタンスのディレクトリにコピー。

1
2
3
4
5
6
7
# 方法1
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003

# 方法2
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf

各インスタンスのポートと作業ディレクトリ(ポートの修正、rdb ファイルの保存場所の修正)を変更。

1
2
3
sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf

IP を修正。すべてのディレクトリを修正すること (ip_address を実際のIPに置換)。

1
2
3
4
5
6
7
# 1つずつ実行
sed -i '1a replica-announce-ip ip_address' 7001/redis.conf
sed -i '1a replica-announce-ip ip_address' 7002/redis.conf
sed -i '1a replica-announce-ip ip_address' 7003/redis.conf

# または一括で修正
printf '%s\n' 7001 7002 7003 | xargs -I{} -t sed -i '1a replica-announce-ip ip_address' {}/redis.conf

起動。

1
2
3
4
5
6
# 1つ目
redis-server 7001/redis.conf
# 2つ目
redis-server 7002/redis.conf
# 3つ目
redis-server 7003/redis.conf

停止。

1
printf '%s\n' 7001 7002 7003 | xargs -I{} -t redis-cli -p {} shutdown

Visits Since 2025-02-28

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