All Products
Search
Document Center

Tair (Redis® OSS-Compatible):Spesifikasi skrip Lua dan kesalahan umum

Last Updated:Jun 26, 2026

Tair (Redis OSS-compatible) mendukung perintah Lua. Anda dapat menggunakan skrip Lua untuk menangani operasi compare-and-set (CAS) secara efisien, meningkatkan performa instans, serta mengimplementasikan pola yang sulit atau tidak efisien dicapai dengan cara lain. Topik ini menjelaskan sintaks dasar dan panduan penggunaan skrip Lua.

Sintaks dasar

Show details

Untuk informasi lebih lanjut tentang perintah Redis, kunjungi situs resmi Redis.

Command

Syntax

Description

EVAL

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

Menjalankan skrip dengan parameter yang ditentukan dan mengembalikan hasilnya.

Parameter:

  • script: Skrip Lua.

  • numkeys: Bilangan bulat non-negatif yang menentukan jumlah argumen kunci dalam array KEYS[].

  • KEYS[]: Argumen kunci Redis yang diteruskan ke skrip.

  • ARGV[]: Argumen skrip yang diteruskan ke skrip. Indeks untuk KEYS[] dan ARGV[] dimulai dari 1.

Catatan
  • Seperti perintah SCRIPT LOAD, perintah EVAL menyimpan cache skrip Lua pada instans.

  • Penggunaan KEYS[] dan ARGV[] yang tidak tepat dapat menyebabkan perilaku tak terduga, terutama dalam mode kluster. Untuk informasi lebih lanjut, lihat Batasan khusus dalam arsitektur kluster.

  • Kami merekomendasikan agar Anda meneruskan nilai melalui parameter KEYS[] dan ARGV[] saat memanggil skrip Lua, alih-alih menyematkan parameter ke dalam skrip Lua. Jika tidak, penggunaan memori mesin virtual Lua akan meningkat dan tidak dapat dikurangi sesegera mungkin. Dalam skenario terburuk, terjadi error out of memory (OOM) pada instans dan berakibat kehilangan data.

EVALSHA

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

Menjalankan skrip berdasarkan digest SHA1-nya.

Jika Anda menjalankan perintah EVALSHA dan skrip yang sesuai dengan nilai sha1 belum disimpan dalam cache Redis, Redis akan mengembalikan error NOSCRIPT. Untuk mengatasinya, gunakan perintah EVAL atau SCRIPT LOAD untuk menyimpan skrip dalam cache, lalu coba lagi. Untuk informasi lebih lanjut, lihat Error NOSCRIPT.

SCRIPT LOAD

SCRIPT LOAD script

Menyimpan skrip yang diberikan dalam cache instans dan mengembalikan digest SHA1-nya.

SCRIPT EXISTS

SCRIPT EXISTS script [script ...]

Memeriksa apakah satu atau beberapa skrip, yang diidentifikasi berdasarkan digest SHA1-nya, ada dalam cache skrip instans. Perintah ini mengembalikan 1 untuk setiap skrip yang ada dan 0 untuk setiap skrip yang tidak ada.

SCRIPT KILL

SCRIPT KILL

Menghentikan skrip Lua yang sedang berjalan.

SCRIPT FLUSH

SCRIPT FLUSH

Menghapus semua skrip Lua dari cache skrip instans saat ini.

Kode contoh berikut memberikan contoh perintah Redis spesifik. Sebelum menjalankan perintah berikut, perintah SET foo value_test telah dijalankan.

  • Contoh perintah EVAL:

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

    Output contoh:

    "value_test"
  • Contoh perintah SCRIPT LOAD:

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

    Output contoh:

    "620cd258c2c9c88c9d10db67812ccf663d96bdc6"
  • Contoh perintah EVALSHA:

    EVALSHA 620cd258c2c9c88c9d10db67812ccf663d96bdc6 1 foo

    Output contoh:

    "value_test"
  • Contoh perintah SCRIPT EXISTS:

    SCRIPT EXISTS 620cd258c2c9c88c9d10db67812ccf663d96bdc6 ffffffffffffffffffffffffffffffffffffffff

    Output contoh:

    1) (integer) 1
    2) (integer) 0
  • Contoh perintah SCRIPT FLUSH:

    Peringatan

    Perintah ini menghapus semua skrip Lua yang tersimpan dalam cache instans. Pastikan Anda melakukan backup skrip Lua sebelum menjalankan perintah ini.

    SCRIPT FLUSH

    Output contoh:

    OK

Optimisasi performa

Optimalkan overhead memori dan jaringan

Menyimpan cache sejumlah besar skrip yang fungsinya berulang mengonsumsi memori signifikan dan bahkan dapat memicu error out of memory (OOM). Berikut adalah contoh penggunaan yang salah:

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

Solusi:

  • Untuk mengurangi pemborosan memori, hindari hardcoding argumen sebagai konstanta dalam skrip Lua.

    # Mencapai fungsi yang sama seperti contoh salah tetapi hanya menyimpan cache skrip sekali.
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k1 v1
    EVAL "return redis.call('set', KEYS[1], ARGV[1])" 1 k2 v2
  • Untuk efisiensi lebih tinggi, kami merekomendasikan pendekatan berikut untuk mengurangi penggunaan memori dan overhead jaringan.

    SCRIPT LOAD "return redis.call('set', KEYS[1], ARGV[1])"    # Setelah dieksekusi, Redis mengembalikan "55b22c0d0cedf3866879ce7c854970626dcef0c3".
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k1 v1
    EVALSHA 55b22c0d0cedf3866879ce7c854970626dcef0c3 1 k2 v2

Bersihkan memori skrip Lua

Cache skrip Lua mengonsumsi memori instans, yang berkontribusi terhadap metrik used_memory. Jika penggunaan memori instans mendekati atau melebihi maxmemory, hal ini dapat memicu error out of memory (OOM). Contoh error ditunjukkan di bawah ini:

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

Solusi:

Jalankan perintah SCRIPT FLUSH dari client untuk membersihkan cache skrip Lua. Metode yang direkomendasikan bergantung pada versi instans Anda:

  • Pembersihan asinkron (Direkomendasikan): open source Redis 7.0 atau versi lebih baru dan Tair (Enterprise Edition) 6.0 atau versi lebih baru mendukung perintah SCRIPT FLUSH ASYNC. Perintah ini membersihkan cache skrip Lua di latar belakang tanpa memblokir instans, sehingga meminimalkan dampak terhadap layanan Anda.

    SCRIPT FLUSH ASYNC
  • Pembersihan sinkron: Untuk versi sebelumnya, perintah SCRIPT FLUSH beroperasi secara sinkron. Jika instans memiliki banyak skrip Lua yang tersimpan dalam cache, perintah ini dapat memblokir instans dalam waktu lama dan membuatnya tidak tersedia. Gunakan perintah ini dengan hati-hati, sebaiknya pada jam sepi.

    SCRIPT FLUSH
Catatan

Mengklik Purge Data di konsol hanya menghapus data dan tidak membersihkan cache skrip Lua.

Selain itu, hindari menulis skrip Lua yang terlalu besar untuk mencegah konsumsi memori tinggi. Jangan melakukan penulisan data massal dalam skrip Lua karena dapat menyebabkan lonjakan penggunaan memori dan berpotensi memicu error OOM. Jika logika bisnis Anda memungkinkan, kami merekomendasikan mengaktifkan eviction data (diaktifkan secara default dengan kebijakan volatile-lru) untuk menghemat ruang memori. Namun, instans tidak akan menghapus cache skrip Lua, terlepas dari apakah eviction data diaktifkan atau tidak.

Penanganan error

Error NOSCRIPT

Saat Anda menggunakan perintah EVALSHA, jika skrip yang sesuai dengan nilai sha1 belum disimpan dalam cache instans, instans akan mengembalikan error NOSCRIPT. Contohnya ditunjukkan di bawah ini:

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

Solusi:

Gunakan perintah EVAL atau SCRIPT LOAD untuk menyimpan skrip dalam cache instans, lalu coba lagi. Namun, instans tidak menjamin persistensi atau replikasi skrip Lua. Dalam beberapa skenario, seperti migrasi instans atau perubahan konfigurasi, cache skrip Lua mungkin dihapus. Oleh karena itu, aplikasi client Anda harus mampu menangani error ini. Untuk informasi lebih lanjut, lihat Masalah persistensi dan replikasi.

Demo Python berikut menunjukkan contoh cara menangani error NOSCRIPT. Demo ini menggunakan skrip Lua untuk melakukan operasi prepend string.

Catatan

Anda juga dapat menggunakan library redis-py untuk Python guna menangani jenis error ini. Library tersebut menyediakan kelas Script yang mengenkapsulasi logika tingkat rendah untuk skrip Lua Redis, seperti menangkap error NOSCRIPT.

import redis
import hashlib

# Fungsi ini menerima skrip Lua sebagai string dan mengembalikan digest SHA1-nya.
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]:      # Periksa apakah skrip tersimpan dalam cache Redis.
            return self.evalsha(script_sha1, 1, key, value) # Jika tersimpan, jalankan skrip dengan EVALSHA.
        else:
            return self.eval(script_content, 1, key, value) # Jika tidak, jalankan skrip dengan EVAL, yang juga menyimpannya dalam cache. Atau, Anda bisa menggunakan SCRIPT LOAD lalu 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"))
            

Error timeout skrip Lua

  • Karena skrip Lua dieksekusi secara atomik, skrip yang berjalan lambat dapat memblokir instans. Jika skrip berjalan lebih dari 5 detik, instans akan mengembalikan error BUSY untuk semua perintah lain hingga skrip selesai dieksekusi.

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

    Solusi:

    Anda dapat menggunakan perintah SCRIPT KILL untuk menghentikan skrip Lua atau menunggu hingga skrip selesai.

    Catatan
    • Perintah SCRIPT KILL tidak berlaku selama 5 detik pertama eksekusi skrip lambat karena instans sedang diblokir.

    • Saat menulis skrip Lua, perkirakan waktu eksekusinya dan periksa masalah seperti infinite loop. Hal ini membantu mencegah skrip berjalan lama yang memblokir instans dan membuat layanan tidak tersedia. Jika perlu, pecah skrip panjang menjadi beberapa skrip yang lebih kecil.

  • Jika skrip Lua saat ini telah mengeksekusi perintah write, perintah SCRIPT KILL tidak akan berfungsi. Contoh error ditunjukkan di bawah ini:

    (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.

    Solusi:

    Di konsol, buka halaman Instances dan klik restart untuk instans yang sesuai.

Masalah persistensi dan replikasi

Instans menyimpan cache skrip Lua yang dieksekusi secara permanen kecuali jika instans direstart atau perintah SCRIPT FLUSH dipanggil. Namun, dalam situasi tertentu, seperti migrasi instans, perubahan konfigurasi, upgrade versi, atau alih bencana HA, instans tidak menjamin persistensi skrip Lua atau replikasinya ke node lain.

Solusi:

Karena instans tidak menjamin persistensi atau replikasi skrip, Anda harus menyimpan semua skrip Lua secara lokal. Jika diperlukan, gunakan perintah EVAL atau SCRIPT LOAD untuk menyimpan kembali skrip dalam cache instans. Hal ini mencegah error NOSCRIPT yang dapat terjadi jika cache skrip dihapus selama operasi seperti restart instans atau alih bencana HA.

Batasan khusus dalam arsitektur kluster

Batasan arsitektur kluster

  • Untuk menjamin atomicity, skrip Lua tidak dapat dibagi dan harus dieksekusi pada satu shard dalam arsitektur kluster. Instans biasanya menggunakan kunci untuk menentukan shard mana yang akan menerima perintah tersebut. Oleh karena itu, Anda harus menentukan setidaknya satu kunci saat mengeksekusi skrip Lua dalam kluster. Jika skrip mengakses beberapa kunci, semua kunci tersebut harus berada dalam slot yang sama; jika tidak, skrip akan gagal atau mengembalikan hasil yang salah. Perintah tanpa kunci, seperti KEYS, SCAN, dan FLUSHDB, dapat dijalankan tetapi hanya akan mengembalikan data dari satu shard. Batasan ini merupakan bagian inheren dari arsitektur Redis Cluster.

  • Menjalankan perintah SCRIPT LOAD pada satu node tidak menjamin bahwa skrip tersebut disimpan pada node lain.

Kode error dalam mode proxy

Proxy melakukan pemeriksaan sintaks untuk mengidentifikasi secara proaktif kasus-kasus di mana kunci tersebar di beberapa slot. Hal ini membantu mendeteksi masalah lebih awal untuk mempermudah troubleshooting. Metode pemeriksaan proxy berbeda dari mesin virtual Lua, sehingga menimbulkan batasan tambahan saat mengeksekusi perintah Lua dalam mode proxy. Misalnya, perintah UNPACK tidak didukung, dan perintah EVAL, EVALSHA, serta perintah seri SCRIPT tidak dapat digunakan dalam transaksi MULTI/EXEC.

Anda juga dapat menonaktifkan beberapa pemeriksaan sintaks Lua proxy dengan mematikan parameter script_check_enable.

Selain itu, untuk instans pemisahan baca/tulis, jika parameter readonly_lua_route_ronode_enable diaktifkan, proxy memeriksa apakah skrip Lua hanya berisi perintah read-only untuk menentukan apakah skrip tersebut dapat diteruskan ke node read-only. Logika pemeriksaan ini memberlakukan batasan pada sintaks Lua.

Catatan

Menonaktifkan parameter script_check_enable memiliki efek berikut:

  • Untuk instans open source Redis 5.0 (versi minor sebelum 5.0.8) atau Redis 4.0 dan versi sebelumnya, kami tidak merekomendasikan menonaktifkan parameter ini. Melakukannya dapat menyebabkan skrip mengembalikan pesan sukses meskipun dieksekusi secara salah.

  • Untuk versi lainnya, menonaktifkan parameter ini menghentikan proxy dari pemeriksaan sintaks Lua, tetapi node data tetap akan melakukan pemeriksaan sintaks normal mereka.

Berikut adalah kode error spesifik beserta penyebabnya.

Batasan arsitektur Redis Cluster

  • Kode error: -ERR for redis cluster, eval/evalsha number of keys can't be negative or zero\r\n

    Deskripsi: Anda harus menentukan setidaknya satu kunci saat mengeksekusi skrip Lua. Proxy menggunakan kunci tersebut untuk menentukan shard mana yang akan menerima skrip.

    # Contoh yang benar
    EVAL "return redis.call('get', KEYS[1])" 1 fooeval
    
    # Contoh yang salah
    EVAL "return redis.call('get', 'foo')" 0
  • Kode error: -ERR 'xxx' command keys must in same slot

    Deskripsi: Semua kunci dalam skrip Lua harus berada dalam slot yang sama.

    # Contoh yang benar:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Contoh yang salah:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo foobar

Batasan sintaks Lua proxy

Catatan

Anda dapat menghindari pemeriksaan sintaks Lua tambahan dari proxy dengan menonaktifkan parameter script_check_enable.

  • Kode error: -ERR bad lua script for redis cluster, nested redis.call/redis.pcall

    Deskripsi: Pemanggilan Redis bersarang tidak didukung. Gunakan variabel lokal sebagai alternatif.

    # Contoh yang benar
    EVAL "local value = redis.call('GET', KEYS[1]); redis.call('SET', KEYS[2], value)" 2 foo bar
    
    # Contoh yang salah
    EVAL "redis.call('SET', KEYS[1], redis.call('GET', KEYS[2]))" 2 foo bar
  • Kode error: -ERR bad lua script for redis cluster, first parameter of redis.call/redis.pcall must be a single literal string

    Deskripsi: Perintah yang dipanggil dalam redis.call/pcall harus berupa string literal.

    # Contoh yang benar
    eval "redis.call('GET', KEYS[1])" 1 foo
    
    # Contoh yang salah
    eval "local cmd = 'GET'; redis.call(cmd, KEYS[1])" 1 foo

Batasan dalam versi tertentu (berlaku hanya untuk open source Redis 5.0 dengan versi minor sebelum 5.0.8, Redis 4.0 dan versi sebelumnya, edisi cloud-native dengan versi proxy sebelum 7.0.2, dan edisi classic dengan versi proxy sebelum 6.8.12)

Catatan
  • Batasan berikut hanya berlaku untuk open source Redis 5.0 (versi minor sebelum 5.0.8), Redis 4.0 dan versi sebelumnya, atau instans dengan versi proxy lama (edisi cloud-native sebelum 7.0.2 atau edisi classic sebelum 6.8.12).

  • Umumnya, jika versi instans dan proxy Anda lebih tinggi dari yang tercantum, Anda dapat mengabaikan konten berikut. Namun, jika instans Anda versi lebih tinggi tetapi masih menunjukkan batasan ini, ubah parameter proxy apa pun (seperti query_cache_expire), tunggu 1 menit, lalu coba lagi.

  • Kode error: -ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array\r\n

    Deskripsi: Semua kunci harus diteruskan melalui array KEYS. Untuk perintah dalam redis.call/pcall, posisi kunci harus menggunakan array KEYS, dan Anda tidak boleh mengganti KEYS dengan variabel Lua.

    # Contoh yang benar:
    EVAL "return redis.call('mget', KEYS[1], KEYS[2])" 2 foo {foo}bar
    
    # Contoh yang salah:
    EVAL "return redis.call('mget', KEYS[1], '{foo}bar')" 1 foo                      # Kunci '{foo}bar' harus diteruskan melalui array KEYS.
    EVAL "local i = 2 return redis.call('mget', KEYS[1], KEYS[i])" 2 foo {foo}bar    # Skrip ini tidak diizinkan dalam mode proxy karena indeks array KEYS adalah variabel. Batasan ini tidak ada dalam mode koneksi langsung.
    EVAL "return redis.call('mget', KEYS[1], ARGV[1])" 1 foo {foo}bar                # Elemen dari array ARGV tidak boleh digunakan sebagai kunci.
  • Kode error: -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

    Deskripsi: Parameter destination dari perintah ZUNIONSTORE dan ZINTERSTORE harus diteruskan menggunakan array KEYS.

  • Kode error: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE numkeys parameter should be a single number and not expression

    Deskripsi: Parameter numkeys dari perintah ZUNIONSTORE dan ZINTERSTORE harus berupa konstanta, bukan ekspresi.

  • Kode error: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE numkeys value is not an integer or out of range

    Deskripsi: Parameter numkeys dari perintah ZUNIONSTORE dan ZINTERSTORE bukan angka.

  • Kode error: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE all the keys that the script uses should be passed using the KEYS array

    Deskripsi: Semua kunci untuk perintah ZUNIONSTORE dan ZINTERSTORE harus diteruskan menggunakan array KEYS.

  • Kode error: -ERR bad lua script for redis cluster, XREAD/XREADGROUP all the keys that the script uses should be passed using the KEYS array

    Deskripsi: Semua kunci untuk perintah XREAD dan XREADGROUP harus diteruskan menggunakan array KEYS.

  • Kode error: -ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array, and KEYS should not be in expression, sort command store key does not meet the requirements

    Deskripsi: Kunci untuk perintah SORT harus diteruskan menggunakan array KEYS.

Masalah izin baca/tulis

  • Kode error: -ERR Write commands are not allowed from read-only scripts

    Deskripsi: Skrip Lua yang dikirim dengan perintah EVAL_RO tidak boleh berisi perintah write.

  • Kode error: -ERR bad write command in no write privilege

    Deskripsi: Skrip Lua yang dikirim dari akun read-only tidak boleh berisi perintah write.

Perintah yang tidak didukung

  • Kode error: -ERR script debug not support

    Deskripsi: Proxy saat ini tidak mendukung perintah SCRIPT DEBUG.

  • Kode error: -ERR bad lua script for redis cluster, redis.call/pcall unkown redis command xxx

    Deskripsi: Skrip Lua berisi perintah yang tidak didukung oleh proxy. Untuk informasi lebih lanjut, lihat Batasan perintah pada instans kluster dan pemisahan baca/tulis.

Error sintaks Lua

  • Kode error: -ERR bad lua script for redis cluster, redis.call/pcall expect '(' atau -ERR bad lua script for redis cluster, redis.call/redis.pcall definition is not complete, expect ')'

    Catatan: Ini adalah error sintaks Lua karena fungsi redis.call harus diikuti oleh sepasang tanda kurung lengkap: ( dan ).

  • Kode error: -ERR bad lua script for redis cluster, at least 1 input key is needed for ZUNIONSTORE/ZINTERSTORE

    Deskripsi: Parameter numkeys dari perintah ZUNIONSTORE dan ZINTERSTORE harus lebih besar dari 0.

  • Kode error: -ERR bad lua script for redis cluster, ZUNIONSTORE/ZINTERSTORE key count < numkeys

    Deskripsi: Jumlah kunci aktual untuk perintah ZUNIONSTORE atau ZINTERSTORE kurang dari nilai numkeys yang ditentukan.

  • Kode error: -ERR bad lua script for redis cluster, xread/xreadgroup command syntax error

    Deskripsi: Sintaks perintah XREAD atau XREADGROUP salah. Periksa jumlah parameternya.

  • Kode error: -ERR bad lua script for redis cluster, xread/xreadgroup command syntax error, streams must be specified

    Deskripsi: Perintah XREAD dan XREADGROUP harus menyertakan parameter streams.

  • Kode error: -ERR bad lua script for redis cluster, sort command syntax error

    Deskripsi: Sintaks perintah SORT salah.

FAQ

  • T: Dapatkah saya mengeksekusi skrip Lua di Data Management (DMS)?

    J: Konsol Data Management (DMS) saat ini tidak mendukung perintah terkait Lua. Untuk menggunakan skrip Lua, sambungkan ke instans Anda menggunakan client atau redis-cli.