Redis「ERR Background save already in progress」エラーをBGSAVE実行時に修正する方法

intermediate🔴 Redis2026-05-06| Linux(Ubuntu、CentOS、Debian)およびmacOS上のRedis 5.x / 6.x / 7.x

Error Message

(error) ERR Background save already in progress
#redis#bgsave#rdb#永続化#スナップショット

エラーの内容

手動でスナップショットを実行すると、Redisから以下のエラーが返ってきます:

127.0.0.1:6379> BGSAVE
(error) ERR Background save already in progress

BGSAVEのフォークがすでに実行中です — Redisは2つのフォークを同時に実行させません。ほとんどの場合、これは無害です。しかし深夜2時にデプロイを待っている状況では、何が起きているのか、いつ完了するのかを把握しておく必要があります。

なぜこのエラーが発生するのか

RedisはRDBスナップショットを処理する際に子プロセスをフォークします。フォークは同時に1つしか実行できません。このエラーは以下の場合に発生します:

  • 前回のBGSAVE — 手動またはsave設定ルールによってトリガーされたもの — がまだ完了していない
  • BGREWRITEAOFが実行中 — 古いRedisバージョンでは、AOFの書き換えもBGSAVEをブロックする
  • レプリカが接続し、RedisがRDB送信のためにフォークした(レプリケーションによる暗黙的なセーブ)

何も壊れていません。Redisは二重フォークからあなたを守っています。すべきことは、現在のセーブが完了するまで待つか、そもそもセーブに時間がかかりすぎている原因を突き止めることです。

ステップ1 — 実際に何が実行されているかを確認する

まずここから始めます — 現在の永続化の状態を取得します:

redis-cli INFO persistence

注目すべきフィールド:

rdb_bgsave_in_progress:1          # 1 = セーブが現在実行中
rdb_current_bgsave_time_sec:42    # セーブ開始からの経過秒数
rdb_last_bgsave_status:ok         # 最後に完了したセーブのステータス
aof_rewrite_in_progress:0         # 1 = AOFの書き換えがフォーク中

rdb_bgsave_in_progress:1はセーブがアクティブであることを意味します。待ちましょう。完了するとRedisは0に戻します。

ステップ2 — 適切な方法で待つ

セーブが完了するまでポーリングします:

watch -n 2 'redis-cli INFO persistence | grep -E "bgsave_in_progress|bgsave_time_sec|last_bgsave"'

通常のディスクI/Oで数GB未満のデータセットであれば、BGSAVEは数秒から数分で完了します。5〜10分を過ぎても終わらない場合は問題があります — 以下のトラブルシューティングのセクションに進んでください。

rdb_bgsave_in_progress0になったら、BGSAVEを再実行します:

127.0.0.1:6379> BGSAVE
Background saving started

ステップ3 — 最初のセーブをトリガーしたものを特定する

Redisのログを見れば、何がきっかけになったか正確にわかります:

tail -n 100 /var/log/redis/redis-server.log | grep -i "bgsave\|save\|fork"

よく見られるログの行:

# 手動によるBGSAVE
* Background saving started by pid 12345

# saveルールによるトリガー(例:save 300 10)
* 10000 changes in 300 seconds. Saving...

# レプリケーションによるトリガー
* Starting BGSAVE for SYNC with target: disk

レプリケーションによるセーブの場合は、レプリカの接続を確認します:

redis-cli INFO replication | grep -E "connected_slaves|slave"

ステップ4 — BGSAVEに時間がかかりすぎている場合

セーブが遅い原因は3つに絞られます。順番に確認していきましょう。

ディスクが遅い大容量のデータセット

子プロセスはデータセット全体をディスクに書き込みます — すべてのバイトを。100 MB/sの速度のHDDで10 GBのデータセットがある場合、オーバーヘッドを考慮する前から少なくとも100秒かかります。データセットのサイズとディスクのスループットを確認しましょう:

redis-cli INFO memory | grep used_memory_human
iostat -x 1 5   # ディスク使用率を確認

ディスクI/Oが上限に達しているとセーブは遅くなります。RDBファイルをより高速なボリュームに移動しましょう:

# redis.conf
dir /mnt/fast-ssd/redis

高い書き込み負荷によるコピーオンライトの圧迫

フォーク後、Redisへの書き込みのたびにOSは影響を受けるメモリページをコピーします(コピーオンライト)。セーブ中に書き込みスループットが高いと、子プロセスのワーキングセットが膨らみます。コピーされるページが多いほど、セーブに時間がかかります。最後のセーブからどれだけ変更があったか確認しましょう:

redis-cli INFO stats | grep rdb_changes_since_last_save

数値が大きい場合、セーブの間隔が広すぎます。間隔を短くするか、オフピーク時間帯にセーブをスケジュールしましょう。

Transparent Huge Pagesによるフォークのレイテンシ

THPはRedisのパフォーマンスに悪影響を与えることで知られており、コピーオンライトのオーバーヘッドを大幅に増加させます。確認して無効化しましょう:

cat /sys/kernel/mm/transparent_hugepage/enabled
# [always]と表示されている場合は無効化する:
echo never > /sys/kernel/mm/transparent_hugepage/enabled

ステップ5 — 競合を避けるためにセーブ頻度を調整する

高負荷なサーバーでは、頻繁な自動セーブが主な原因です。デフォルトのルールは積極的に実行されるため、大きなデータセットではセーブが重複することがあります。redis.confで設定を緩めましょう:

# デフォルト(大容量データセットには頻度が高すぎることが多い)
save 900 1
save 300 10
save 60 10000

# より保守的 — 大きな変更量があった時だけ保存
save 900 1
save 300 1000

再起動なしで適用する:

redis-cli CONFIG SET save "900 1 300 1000"

ライブ設定が反映されたか確認する:

redis-cli CONFIG GET save

確認

セーブが正常に完了したことを確認します:

redis-cli INFO persistence | grep -E "rdb_bgsave_in_progress|rdb_last_bgsave_status|rdb_last_save_time"

正常な出力は次のようになります:

rdb_bgsave_in_progress:0
rdb_last_bgsave_status:ok
rdb_last_save_time:1714900000

次に、RDBファイル自体が更新されていることを確認します:

ls -lh $(redis-cli CONFIG GET dir | tail -1)/$(redis-cli CONFIG GET dbfilename | tail -1)

タイムスタンプが直近のセーブと一致しているはずです。

クイックリファレンス

  • 無視して問題ないのはセーブが既に実行中の場合 — 完了するまで待つだけ
  • 状態の確認: redis-cli INFO persistence | grep bgsave
  • BGSAVEの子プロセスを手動でkillしてはいけません — 何時間も実行中でない限り、書き込み途中でkillするとRDBファイルが破損します
  • LASTSAVEは最後に成功したセーブのUnixタイムスタンプを返します: redis-cli LASTSAVE
  • すべてのセーブを完全に停止するには: redis-cli CONFIG SET save "" — どの永続化を諦めるか理解した上でのみ実行してください

Related Error Notes