为什么 redis 中的 lua 脚本如此慢?有什么解决方法吗?
2016-3-22 1:32:16
收藏:0
阅读:89
评论:3
我正在评估在 redis 中使用 lua 脚本,它们似乎有点慢。我进行如下基准测试:
- 对于一个非 lua 版本,我简单地执行了
SET key_i val_i1M 次 - 对于一个lua 版本,我做了同样的事情,但是在一个脚本中:
EVAL "SET KEYS[1] ARGV[1]" 1 key_i val_i
在我的笔记本电脑上测试,lua 版本大约比非 lua 版本慢 3 倍。我知道 lua 是一种脚本语言,而不是编译语言等等,但这似乎是很大的性能开销-这是正常的吗?
假设这确实是正常的,是否有任何解决办法?是否有一种方法来使用更快的语言(例如 redis 是用 C 编写的)实现脚本,以实现更好的性能?
编辑:我正在使用此处的 go 代码进行测试:https://gist.github.com/ortutay/6c4a02dee0325a608941
点赞
用户12671031
所以现在有一种解决方法,使用 John Sully 创建的模块。它适用于 Redis 和 KeyDB,允许您使用 V8 JIT 引擎,该引擎比 Lua 脚本运行更快速且可以运行复杂脚本。https://github.com/JohnSully/ModJS
2020-06-10 23:21:24
用户462398
我偶然发现了这个帖子,也对基准测试结果很感兴趣。我写了一个简单的 Ruby 脚本来比较它们。脚本使用不同选项在同一个键上执行简单的“SET / GET”操作。
require "redis"
def elapsed_time(name, &block)
start = Time.now
block.call
puts "#{name} - elapsed time: #{(Time.now-start).round(3)}s"
end
iterations = 100000
redis_key = "test"
redis = Redis.new
elapsed_time "Scenario 1: From client" do
iterations.times { |i|
redis.set(redis_key, i.to_s)
redis.get(redis_key)
}
end
eval_script1 = <<-LUA
redis.call("SET", "#{redis_key}", ARGV[1])
return redis.call("GET", "#{redis_key}")
LUA
elapsed_time "Scenario 2: Using EVAL" do
iterations.times { |i|
redis.eval(eval_script1, [redis_key], [i.to_s])
}
end
elapsed_time "Scenario 3: Using EVALSHA" do
sha1 = redis.script "LOAD", eval_script1
iterations.times { |i|
redis.evalsha(sha1, [redis_key], [i.to_s])
}
end
eval_script2 = <<-LUA
for i = 1,#{iterations} do
redis.call("SET", "#{redis_key}", tostring(i))
redis.call("GET", "#{redis_key}")
end
LUA
elapsed_time "Scenario 4: Inside EVALSHA" do
sha1 = redis.script "LOAD", eval_script2
redis.evalsha(sha1, [redis_key], [])
end
eval_script3 = <<-LUA
for i = 1,2*#{iterations} do
redis.call("SET", "#{redis_key}", tostring(i))
redis.call("GET", "#{redis_key}")
end
LUA
elapsed_time "Scenario 5: Inside EVALSHA with 2x the operations" do
sha1 = redis.script "LOAD", eval_script3
redis.evalsha(sha1, [redis_key], [])
end
我在我的 MacBook Pro 上得到了以下结果
Scenario 1: From client - elapsed time: 11.498s
Scenario 2: Using EVAL - elapsed time: 6.616s
Scenario 3: Using EVALSHA - elapsed time: 6.518s
Scenario 4: Inside EVALSHA - elapsed time: 0.241s
Scenario 5: Inside EVALSHA with 2x the operations - elapsed time: 0.5s
总的来说:
- 方案 1 与方案 2 显示主要贡献者是往返时间,因为方案 1 需要向 Redis 提交 2 个请求,而方案 2 只需 1 个,并且方案 1 的执行时间约为方案 2 的 2 倍。
- 方案 2 与方案 3 表明 EVALSHA 确实提供了一些好处,我相信这些好处会随着脚本复杂度的增加而增加。
- 方案 4 与方案 5 显示调用脚本的开销几乎可以忽略不计,因为我们将操作数量增加了一倍,执行时间增加了约 2 倍。
2021-10-07 15:05:36
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
问题不在于 Lua 或 Redis,而在于您的期望。您正在将脚本编译1百万次。没有理由期望这会很快。
Redis 中 EVAL 的目的不是执行单个命令;您可以自行执行。目的是在 Redis 自身中进行复杂逻辑,而不是在本地客户端上执行。也就是说,您实际上在单个 EVAL 脚本中执行了 1 百万个设置操作的整个系列,这将由 Redis 服务器本身执行。
我不太了解 Go,所以无法编写调用它的语法。但我知道 Lua 脚本会是什么样子:
for i = 1, ARGV[1] do local key = "key:" .. tostring(i) redis.call('SET', key, i) end将其放入 Go 字符串中,然后将其传递给适当的调用,不带键参数,并且单个非键参数是循环次数。