TL;DR: 30秒でできる修正
Redisインスタンスがメモリ上限に達したため、自己保護のためにすべての書き込み操作を拒否しています。上限を引き上げるか、メモリがいっぱいになった時のRedisの挙動を変更することで、すぐにサービスを復旧できます。redis-cliで以下のコマンドを実行してください:
# 1. 実際に使用されているメモリ量を確認
INFO memory
# 2. 上限を4GBに増やす(例:システムの使用可能なRAMの80%を使用)
CONFIG SET maxmemory 4gb
# 3. 古いデータを自動削除して空き容量を確保する設定を有効化
CONFIG SET maxmemory-policy allkeys-lru
この修正は再起動なしで即座に反映されます。再起動後もエラーが再発しないよう、redis.confファイルも同じ値で更新することを忘れないでください。
なぜこのエラーが発生するのか?
Redisはインメモリデータベースです。ディスクに溢れたデータを逃がすことができる PostgreSQL や MySQL とは異なり、Redisは設定で定義された maxmemory 制限を厳格に守ります。このエラーが表示されるのは、その制限に達したことを意味します。
デフォルトでは、多くの Redis インストール環境で noeviction ポリシーが使用されています。これは、RAMがいっぱいになると、古いキーを削除するのではなく、新しいデータの受け入れを拒否することを意味します。読み取りコマンド(GET や EXISTS など)は引き続き正常に動作しますが、書き込みコマンド(SET, HSET, LPUSH)は OOM エラーで失敗します。
mem_fragmentation_ratio(メモリ断片化率)にも注意してください。この数値が 1.5 を超えている場合、Redisは実際にはデータに使用していないメモリを保持している可能性があり、予想よりも早くシステムが「満杯」であると感じる原因になります。
実証済みの修正方法
1. メモリ上限を拡張する
サーバーに空きRAMがある場合、最も簡単な方法は Redis により多くの容量を割り当てることです。16GBのVPSで実行しており、Redisの制限が2GBに設定されているなら、十分な余裕があるはずです。
redis-cli
> CONFIG GET maxmemory
> CONFIG SET maxmemory 8gb
注意点: 本番サーバーで maxmemory 0(無制限)に設定するのは避けてください。Redisが物理RAMをすべて消費してしまうと、Linuxの OOM Killer がパニックを起こして Redis プロセス自体を強制終了させ、完全にダウンタイムが発生する可能性が高くなります。
2. データの自動クリーンアップ(退避)を設定する
ほとんどのキャッシュ利用シーンでは、すべてのキーを永久に保持する必要はありません。メモリ上限に達したときに古いデータや使用頻度の低いデータを削除するように設定することで、Redisをスマートなキャッシュとして動作させることができます。
redis.conf を更新するか、CONFIG SET を使用してポリシーを選択します:
allkeys-lru: 最近最も使われていないキーを削除します。ほとんどのウェブアプリケーションにとっての推奨設定です。volatile-ttl: 有効期限(TTL)が設定されているキーのみを削除し、期限が切れそうなものを優先します。allkeys-lfu: 使用頻度が最も低いキーを削除します(特定のデータが他よりも圧倒的に多くアクセスされる場合に有効です)。
3. バックグラウンド保存の失敗を修正する(Overcommit Memory)
十分なRAMがあるにもかかわらず、BGSAVE(ディスクスナップショット)中に Redis が OOM エラーを発生させることがあります。これは、Redisが子プロセスをフォークしようとする際、Linuxカーネルがメモリ割り当てに対して保守的すぎるために起こります。
これを修正するには、root ユーザーとして以下を実行し、カーネルがメモリを「オーバーコミット」できるようにします:
sysctl vm.overcommit_memory=1
再起動後も設定を維持するには、/etc/sysctl.conf に vm.overcommit_memory = 1 を追加してください。これにより、メモリ使用率が高いときでも Redis がディスクにデータを保存できるようになります。
4. 「大きなキー」を特定する
たった一つの巨大なハッシュやリストが原因であることもよくあります。500MBのJSONバイナリを含む単一のキーは、メモリ管理における時限爆弾です。組み込みのスキャナーを使ってそれらを見つけ出しましょう:
# サーバーをブロックせずにキースペース全体をスキャン
redis-cli --bigkeys
もし、24時間しか必要ないのに100万個の要素を持つリストを見つけた場合は、TTLを設定してください: EXPIRE my_massive_list 86400
修正の確認
エラーが止まったからといって安心しないでください。以下の手順でインスタンスの状態を確認しましょう:
- 差分を確認:
INFO memoryを実行し、used_memory_humanとmaxmemory_humanを比較します。十分なバッファがあることが望ましいです。 - 書き込みを確認:
SET health_check 1を実行します。OKが返ってくれば、アプリケーションは正常に復旧しています。 - 削除状況を監視: 削除ポリシーを有効にした場合は、
redis-cli info stats | grep evicted_keysを実行します。この数値が増えているなら、Redisは新しいデータのために正常に空き容量を作っています。

