MST

星途 面试题库

面试题:Redis脚本管理命令之自动化操作基础

请阐述在Redis中使用脚本管理命令实现自动化操作时,EVAL和EVALSHA这两个命令的区别,并举例说明何时应该使用EVALSHA而不是EVAL。
19.7万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

区别

  1. 命令格式
    • EVAL 格式为 EVAL script numkeys key [key ...] arg [arg ...],其中 script 是完整的Lua脚本内容。
    • EVALSHA 格式为 EVALSHA sha1 numkeys key [key ...] arg [arg ...]sha1 是Lua脚本内容的SHA1摘要。
  2. 传输内容
    • EVAL 每次执行都需要将完整的Lua脚本发送给Redis服务器,若脚本较长,会增加网络传输开销。
    • EVALSHA 只需要发送脚本的SHA1摘要,网络传输量小很多,尤其适用于脚本内容较大的情况。
  3. 脚本存储
    • EVAL 每次执行时Redis服务器都要重新加载和编译Lua脚本。
    • EVALSHA 假设Redis服务器已经缓存了对应的Lua脚本(通过 SCRIPT LOAD 等方式预先加载),直接根据摘要找到脚本并执行,减少了重复加载和编译的开销。

何时使用EVALSHA而不是EVAL

  1. 脚本重复执行:当同一个Lua脚本需要在多个Redis操作中反复执行时,使用 EVALSHA 可以避免每次都传输和编译脚本。例如,在一个复杂的电商购物车业务中,添加商品、修改商品数量、删除商品等操作可能都用到同一个计算购物车总价的Lua脚本,此时使用 EVALSHA 更合适。
  2. 网络带宽有限:如果Redis客户端和服务器之间网络带宽有限,EVALSHA 减少的网络传输量可以显著提高性能。比如在一些物联网场景下,设备与Redis服务器之间通过窄带宽网络连接,此时使用 EVALSHA 能有效降低网络压力。

示例代码: 假设我们有一个简单的Lua脚本用于获取两个键的值并相加:

local val1 = redis.call('GET', KEYS[1])
local val2 = redis.call('GET', KEYS[2])
if val1 == nil then
    val1 = 0
end
if val2 == nil then
    val2 = 0
end
return tonumber(val1) + tonumber(val2)

使用 EVAL 执行:

redis-cli EVAL "local val1 = redis.call('GET', KEYS[1]) local val2 = redis.call('GET', KEYS[2]) if val1 == nil then val1 = 0 end if val2 == nil then val2 = 0 end return tonumber(val1) + tonumber(val2)" 2 key1 key2

使用 EVALSHA 执行: 首先加载脚本获取SHA1摘要:

redis-cli SCRIPT LOAD "local val1 = redis.call('GET', KEYS[1]) local val2 = redis.call('GET', KEYS[2]) if val1 == nil then val1 = 0 end if val2 == nil then val2 = 0 end return tonumber(val1) + tonumber(val2)"

假设返回的SHA1摘要为 abcdef1234567890,则执行:

redis-cli EVALSHA abcdef1234567890 2 key1 key2