

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# Lua 脚本
<a name="BestPractices.Clients.Redis.LuaScripts"></a>

Valkey 和 Redis OSS 支持 200 多条命令，包括用于运行 Lua 脚本的命令。不过，对于 Lua 脚本，有几个缺陷可能会影响 Valkey 或 Redis OSS 的内存和可用性。

**非参数化 Lua 脚本**

每个 Lua 脚本在运行之前都会在 Valkey 或 Redis OSS 服务器上进行缓存。非参数化 Lua 脚本是独有的，这可能会导致 Valkey 或 Redis OSS 服务器存储大量 Lua 脚本并占用更多内存。为了减轻此情况，请确保所有 Lua 脚本都已参数化，并在需要时定期执行 SCRIPT FLUSH 来清除缓存的 Lua 脚本。

另请注意，必须提供键。如果未提供 KEY 参数的值，则脚本将失败。例如，以下脚本无效：

```
serverless-test-lst4hg.serverless.use1.cache.amazonaws.com:6379> eval 'return "Hello World"' 0
(error) ERR Lua scripts without any input keys are not supported.
```

以下脚本有效：

```
serverless-test-lst4hg.serverless.use1.cache.amazonaws.com:6379> eval 'return redis.call("get", KEYS[1])' 1 mykey-2
"myvalue-2"
```

以下示例说明如何定义和使用参数化脚本。首先，我们提供了一个非参数化方法的示例，它会生成三个不同的缓存 Lua 脚本，建议不使用此方法：

```
eval "return redis.call('set','key1','1')" 0
eval "return redis.call('set','key2','2')" 0
eval "return redis.call('set','key3','3')" 0
```

相反，请使用以下模式来创建能够接受传递的参数的单个脚本：

```
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key1 1 
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key2 2 
eval "return redis.call('set',KEYS[1],ARGV[1])" 1 key3 3
```

**长时间运行的 Lua 脚本**

Lua 脚本可以原子方式运行多条命令，因此它们的完成时间长于常用 Valkey 或 Redis OSS 命令的完成时间。如果 Lua 脚本仅运行只读操作，则可中途将其停止。不过，一旦 Lua 脚本执行写入操作，就无法将其终止，必须运行直至完成。如果长时间运行的 Lua 脚本发生突变，则会导致 Valkey 或 Redis OSS 服务器长时间无法响应。要缓解此问题，请避免长时间运行的 Lua 脚本，并在预生产环境中测试脚本。

**带 Stealth 写入的 Lua 脚本**

即使 Valkey 或 Redis OSS 超出 `maxmemory`，Lua 脚本也可通过以下几种方式继续向 Valkey 或 Redis OSS 写入新数据：
+ 该脚本在 Valkey 或 Redis OSS 服务器低于 `maxmemory` 时启动，并包含多个写入操作
+ 脚本的第一条写入命令不占用内存（例如 DEL），后跟的多个写入操作会占用内存
+ 可以通过在 `noeviction` 之外的 Valkey 或 Redis OSS 服务器中配置适当的驱逐策略来缓解此问题。这将允许 Redis OSS 在 Lua 脚本之间驱逐项目并释放内存。