面试题答案
一键面试区别
- 命令格式:
EVAL
格式为EVAL script numkeys key [key ...] arg [arg ...]
,其中script
是完整的Lua脚本内容。EVALSHA
格式为EVALSHA sha1 numkeys key [key ...] arg [arg ...]
,sha1
是Lua脚本内容的SHA1摘要。
- 传输内容:
EVAL
每次执行都需要将完整的Lua脚本发送给Redis服务器,若脚本较长,会增加网络传输开销。EVALSHA
只需要发送脚本的SHA1摘要,网络传输量小很多,尤其适用于脚本内容较大的情况。
- 脚本存储:
EVAL
每次执行时Redis服务器都要重新加载和编译Lua脚本。EVALSHA
假设Redis服务器已经缓存了对应的Lua脚本(通过SCRIPT LOAD
等方式预先加载),直接根据摘要找到脚本并执行,减少了重复加载和编译的开销。
何时使用EVALSHA而不是EVAL
- 脚本重复执行:当同一个Lua脚本需要在多个Redis操作中反复执行时,使用
EVALSHA
可以避免每次都传输和编译脚本。例如,在一个复杂的电商购物车业务中,添加商品、修改商品数量、删除商品等操作可能都用到同一个计算购物车总价的Lua脚本,此时使用EVALSHA
更合适。 - 网络带宽有限:如果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