すべてのプロダクト
Search
ドキュメントセンター

PolarDB:Lua スクリプト使用ガイド

最終更新日:Feb 11, 2026

分散ロック、レートリミッターの実装、条件付き更新など、単一のデータベース操作内で複数のコマンドをアトミックに実行する必要がある場合、複数のネットワークラウンドトリップはレイテンシーを増加させ、競合状態(race condition)のリスクを引き起こします。Orca は Redis 互換プロトコルであり、複数の Redis 互換コマンドを 1 つのスクリプトにカプセル化できる Lua スクリプティング機能を提供します。データベースはこのスクリプトをアトミックに実行するため、上記の課題を効果的に解決し、複雑な操作における実行効率およびデータ整合性を向上させます。

特長

Redis 互換プロトコルである Orca の Lua スクリプティング機能では、Redis と同様に Lua スクリプトを実行できます。主な利点は原子性と高性能です。

  • 原子性:スクリプト内のすべてのコマンドは分割不可能な単位として実行されます。他のコマンドやスクリプトが実行中のスクリプトを中断することはできません。これにより、アトミックな操作が保証され、部分実行によって生じる中間状態が防止されます。

  • 高性能

    • ネットワークオーバーヘッドの削減:複数のコマンドを 1 つのスクリプトにパッケージ化し、一度にデータベースへ送信できます。これにより、クライアントとサーバー間のネットワークラウンドトリップが大幅に削減されます。

    • スクリプトキャッシュ:事前に SCRIPT LOAD コマンドを使用してスクリプトをクラスタのメモリにプリロードし、SHA1 チェックサムを取得できます。その後、EVALSHA コマンドでこの短い SHA1 値のみを送信することでスクリプトを呼び出せます。これにより、ネットワーク上で転送されるデータ量がさらに削減されます。

適用範囲

  • クラスタバージョン:クラスタバージョンは MySQL 8.0.2 以上である必要があります。また、マイナーエンジンバージョンは 8.0.2.2.33 以降である必要があります。

  • エンドポイント:Lua スクリプトコマンドを実行するには、Orca アドレス を使用し、読み書きモード読み書き (自動読み書き分離) に設定する必要があります。

  • サポートされていないコマンドredis.call() または redis.pcall() を使用した Lua スクリプト内では、以下のコマンドを実行できません。これらのコマンドを使用すると、エラーが返されます。

    • トランザクション制御コマンド:WATCHUNWATCHMULTIEXEC、または DISCARD

    • ブロッキングコマンド:BLPOP または BRPOP

    • Lua スクリプティングコマンド:EVALEVAL_ROEVALSHAEVALSHA_RO、または SCRIPT

    • Pub/Sub コマンド:SUBSCRIBEUNSUBSCRIBEPSUBSCRIBE、または PUNSUBSCRIBE

    • 接続管理コマンド:AUTHHELLO、または CLIENT

基本構文

以下は、Lua スクリプトを操作するための主要コマンドです。詳細については、公式 Redis ウェブサイトの「Lua スクリプトコマンド」および「Lua を用いたスクリプティング」をご参照ください。

コマンド

構文

説明

EVAL

EVAL script numkeys [key [key ...]] [arg [arg ...]]

指定された Lua スクリプトを直接実行します。これは最も基本的な実行方法です。パラメーターの説明は以下のとおりです。

  • script:Lua スクリプト。

  • numkeysKEYS[] パラメーターの数を指定する非負整数。

  • KEYS[]:渡される Redis キーのパラメーター。配列のインデックスは 1 から始まります。

  • ARGV[]:渡されるスクリプトパラメーター。配列のインデックスは 1 から始まります。

EVAL_RO

EVAL_RO script numkeys [key [key ...]] [arg [arg ...]]

読み取り専用モードで Lua スクリプトを実行します。これは読み書き分離のシナリオに適用され、スクリプトが書き込み操作を行わないことを保証します。スクリプトに書き込みコマンドが含まれている場合、エラーが返されます。パラメーターの説明は EVAL と同じです。

EVALSHA

EVALSHA sha1 numkeys [key [key ...]] [arg [arg ...]]

SHA1 チェックサムを使用してキャッシュ済みのスクリプトを実行します。スクリプトがキャッシュされていない場合、NOSCRIPT エラーが返されます。対象のスクリプトを EVAL または SCRIPT LOAD コマンドでキャッシュした後、再試行してください。

EVALSHA_RO

EVALSHA_RO sha1 numkeys [key [key ...]] [arg [arg ...]]

SHA1 チェックサムを使用して、読み取り専用モードでキャッシュ済みのスクリプトを実行します。これは読み書き分離のシナリオに適用され、スクリプトが書き込み操作を行わないことを保証します。スクリプトに書き込みコマンドが含まれている場合、エラーが返されます。パラメーターの説明は EVALSHA と同じです。

SCRIPT LOAD

SCRIPT LOAD script

スクリプトをキャッシュに読み込み、後続の EVALSHA による呼び出しに使用する SHA1 チェックサムを返します。

SCRIPT EXISTS

SCRIPT EXISTS sha1 [sha1 ...]

1 つ以上の SHA1 チェックサムに対応するスクリプトがキャッシュ内に存在するかどうかを確認します。存在する場合は 1、存在しない場合は 0 を返します。

SCRIPT KILL

SCRIPT KILL

現在実行中の Lua スクリプトを終了します。Orca では、任意のスクリプト(書き込みスクリプトを含む)を終了でき、そのスクリプトによって行われたデータ変更を自動的にロールバックして、データ整合性を確保します。

SCRIPT FLUSH

SCRIPT FLUSH [ASYNC | SYNC]

現在のクラスタ内のすべての Lua スクリプトキャッシュをクリアします。

  • ASYNC:非同期でスクリプトキャッシュをクリアします。

  • SYNC(デフォルト):同期でスクリプトキャッシュをクリアします。

操作例

  1. テストデータを準備します:

    SET polardb orca
  2. テストコマンド:

    EVAL

    EVAL "return redis.call('GET', KEYS[1])" 1 polardb

    返り値の例:

    "orca"

    EVAL_RO

    EVAL_RO "return redis.call('GET', KEYS[1])" 1 polardb

    返り値の例:

    "orca"

    SCRIPT LOAD

    SCRIPT LOAD "return redis.call('GET', KEYS[1])"

    返り値の例:

    "d3c21d0c2b9ca22f82737626a27bcaf5d288f99f"

    EVALSHA

    EVALSHA d3c21d0c2b9ca22f82737626a27bcaf5d288f99f 1 polardb

    返り値の例:

    "orca"

    EVALSHA_R

    EVALSHA_RO d3c21d0c2b9ca22f82737626a27bcaf5d288f99f 1 polardb

    返り値の例:

    "orca"

    SCRIPT EXISTS

    SCRIPT EXISTS d3c21d0c2b9ca22f82737626a27bcaf5d288f99f ffffffffffffffffffffffffffffffffffffffff

    返り値の例:

    1) (integer) 1
    2) (integer) 0

    SCRIPT FLUSH

    警告

    このコマンドはクラスタ内のすべての Lua スクリプトキャッシュをクリアします。SCRIPT LOAD または EVAL によって生成されたキャッシュも削除されます。

    • キャッシュをクリアした後、EVALSHA または EVALSHA_RO に依存するすべての呼び出しで NOSCRIPT エラーが発生する可能性があります。スクリプトを再読み込みして操作を再試行する必要があります。

    • 多数のスクリプトがキャッシュされている場合、SCRIPT FLUSH コマンドがクラスタを長時間ブロックする可能性があります。ピーク時を避けて実行することを推奨します。

    • スクリプトのソースコードはクライアントまたはアプリケーション側に保持し、NOSCRIPT エラーに対する自動回復機構を実装することを推奨します。たとえば、SCRIPT LOAD を使用してスクリプトを再読み込みしたり、EVAL を使用して再登録したりできます。

    SCRIPT FLUSH

    返り値の例:

    OK

よくあるユースケース

アトミックカウンターの設定と実行

同時実行の INCR 操作によって生じる競合状態を回避できます。これにより、カウンターが厳密に増分され、条件付きでリセット可能になります。

処理の概要

  1. Lua スクリプトを作成します。

  2. クラスタのキャッシュに読み込みます。

  3. EVALSHA を使用してスクリプトを再利用・実行します。

SCRIPT LOAD + EVALSHA の組み合わせを使用すると、ネットワークトラフィックが削減され、パフォーマンスおよびべき等性が向上します。また、スクリプトの内容はリクエストボディに公開されません。

操作手順

  1. スクリプトを作成し、ローカルに保存します:

    -- counter.lua: キーが存在しない場合は 0 に設定し、その後 1 増分する。新しい値を返す。
    if redis.call('EXISTS', KEYS[1]) == 0 then
      redis.call('SET', KEYS[1], 0)
    end
    return redis.call('INCR', KEYS[1])
  2. スクリプトを読み込んで SHA1 チェックサムを取得します

    SCRIPT LOAD "if redis.call('EXISTS', KEYS[1]) == 0 then redis.call('SET', KEYS[1], 0) end return redis.call('INCR', KEYS[1])"
    
    
    -- 返り値
    "b547eabbcde73b25330442e4f4e4dc1783b91241"
  3. (推奨)スクリプトを再利用して実行します:

    EVALSHA b547eabbcde73b25330442e4f4e4dc1783b91241 1 my_counter
    
    -- 返り値
    (integer) 1
    -- 再度実行した場合の返り値
    (integer) 2

読み取り専用スクリプトの実行

  1. スクリプトに書き込み操作が含まれていないことを確認しますスクリプトが SETDELHSET、または LPUSH などの書き込みコマンドを呼び出していないかを確認します。書き込みコマンドが含まれている場合は、EVAL_RO を使用しないでください。

    説明

    スクリプトに書き込みコマンドが含まれている場合、エラー (error) ERR Write commands are not allowed from read-only scripts. が返されます。

  2. EVAL_RO を使用してスクリプトを実行します:

    EVAL_RO "return {redis.call('SET', KEYS[1]), redis.call('TTL', KEYS[1])}" 1 polardb
    
    -- 返り値
    1) "orca"
    2) (integer) -1

異常稼働中の Lua スクリプトを停止する

長時間実行されるスクリプトがクラスタをブロックするのを防ぐことができます。このため、SCRIPT KILL コマンドを使用して実行を中断します。システムはデータ整合性を維持するために、そのスクリプトによって行われたすべての変更を自動的にロールバックします。

説明

現在実行中のスクリプトのみを終了できます。SHA1 値を指定して特定のスクリプトを終了することはできません。

SCRIPT KILL

-- 返り値
OK

パフォーマンス最適化のベストプラクティス

Lua スクリプトによるクラスタへのブロッキング影響を軽減し、機能的に重複した多数のスクリプトのキャッシュによる過剰なメモリ使用量を防ぐため、以下のベストプラクティスに従うことを推奨します:

  • タイムアウト制限:単一の Lua スクリプトのデフォルト実行タイムアウトは 300 秒です。

    • 過剰なメモリ消費を防ぐため、過大な Lua スクリプトの作成は避けてください。

    • Lua スクリプト内で長時間実行される処理や大量データの書き込みは避けてください。

  • ブロッキングリスク: Lua スクリプトはクラスタ内でアトミックに実行されます。実行中は他のコマンドおよびスクリプトをブロックします。そのため、書き込みバッチサイズおよび実行時間を制御し、長時間のループや広範囲の走査を回避する必要があります。必要に応じて、複雑なロジックを複数の独立したスクリプトに分割して実行できます。

  • 永続化されないスクリプトキャッシュ:Lua スクリプトキャッシュはクラスタの実行中にクリアされません。ただし、クラスタの再起動、高可用性(HA)スイッチオーバー、または SCRIPT FLUSH コマンドの実行後にキャッシュはクリアされます。これらの場合は、スクリプトを再登録する必要があります。

  • スクリプト作成ガイドラインKEYS[] および ARGV[] を使用してパラメーターを渡します。スクリプト内にパラメーターをハードコーディングしないでください。

  • ネットワークトラフィックの削減SCRIPT LOAD + EVALSHA の組み合わせを使用して、最適なパフォーマンスとネットワークトラフィックの削減を実現します。

操作例

  1. スクリプトの読み込み:アプリケーションの初期化時または初回使用時に、SCRIPT LOAD を使用してスクリプトをクラスタに読み込み、SHA1 値を取得します。アプリケーションはこの SHA1 値をローカルに保存する必要があります。

    # キーの値を設定するスクリプトを読み込む
    SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])"
    # 返り値の例
    "55b22c0d0cedf3866879ce7c854970626dcef0c3"
  2. スクリプトの実行:その後、前ステップで取得した SHA1 値を EVALSHA コマンドで使用してスクリプトを実行します。

    # キャッシュ済みのスクリプトを使用して k1 = v1 を設定
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1
    # 同じキャッシュ済みのスクリプトを使用して k2 = v2 を設定
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2
  3. NOSCRIPT エラーの処理EVALSHANOSCRIPT エラーを返した場合、アプリケーションはこのエラーを捕捉する必要があります。その後、アプリケーションは自動的に EVAL または SCRIPT LOAD コマンドを使用してスクリプトを 1 回実行し、クラスタにキャッシュできます。

    • EVAL:実行中にスクリプトを自動的に再キャッシュします。

    • SCRIPT LOAD:スクリプトをクラスタに読み込み、SHA1 値を取得します。

  4. Lua スクリプトのメモリ使用量のクリア:今後 Lua スクリプトを実行する予定がない場合は、SCRIPT FLUSH コマンドを実行して Lua スクリプトキャッシュをクリアできます。クラスタに多数の Lua スクリプトがキャッシュされている場合、このコマンドがクラスタを長時間ブロックする可能性があります。ピーク時を避けて実行することを推奨します。

よくある質問

  • NOSCRIPT No matching script. Please use EVAL. エラーをどう処理すればよいですか?

    原因:このエラーは、EVALSHA または EVALSHA_RO コマンドを使用して、クラスタのキャッシュに存在しないスクリプトを実行しようとした場合に発生します。このエラーは、通常、クラスタの再起動、高可用性(HA)スイッチオーバー、または SCRIPT FLUSH コマンドの実行後に発生します。
    解決策:クライアントコードにエラー処理ロジックを実装する必要があります。NOSCRIPT エラーを捕捉した場合、EVAL または SCRIPT LOAD コマンドを使用してスクリプトを再実行し、クラスタにキャッシュできます。その後、EVALSHA の呼び出しは正常に動作します。

  • Lua スクリプトの実行がタイムアウトした場合はどうすればよいですか?

    デフォルトのスクリプトタイムアウトは 300 秒です。タイムアウトエラーは、通常、スクリプトのロジックが複雑すぎるか、処理するデータ量が多すぎるために発生します。
    解決策:

    • スクリプトのロジックを最適化します。スクリプト内で非効率なループや大規模なデータ走査を避けてください。

    • スクリプトの実行時間が長すぎる場合は、SCRIPT KILL コマンドを使用して終了できます。PolarDB は、そのスクリプトによって行われたすべての変更をロールバックします。

    • 複雑なビジネスロジックを、複数の小さな高速なスクリプトに分割し、段階的に実行します。

  • EVAL_RO を使用してスクリプトを実行した際に、エラー ERR Write commands are not allowed from read-only scripts. が返されるのはなぜですか?

    EVAL_RO および EVALSHA_RO は読み取り専用モードであり、SETHSET、または DEL などの書き込み操作を厳密に禁止します。このエラーは、スクリプトに書き込みコマンドが含まれていることを示しています。
    解決策:

    • スクリプトを確認し、すべての書き込みコマンドを削除します。

    • 書き込み操作を実行するには、EVAL または EVALSHA コマンドを使用します。