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

Tair (Redis® OSS-Compatible):Lua スクリプトの構文と一般的なエラーの解決策

最終更新日:Nov 09, 2025

Tair (Redis OSS-compatible) インスタンスは Lua コマンドをサポートしています。Lua スクリプトは、CAS (Compare-And-Set) コマンドを効率的に処理し、インスタンスのパフォーマンスを向上させ、以前は実装が困難または非効率だった機能の実装を簡素化できます。このトピックでは、Lua スクリプトの構文と使用方法について説明します。

構文

クリックして詳細を表示

Redis コマンドの詳細については、「」をご参照ください。Redis 公式ウェブサイト

コマンド

構文

説明

EVAL

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

パラメーターを受け取り、出力を返す指定されたスクリプトを実行します。

パラメーター:

  • script: Lua スクリプト。

  • numkeys: KEYS 配列の引数の数。数値は負でない整数です。

  • KEYS[]: 引数としてスクリプトに渡すキー。

  • ARGV[]: スクリプトに渡す追加の引数。KEYS[] と ARGV[] パラメーターのインデックスは 1 から始まります。

説明
  • EVAL コマンドは、SCRIPT LOAD コマンドと同様の方法でスクリプトをスクリプトキャッシュにロードします。

  • KEYS[]ARGV[] を混用または誤用すると、特にクラスターモードでは、インスタンスが異常動作する可能性があります。 詳細については、「クラスタアーキテクチャの特定の制限」をご参照ください。

  • Lua スクリプトを呼び出すには、Lua スクリプトにパラメーターをエンコードするのではなく、KEYS[] および ARGV[] パラメーターで値を渡すことを推奨します。そうしないと、Lua 仮想マシンのメモリ使用量が増加し、早期に削減できなくなります。最悪の場合、インスタンスでメモリ不足 (OOM) エラーが発生し、データが失われます。

EVALSHA

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

SHA1 ダイジェストによってキャッシュされたスクリプトを評価し、スクリプトを実行します。

EVALSHA コマンドを使用するときにスクリプトが Tair (Redis OSS-compatible) にキャッシュされていない場合、Tair は NOSCRIPT エラーを返します。EVAL または SCRIPT LOAD コマンドを実行してスクリプトを Tair にキャッシュし、再試行してください。詳細については、「NOSCRIPT エラー」をご参照ください。

SCRIPT LOAD

SCRIPT LOAD script

指定されたスクリプトをキャッシュし、スクリプトの SHA1 ダイジェストを返します。

SCRIPT EXISTS

SCRIPT EXISTS script [script ...]

対応する SHA1 ダイジェを使用して、スクリプトキャッシュ内に 1 つ以上のスクリプトが存在するかどうかに関する情報を返します。指定されたスクリプトが存在する場合、値 1 が返されます。それ以外の場合は、値 0 が返されます。

SCRIPT KILL

SCRIPT KILL

実行中の Lua スクリプトを終了させます。

SCRIPT FLUSH

SCRIPT FLUSH

現在のインスタンスのスクリプトキャッシュからすべての Lua スクリプトを削除します。

次のサンプルコードは、特定の Redis コマンドの例を示しています。次のコマンドを実行する前に、SET foo value_test コマンドが実行されます。

  • EVAL コマンドの例:

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

    出力例:

    "value_test"
  • SCRIPT LOAD コマンドの例:

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

    出力例:

    "620cd258c2c9c88c9d10db67812ccf663d96bdc6"
  • EVALSHA コマンドの例:

    EVALSHA 620cd258c2c9c88c9d10db67812ccf663d96bdc6 1 foo

    出力例:

    "value_test"
  • SCRIPT EXISTS コマンドの例:

    SCRIPT EXISTS 620cd258c2c9c88c9d10db67812ccf663d96bdc6 ffffffffffffffffffffffffffffffffffffffff

    出力例:

    1) (integer) 1
    2) (integer) 0
  • SCRIPT FLUSH コマンドの例:

    警告

    このコマンドは、インスタンスからキャッシュされたすべての Lua スクリプトを削除します。このコマンドを実行する前に、必ず Lua スクリプトをバックアップしてください。

    SCRIPT FLUSH

    出力例:

    OK

パフォーマンス最適化の実践

メモリとネットワークのオーバーヘッドを削減する

重複した機能を持つ多くのスクリプトがインスタンスにキャッシュされると、大量のメモリを消費し、メモリ不足 (OOM) エラーを引き起こすことさえあります。以下は、不正な使用例です。

EVAL "return redis.call('set', 'k1', 'v1')" 0
EVAL "return redis.call('set', 'k2', 'v2')" 0

ソリューション:

  • メモリ使用量を削減するために、パラメーターを定数として Lua スクリプトに渡さないでください。

    # 次のコマンドは、前のサンプルコマンドと同じ目的を果たしますが、スクリプトを一度だけキャッシュします。
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k1 v1
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k2 v2
  • 次のコマンド構文を使用して、メモリとネットワークのオーバーヘッドを削減します:

    SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])"    # このコマンドを実行すると、Redis は "55b22c0d0cedf3866879ce7c854970626dcef0c3" を返します
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2

Lua スクリプトキャッシュをフラッシュする

Lua スクリプトキャッシュがインスタンスのメモリを占有するため、インスタンスの使用済みメモリが予想よりも高くなることがあります。インスタンスの使用済みメモリが上限に近づくか超えると、OOM エラーが返されます。エラー例:

-OOM command not allowed when used memory > 'maxmemory'.

ソリューション:

クライアントで SCRIPT FLUSH コマンドを実行して、Lua スクリプトキャッシュをフラッシュします。FLUSHALL コマンドとは異なり、SCRIPT FLUSH コマンドは同期的です。インスタンスが多くの Lua スクリプトをキャッシュしている場合、SCRIPT FLUSH コマンドはインスタンスを長時間ブロックし、関連するインスタンスが利用できなくなる可能性があります。注意して進めてください。この操作はオフピーク時に実行することを推奨します。

説明

コンソールで データをクリアする をクリックしても、データはクリアできますが、Lua スクリプトキャッシュはフラッシュできません。

過剰なメモリを占有する可能性のある Lua スクリプトを記述しないでください。また、大量のデータを含む Lua スクリプトも記述しないでください。そうしないと、メモリ使用量が大幅に増加し、OOM エラーが発生する可能性があります。メモリ使用量を削減するには、データのエビクション (インスタンスではデフォルトで有効、volatile-lru モード) を有効にすることを推奨します。ただし、データのエビクションが有効になっているかどうかに関係なく、インスタンスは Lua スクリプトキャッシュをエビクションしません。

エラー処理ガイド

NOSCRIPT エラー

EVALSHA コマンドを使用するときにスクリプトがインスタンスにキャッシュされていない場合、インスタンスは NOSCRIPT エラーを返します。エラー例:

(error) NOSCRIPT No matching script. Please use EVAL.

ソリューション:

EVAL または SCRIPT LOAD コマンドを実行してスクリプトをインスタンスにキャッシュし、再試行してください。インスタンスの移行や構成の変更などの特定のシナリオでは、インスタンスは Lua スクリプトの永続性と複製可能性を保証できないため、Lua スクリプトキャッシュをフラッシュします。この場合、クライアントがエラーを処理できる必要があります。詳細については、「永続性とレプリケーションの問題」をご参照ください。

次のサンプル Python コードは、NOSCRIPT エラーを処理するメソッドを示しています。サンプルコードは、Lua スクリプトを使用して文字列を先頭に追加します。

説明

redis-py を使用してこのエラーを処理することもできます。redis-py は、NOSCRIPT エラーの catch 文など、Redis の Lua スクリプトの判断ロジックをカプセル化する Script クラスを提供します。

import redis
import hashlib

# strin は Lua スクリプト内の文字列です。この関数は strin の sha1 値を文字列形式で返します。
def calcSha1(strin):
    sha1_obj = hashlib.sha1()
    sha1_obj.update(strin.encode('utf-8'))
    sha1_val = sha1_obj.hexdigest()
    return sha1_val

class MyRedis(redis.Redis):

    def __init__(self, host="localhost", port=6379, password=None, decode_responses=False):
        redis.Redis.__init__(self, host=host, port=port, password=password, decode_responses=decode_responses)

    def prepend_inLua(self, key, value):
        script_content = """\
        local suffix = redis.call("get", KEYS[1])
        local prefix = ARGV[1]
        local new_value = prefix..suffix
        return redis.call("set", KEYS[1], new_value)
        """
        script_sha1 = calcSha1(script_content)
        if self.script_exists(script_sha1)[0] == True:      # スクリプトが Redis にすでにキャッシュされているかどうかを確認します。
            return self.evalsha(script_sha1, 1, key, value) # スクリプトがすでにキャッシュされている場合は、EVALSHA コマンドを使用してスクリプトを実行します。
        else:
            return self.eval(script_content, 1, key, value) # それ以外の場合は、EVAL コマンドを使用してスクリプトを実行します。EVAL コマンドは Redis にスクリプトをキャッシュできることに注意してください。SCRIPT LOAD および EVALSHA コマンドを使用することもできます。

r = MyRedis(host="r-******.redis.rds.aliyuncs.com", password="***:***", port=6379, decode_responses=True)

print(r.prepend_inLua("k", "v"))
print(r.get("k"))
            

Lua スクリプトのタイムアウトエラー

  • Lua スクリプトはインスタンス内で原子的に実行されるため、遅い Lua リクエストはインスタンスをブロックする可能性があります。1 つの Lua スクリプトは最大 5 秒間インスタンスをブロックできます。5 秒後、スクリプトの実行が完了するまで、インスタンスは他のコマンドに対して BUSY エラーを返します。

    BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.

    ソリューション:

    SCRIPT KILL コマンドを実行して Lua スクリプトを終了させるか、Lua スクリプトの実行が完了するまで待ちます。

    説明
    • 遅い Lua スクリプトが実行されている最初の 5 秒間は、インスタンスがブロックされているため、SCRIPT KILL コマンドは効果がありません。

    • インスタンスが長時間ブロックされるのを防ぐために、Lua スクリプトを作成する際に、Lua スクリプトの実行に必要な時間を推定し、無限ループがないか確認し、必要に応じて Lua スクリプトを分割することを推奨します。

  • Lua スクリプトがすでにデータセットに対して書き込みコマンドを実行している場合、SCRIPT KILL コマンドは効果がありません。エラー例:

    (error) UNKILLABLE Sorry the script already executed write commands against the dataset. You can either wait the script termination or kill the server in a hard way using the SHUTDOWN NOSAVE command.

    ソリューション:

    コンソールの インスタンス一覧 ページで、管理したいインスタンスを見つけて 再起動 をクリックします。

永続性とレプリケーションの問題

Tair (Redis OSS-compatible) は、インスタンスが再起動されないか、インスタンスに対して SCRIPT FLUSH コマンドが実行されない限り、インスタンスで実行された Lua スクリプトをキャッシュし続けます。ただし、Tair (Redis OSS-compatible) は、インスタンスの移行、構成の変更、バージョンのスペックアップ、インスタンスのスイッチオーバーなどのシナリオにおいて、Lua スクリプトの永続性や、現在のノードから他のノードへの Lua スクリプトの同期を保証できません。

ソリューション:

すべての Lua スクリプトをオンプレミスデバイスに保存します。必要に応じて、EVAL または SCRIPT LOAD コマンドを使用して、Tair (Redis OSS-compatible) に Lua スクリプトを再キャッシュします。これにより、インスタンスの再起動または高可用性 (HA) スイッチオーバー中に Lua スクリプトがクリアされたときに NOSCRIPT エラーが発生するのを防ぎます。

クラスターインスタンスの特別な制限

クラスターアーキテクチャの制約

  • 実行の原子性を確保するために、Lua スクリプトは分割できず、クラスターインスタンス内の 1 つのシャードでのみ実行できます。ほとんどの場合、キーを使用して Lua スクリプトがルーティングされるシャードを決定します。したがって、クラスターインスタンスで Lua スクリプトを実行するときは、少なくとも 1 つのキーを指定する必要があります。複数のキーを読み書きする場合、1 つの Lua スクリプト内のキーは同じスロットに属している必要があります。そうしないと、異常な実行結果が返されます。キーを持たない Lua スクリプト (KEYS、SCAN、FLUSHDB など) は正常に実行できます。ただし、単一のシャードのデータのみが返されます。この制限は、クラスターインスタンスのアーキテクチャに起因します。

  • 1 つのノードで SCRIPT LOAD コマンドを実行しても、Lua スクリプトが他のノードに保存されない場合があります。

プロキシモードのエラーコード

プロキシは構文チェックを実行して、複数のスロットに属するキーを特定し、トラブルシューティングを支援するために事前に例外をスローします。プロキシは Lua 仮想マシンとは異なるチェックメソッドを使用します。これにより、プロキシモードでの Lua スクリプトの実行に追加の制限が課せられます。たとえば、UNPACK コマンドはサポートされておらず、EVAL、EVALSHA、および SCRIPT コマンドは MULTI および EXEC トランザクションではサポートされていません。

また、script_check_enable パラメーターを設定して、プロキシモードでの Lua 構文の追加チェックを無効にすることもできます。

読み書き分離インスタンスに対して readonly_lua_route_ronode_enable パラメーターが 1 に設定されている場合、プロキシノードは Lua スクリプトに読み取り専用コマンドのみが含まれているかどうかをチェックし、読み取り専用ノードに転送するかどうかを決定します。このチェックロジックは Lua 構文に制限を課します。

説明

script_check_enable パラメーターを 0 に設定すると、インスタンスにどのような影響がありますか?

  • インスタンスが Redis 5.0 (マイナーバージョン 5.0.8 未満) および 4.0 以前と互換性がある場合、チェックを無効にしないことを推奨します。そうしないと、スクリプトが正常に実行されない場合に正常な結果が返される可能性があります。

  • 他のバージョンでチェックを無効にすると、プロキシは Lua 構文をチェックしなくなりますが、データノードは引き続き Lua 構文をチェックします。

以下にエラーコードとその原因を説明します。

Redis Cluster アーキテクチャの制限

  • エラーコード: -ERR for redis cluster, eval/evalsha number of keys can't be negative or zero\r\n

    説明: Lua スクリプトを実行するときは、キーを含める必要があります。プロキシノードはキーを使用して、Lua スクリプトが転送されるシャードを決定します。

    # 有効な使用例
    EVAL "return redis.call('get', KEYS[1])" 1 fooeval
    
    # 無効な使用例
    EVAL "return redis.call('get', 'foo')" 0
  • エラーコード: -ERR 'xxx' command keys must in same slot

    説明: Lua スクリプト内の複数のキーは、同じスロットに属している必要があります。

    # 有効な使用例:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # 無効な使用例:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo foobar

プロキシモードでの Lua 構文チェックによる追加の制限

説明

script_check_enable パラメーターを 無効 にして、プロキシが Lua 構文の追加チェックを実行しないようにすることができます。

  • エラーコード: -ERR bad lua script for redis cluster, nested redis.call/redis.pcall

    説明: ネストされた呼び出しはサポートされていません。ローカル変数を使用して Lua スクリプトを呼び出すことができます。

    # 有効な使用例
    EVAL "local value = redis.call('GET', KEYS[1]); redis.call('SET', KEYS[2], value)" 2 foo bar
    
    # 無効な使用例
    EVAL "redis.call('SET', KEYS[1], redis.call('GET', KEYS[2]))" 2 foo bar
  • エラーコード: -ERR bad lua script for redis cluster, first parameter of redis.call/pcall must be a single literal string

    説明: redis.call/pcall で呼び出されるコマンドは、文字列リテラルである必要があります。

    # 有効な使用例
    eval "redis.call('GET', KEYS[1])" 1 foo
    
    # 無効な使用例
    eval "local cmd = 'GET'; redis.call(cmd, KEYS[1])" 1 foo

特定バージョンの制限 (Community Edition 5.0 (マイナーバージョン 5.0.8 未満)、バージョン 4.0 以前のインスタンス、クラウドネイティブ版 7.0.2 未満のプロキシバージョン、または クラシック版 6.8.12 未満のプロキシバージョンのみ)

説明
  • 次の制限は、Redis 5.0 (マイナーバージョン 5.0.8 未満) または Redis 4.0 以前を実行する Community Edition インスタンス、または古いプロキシバージョン (クラウドネイティブ版 7.0.2 未満または クラシック版 6.8.12 未満) のインスタンスにのみ適用されます。

  • ほとんどの場合、インスタンスのバージョンとプロキシのバージョンが上記のバージョンよりも高い場合は、次の内容を無視できます。ただし、インスタンスのバージョンが上記のバージョンよりも高い場合でも制限が依然として存在する場合は、query_cache_expire などのプロキシパラメーターを変更します。1 分待ってから再試行してください。

  • エラーコード:-ERR Redis クラスター用の Lua スクリプトが不正です。スクリプトが使用するすべてのキーは、KEYS 配列を使用して渡す必要があります\r\n

    redis.call または redis.pcall 内で呼び出されるコマンドの場合、すべてのキーは KEYS 配列から渡す必要があり、Lua 変数にすることはできません。

    # 有効なコマンドの使用例:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # 無効なコマンドの使用例:
    EVAL "return redis.call('mget', KEYS[1], '{foo}bar')" 1 foo                      # このコマンドは、'{foo}bar' キーを KEYS 配列を使用して指定する必要があるため無効です。
    EVAL "local i = 2 return redis.call('mget', KEYS[1], KEYS[i])" 2 foo {foo}bar    # このコマンドは、キーのインデックスが変数で構成されているため無効です。これはプロキシモードのインスタンスでは許可されていません。直接接続モードのインスタンスはこの制限を受けません。
    EVAL "return redis.call('mget', KEYS[1], ARGV[1])" 1 foo {foo}bar                # このコマンドは、ARGV[1] をキーとして指定できないため無効です。
  • エラーコード: -ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array, include destination, and KEYS should not be in expression

    説明: ZUNIONSTORE および ZINTERSTORE コマンドの destination パラメーターは、KEYS 配列を使用して指定する必要があります。

  • エラーコード: Redis クラスター用の Lua スクリプトが不正です。ZUNIONSTORE/ZINTERSTORE の numkeys パラメーターは、式ではなく単一の数値である必要があります。

    説明: ZUNIONSTORE および ZINTERSTORE コマンドの numkeys パラメーターは定数ではありません。

  • エラーコード: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE numkeys value is not an integer or out of range

    説明: ZUNIONSTORE および ZINTERSTORE コマンドの numkeys パラメーターは数値ではありません。

  • エラーコード: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE all the keys that the script uses should be passed using the KEYS array

    説明: ZUNIONSTORE および ZINTERSTORE コマンドのすべてのキーは、KEYS 配列を使用して指定する必要があります。

  • エラーコード: -ERR Redis クラスター用の Lua スクリプトが不正です。XREAD/XREADGROUP では、スクリプトが使用するすべてのキーを KEYS 配列を使用して渡す必要があります。

    説明: XREAD および XREADGROUP コマンドのすべてのキーは、KEYS 配列を使用して指定する必要があります。

  • エラーコード: -ERR Redis クラスター用の Lua スクリプトが不正です。スクリプトが使用するすべてのキーは KEYS 配列を使用して渡す必要があり、KEYS は式に含めることはできず、SORT コマンドのストアキーは要件を満たしていません。

    説明: SORT コマンドのキーは、KEYS 配列を使用して指定する必要があります。

読み取り/書き込み権限の問題

  • エラーコード: -ERR Write commands are not allowed from read-only scripts

    説明: EVAL_RO コマンドを使用して送信された Lua スクリプトに書き込みコマンドを含めることはできません。

  • エラーコード: -ERR bad write command in no write privilege

    説明: 読み取り専用アカウントによって送信された Lua スクリプトに書き込みコマンドを含めることはできません。

サポートされていないコマンド

  • エラーコード: -ERR script debug not support

    説明: SCRIPT DEBUG コマンドはプロキシモードではサポートされていません。

  • エラーコード: -ERR bad lua script for redis cluster, redis.call/pcall unkown redis command xxx

    説明: Lua スクリプトには、プロキシモードでサポートされていないコマンドが含まれています。詳細については、「クラスターアーキテクチャおよび読み書き分離インスタンスのコマンドの制限」をご参照ください。

Lua 構文エラー

  • エラーコード: -ERR bad lua script for redis cluster, redis.call/pcall expect '(' または -ERR bad lua script for redis cluster, redis.call/redis.pcall definition is not complete, expect ')'

    説明: Lua 構文エラー。redis.call 関数には、完全な () のセットが続く必要があります。

  • エラーコード: -ERR bad lua script for redis cluster, at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE

    説明: ZUNIONSTORE および ZINTERSTORE コマンドの numkeys パラメーターは 0 より大きい必要があります。

  • エラーコード: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE key count < numkeys

    説明: ZUNIONSTORE および ZINTERSTORE コマンドのキーの数は numkeys の値より小さいです。

  • エラーコード: -ERR bad lua script for redis cluster, xread/xreadgroup command syntax error

    説明: XREAD または XREADGROUP コマンドの構文が正しくありません。パラメーターの数を確認してください。

  • エラーコード: -ERR Redis クラスター用の不正な Lua スクリプト、xread/xreadgroup コマンドの構文エラー、ストリームが指定されていません

    説明: XREAD および XREADGROUP コマンドでは streams パラメーターが必要です。

  • エラーコード: -ERR bad lua script for redis cluster, sort command syntax error

    説明: SORT コマンドの構文が正しくありません。

よくある質問

  • Q: DMS は Lua スクリプトの実行をサポートしていますか?

    A: Lua スクリプトに関連するコマンドは、現在 DMS コンソールではサポートされていません。クライアントまたは redis-cli を使用してインスタンスに接続し、Lua スクリプトを使用できます。