使用StackExchange.Redis时,我们需要缓存已加载的脚本吗?

我正在创建一个主要用于非 Web 环境的库,通过 StackExchange.Redis 利用 Lua 脚本。

当使用 StackExchange.Redis 时,我们是否应该为每个 Evaluate 调用加载 Lua 脚本,例如:

var prepped = LuaScript.Prepare(_someScript);
var loaded = prepped.Load(someServer);
loaded.Evaluate(someDb);

或者我们应该加载一次,然后在给定进程中每次评估时重用 LoadedLuaScript 实例?

点赞
用户389828
用户389828

脚本应该在启动时加载一次,并保留 LoadedLuaScript 实例以供需要时评估。StackExchange.Redis 不会在任何地方缓存 LoadedLuaScripts,因此如果您每次调用都要执行预处理和加载过程,那么您需要做的就是让 StackExchange.Redis 将脚本传输到 Redis,在那里对其进行哈希,Redis 会意识到已经有了它,然后传回哈希。

如果您的进程不经常启动(对于某些频率),即使已在 Redis 中加载了它们,将所有脚本在启动时加载也是合理的,因为这不会导致多个脚本实例被缓存在 Redis 中。您可以将 LoadedLuaScripts 保留在简单的缓存中,例如:

    private static readonly string _helloScript =
          "print(\"Hello World!\")"
        ;

    public void LoadScripts(IDatabase db, IServer srv)
    {
        var scripts = new Dictionary<string, string>
        {
            { "sayHello",                      _helloScript },
        };

        foreach (var scriptName in scripts.Keys)
        {
            var prepped = LuaScript.Prepare(scripts[scriptName]);

            _scripts.Add(scriptName, prepped.Load(srv));
        }
    }

    public void SayHello(IDatabase db)
    {
        _scripts["sayHello"].Evaluate(db);
    }
2015-09-10 20:10:56
用户16487514
用户16487514

为了实现更好的性能,Lua 脚本可以被加载到 Redis 中,然后通过它们的哈希值进行调用。加载过程是可选的,并且只需要执行一次以获得性能提升。

使用 StackExchange.Redis,您不需要显式地使用 Load 方法。更容易让 StackExchange.Redis 处理缓存。LuaScript 类会在第一次调用 ScriptEvaluate 时自动将 Lua 脚本传输到 Redis。对于同一脚本的进一步调用,只使用哈希值:

var prepared = LuaScript.Prepare(script);
prepared.Evaluate(someDb); // 将脚本加载到 Redis 并调用它

var prepared2 = LuaScript.Prepare(script);
prepared2.Evaluate(someDb); // 通过哈希值调用脚本
2021-07-20 15:08:35
用户11423549
用户11423549

无法评论,但我想补充一下 @ChriZ 的回答,

LuaScript.Evaluate 看起来可能会使用缓存,通过查看 RedisDatabase.cs->GetMessages(没有检查)。。但是。。

根据Evaluate代码,它似乎做了一些肮脏的哈希正则表达式检查(ScriptLoadProcessor.IsSHA1)和很多其他检查,在我看来并不是很有效率。。

此外,如果您进入 LuaScript.cs,它明确写着:

与 LuaScript 不同,LoadedLuaScript 向 Redis 发送其可执行脚本的哈希值,而不是在每次调用时传递整个脚本。 这要求在使用脚本之前将其加载到 Redis 中。 要创建 LoadedLuaScript,请先通过 LuaScript.Prepare(string)创建 LuaScript,然后在返回的 LuaScript 上调用 Load(IServer,CommandFlags)。

如果我错了,请纠正我...

2021-10-16 05:32:45