Redisは、トランザクションを処理するための2つのメカニズムを提供します。MULTI/EXECベースのトランザクションとLuaスクリプトの評価です。 Redis Luaスクリプトが推奨されるアプローチであり、使用法でかなり人気があります。
LuaスクリプトをデプロイしているRedis™のお客様は、このエラーを報告することがよくあります–「BUSYRedisはスクリプトの実行で忙しいです。 SCRIPTKILLまたはSHUTDOWNNOSAVEにのみ電話をかけることができます 」。この投稿では、スクリプトのRedisトランザクションプロパティ、このエラーの内容、およびフェイルオーバーが可能なSentinel管理システムで特に注意する必要がある理由について説明します。
RedisLuaスクリプトのトランザクションの性質
Redisの「トランザクション」は、従来のように実際にはトランザクションではありません。エラーが発生した場合、スクリプトによる書き込みのロールバックはありません。
Redisスクリプトの「Atomicity」は次の方法で保証されます。
- スクリプトの実行が開始されると、スクリプトが完了するまで、他のすべてのコマンド/スクリプトはブロックされます。そのため、他のクライアントは、スクリプトによって行われた変更を確認するか、確認しません。これは、スクリプトの前またはスクリプトの後にしか実行できないためです。
- ただし、Redisはロールバックを実行しないため、スクリプト内でエラーが発生した場合、スクリプトによって既に行われた変更は保持され、将来のコマンド/スクリプトにはそれらの部分的な変更が表示されます。
- スクリプトの実行中は他のすべてのクライアントがブロックされるため、スクリプトが適切に動作し、時間内に終了することが重要です。
「lua-time-limit」値
スクリプトを制限時間内に完了することを強くお勧めします。 Redisはこれを弱い方法で実施します 「lua-time-limit」値を使用します。これは、スクリプトの実行が許可される最大許容時間(ミリ秒単位)です。デフォルト値は5秒です。これは、CPUにバインドされたアクティビティにとって非常に長い時間です(スクリプトはアクセスが制限されており、ディスクにアクセスするコマンドを実行できません)。
ただし、この時間を超えて実行しても、スクリプトは強制終了されません。 Redisはクライアントコマンドの受け入れを再開しますが、BUSYエラーで応答します。
この時点でスクリプトを強制終了する必要がある場合は、次の2つのオプションを使用できます。
- スクリプトキル コマンドを使用して、まだ書き込みを行っていないスクリプトを停止できます。
- スクリプトがすでにサーバーへの書き込みを実行していて、それでも強制終了する必要がある場合は、 SHUTDOWN NOSAVEを使用します。 サーバーを完全にシャットダウンします。
通常は、スクリプトが操作を完了するのを待つ方がよいでしょう。スクリプトの実行を強制終了する方法と関連する動作に関する完全な情報は、ドキュメントに記載されています。
Redisトランザクションと長時間実行されるLuaスクリプトクリックしてツイートSentinelで監視される高可用性システムでの動作
センチネル管理の高可用性システムは、これに新しいしわを追加します。実際、この説明は、Redisサーバーの正常性のポーリングに依存する高可用性システムに適用されます。
- 実行時間の長いスクリプトは、最初はクライアントコマンドをブロックします。後で「lua-time-limit」が経過すると、サーバーはBUSYエラーで応答を開始します。
- センチネルは、そのようなノードを使用不可と見なし、これがセンチネルに設定されたミリ秒後のダウン値を超えて続く場合、ノードがダウンしていると判断します。
- そのようなノードがマスターである場合、フェイルオーバーが開始されます。レプリカノードが昇格し、クライアントからの新しい接続の受け入れを開始する可能性があります。
- その間、古いマスターは最終的にスクリプトの実行を完了し、オンラインに戻ります。ただし、Sentinelは最終的にレプリカとして再構成し、新しいマスターとの同期を開始します。スクリプトによって書き込まれたデータはすべて失われます。
|
デモンストレーション
このフェイルオーバー動作を実証するために、機密性の高い高可用性システムをセットアップしました。セットアップには、3センチネルクォーラムによって監視されているマスター/レプリカ構成で実行されている2台のRedisサーバーがあります。
lua-time-limit値は500ミリ秒に設定されているため、スクリプトが500ミリ秒を超えて実行されると、エラーのあるクライアントへの応答が開始されます。センチネルのミリ秒後のダウン値は5秒に設定されているため、エラーを報告するノードは5秒後にダウンとマークされます。
マスターで次のLuaスクリプトを実行します:
local i = 0 while (true) do local key = "Key-" .. i local value = "Value-" .. i redis.call('set', key, value) i = i + 1 redis.call('time') end
これにより、Redisマスターにエントリが書き込まれ続けます。センチネルの1つでイベントを購読して、行動を観察します。
スクリプトはマスターで開始されます:
$ redis-cli -a --eval test.lua Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Sentinelで見られるように、切り捨てられた一連のアクティビティがあります:
3) "+vote-for-leader" 4) "9096772621089bb885eaf7304a011d9f46c5689f 1" 1) "pmessage" 2) "*" 3) "+sdown" <<< master marked DOWN 4) "master test 172.31.2.48 6379" 1) "pmessage" 2) "*" 3) "+odown" 4) "master test 172.31.2.48 6379 #quorum 3/2" 1) "pmessage" 2) "*" 3) "-role-change" << role change initiated 4) "slave 172.31.28.197:6379 172.31.28.197 6379 @ test 172.31.2.48 6379 new reported role is master" 1) "pmessage" 2) "*" 3) "+config-update-from" 4) "sentinel 9096772621089bb885eaf7304a011d9f46c5689f 172.31.2.48 26379 @ test 172.31.2.48 6379" 1) "pmessage" 2) "*" 3) "+switch-master" 4) "test 172.31.2.48 6379 172.31.28.197 6379"
後で、古いマスターがオンラインになると、レプリカに変更されます:
3) "-role-change" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379 new reported role is master" 1) "pmessage" 2) "*" 3) "-sdown" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379" 1) "pmessage" 2) "*" 3) "+role-change" 4) "slave 172.31.2.48:6379 172.31.2.48 6379 @ test 172.31.28.197 6379 new reported role is slave"
スクリプトを介して古いマスターに書き込まれたすべてのデータが失われます。
推奨事項
- 本番環境にデプロイする前に、実行時間の長いスクリプトの特性を事前に知っておく必要があります。
- スクリプトが定期的にlua-time-limitに違反している場合は、可能な最適化についてスクリプトを徹底的に確認する必要があります。また、許容可能な期間で完了するように分割することもできます。
- lua-time-limitに違反するスクリプトを実行する必要がある場合は、他のクライアントアクティビティが少ない時間帯にこれらのスクリプトをスケジュールすることを検討してください。
- lua-time-limitの値も増やすことができます。これは、スクリプトと並行して実行される他のクライアントアプリケーションが、ビジーエラーではなく、極端に遅延した応答の受信と後で再試行することを許容できる場合、許容できるソリューションです。
Sentinelで監視される高可用性システムに関する追加の考慮事項:
- スクリプトが読み取り操作のみを実行していて、使用可能なレプリカがある場合は、これらのスクリプトをレプリカに移動できます。
Sentinelパラメーターをミリ秒後にdown-after-millisecondsの値に変更して、フェイルオーバーが開始されないようにします。値を大幅に増やすとシステムの高可用性特性が損なわれるため、慎重に検討した後でのみこれを行う必要があります。これにより、正規のサーバー障害が無視される可能性もあります。
|