Redis Sentinel:その「自動フェイルオーバー」という甘い罠と、真の可用性を掴む設計思想
Redisを運用するエンジニアにとって、Sentinelは「とりあえず導入しておけば安心」というお守りになりがちだ。だが、現場で数多の障害を乗り越えてきた経験から言わせれば、Sentinelをブラックボックスとして扱うのは、時限爆弾を抱えるのと同義だ。
なぜなら、Sentinelは単なる「監視ツール」ではなく、「ネットワーク分断という地獄」と「一貫性」の狭間で踊る、極めて繊細な分散合意システムだからだ。
本稿では、教科書的な説明は最小限に留め、本番環境で「刺される」ポイントを解剖し、堅牢なアーキテクチャを構築するための知見を共有する。
—
1. Sentinelは「分散合意」の戦場である
まず叩き込んでおくべきは、Sentinelのアーキテクチャが「多数決(Quorum)」という民主主義的な合意形成に基づいているという事実だ。
- Quorum(クォーラム)の意味: 障害を検知したSentinelが「マスターが死んだ」と判断する最小人数。
- 脳死状態の回避: 全てのSentinelが独立して動くわけではない。彼らはGossipプロトコルで通信し、「本当にマスターはダウンしたのか?」を議論する。
【実務上の鉄則】
Sentinelのノード数は、必ず「奇数(3台以上)」にすること。2台ではネットワークの瞬断が発生した瞬間に、双方のSentinelが「相手が死んだ」と誤解し、共倒れ(スプリット・ブレイン)を引き起こす可能性がある。
—
2. 現場で遭遇する「フェイルオーバーの罠」
Sentinelを導入しても、アプリケーションがダウンするケースは後を絶たない。その原因の多くは、クライアント側の「接続のライフサイクル」にある。
罠:IP固定という信仰
多くのエンジニアは、アプリケーション側のRedis接続先に「特定のマスターIP」をハードコードする。これは致命的だ。フェイルオーバーが起きた瞬間、そのIPはゴミとなり、アプリは接続不能に陥る。
【解決策:Sentinel Awareness】
Redisクライアントライブラリ(`go-redis`, `redis-py`, `Jedis`など)は、Sentinelをサポートしている。これらは起動時にSentinelノード群に問い合わせ、「現在のマスターは誰か?」を動的に解決する。
悪い例:IPを直接指定
r = redis.Redis(host=’10.0.0.1′, port=6379)
良い例:Sentinelを認識させる
from redis.sentinel import Sentinel
Sentinelノードを教えるだけで、マスターの追跡はライブラリが勝手にやる
sentinel = Sentinel([(‘sentinel1’, 26379), (‘sentinel2’, 26379)], socket_timeout=0.1)
master = sentinel.master_for(‘mymaster’, socket_timeout=0.1)
ここで取得するmasterは、フェイルオーバー後も自動で新マスターに再接続される
master.set(‘key’, ‘value’)
—
3. パフォーマンスとネットワークの「見えない壁」
Sentinelが誤検知を起こす最大の原因は、Redisの負荷による「一時的な無反応」だ。
- `down-after-milliseconds` のチューニング:
デフォルト値(通常30秒)は本番環境では長すぎる。しかし、短すぎると負荷スパイクだけでフェイルオーバーが走る。
- 計算式: `(Redisの最大I/O待ち) + (ネットワークの往復時間) + マージン`
- 多くの高負荷システムでは、5秒〜10秒程度に設定し、監視のメトリクス(`info replication`)とセットで調整する。
- スワップの恐怖:
Redisはメモリ上で動く。OSのメモリが不足し、Redisの一部がディスク(スワップ)に吐き出された瞬間、レスポンスは数秒単位で止まる。Sentinelはこれを「マスターダウン」と誤検知する。
アーキテクトの戒め: `vm.swappiness = 0` は必須。これなしでRedisを運用するのは、砂上の楼閣を建てるようなものだ。
—
4. 堅牢な設計パターンのための「チェックリスト」
私がコードレビューで必ず確認する項目を伝授する。
1. Proxyの排除:
Sentinel環境でEnvoyやHAProxyを挟む構成を好む者がいるが、それは複雑性を増すだけだ。クライアントライブラリがSentinelをサポートしているなら、直結させるのが最も低レイテンシで確実である。
2. 監視との分離:
Sentinelのログを監視して `+switch-master` や `+sdown` イベントを拾えるようにしておくこと。フェイルオーバーは「成功すればよし」ではなく、「なぜ起きたのか」を追跡できないと運用崩壊する。
3. クライアントの再試行戦略:
フェイルオーバー中、わずかに接続が切れる瞬間がある。アプリ側でリトライポリシー(指数バックオフ)を正しく実装していないと、その瞬間にリクエストが全滅する。
—
結論:Sentinelは「自動化」ではなく「保険」である
Sentinelは、マスターが死んだときに「最短で」系を切り替えるための仕組みであり、「障害が起きないようにする魔法」ではない。
結局のところ、最高の可用性は「Sentinelを信頼しすぎない」設計から生まれる。
- データの整合性は保たれているか?
- フェイルオーバー中の書き込みは防げているか?
- クライアントは瞬時の切断を許容できる構造か?
Sentinelを単なる機能として導入するのではなく、インフラ全体を「壊れる前提」で設計する。そのマインドセットを持って初めて、貴方のRedisシステムは真の堅牢性を手に入れる。
さあ、コードを書き、そして徹底的に負荷をかけてくれ。Sentinelが意図通りに動くかどうかを、本番環境に投入する前に、自らの手で破壊して確かめることだ。それがエンジニアとしての唯一の近道である。
コメント