面试题答案
一键面试- Lua脚本大致逻辑:
- 获取商品库存:使用
redis.call('GET', key)
获取商品库存键对应的值,这个值表示当前商品的剩余库存。 - 判断库存是否足够:通过
if tonumber(stock) >= 1 then
判断库存是否大于等于1(假设每次抢购1个商品)。 - 库存足够时减库存:如果库存足够,使用
redis.call('DECR', key)
减少库存。 - 返回结果:库存足够返回1(表示抢购成功),库存不足返回0(表示抢购失败)。 示例Lua脚本如下:
local key = KEYS[1] local stock = redis.call('GET', key) if tonumber(stock) >= 1 then redis.call('DECR', key) return 1 else return 0 end
- 获取商品库存:使用
- EVALSHA命令的参数传递:
- 计算脚本的SHA1值:在客户端使用
redis-cli --eval script.lua key, arg
命令(假设脚本保存在script.lua
文件中),或者在编程语言中通过相应的Redis库函数获取脚本的SHA1值。例如在Python中使用redis - py
库:
import redis r = redis.Redis() script = """ local key = KEYS[1] local stock = redis.call('GET', key) if tonumber(stock) >= 1 then redis.call('DECR', key) return 1 else return 0 end """ sha1 = r.script_load(script)
- 使用EVALSHA命令:在高并发场景下,使用
EVALSHA sha1 numkeys key [key...] arg [arg...]
格式调用。其中sha1
是前面计算得到的脚本SHA1值,numkeys
是键参数的数量(通常为1,因为只有商品库存这一个键),key
是商品库存的键名,arg
这里没有用到(因为逻辑简单,不需要额外参数)。例如在Python中:
result = r.evalsha(sha1, 1, 'product_stock')
- 计算脚本的SHA1值:在客户端使用
- 可能遇到的问题与解决方案:
- 脚本未加载问题:如果在执行
EVALSHA
命令时,Redis服务器上还未加载该脚本(可能由于重启等原因),会返回NOSCRIPT
错误。解决方案是在捕获到NOSCRIPT
错误时,重新使用SCRIPT LOAD
命令加载脚本,然后再次执行EVALSHA
。例如在Python中:
try: result = r.evalsha(sha1, 1, 'product_stock') except redis.ResponseError as e: if e.args[0].startswith('NOSCRIPT'): r.script_load(script) result = r.evalsha(sha1, 1, 'product_stock')
- 并发控制不当:虽然Lua脚本在Redis中是原子执行的,但如果多个客户端同时获取到库存足够的判断,然后由于网络延迟等原因,库存减少操作在不同时间点执行,可能还是会导致超卖。解决方案是确保所有的库存操作都通过这个Lua脚本执行,避免在其他地方对库存进行操作。
- 库存数据类型问题:如果库存初始值设置不是数字类型,Lua脚本中
tonumber(stock)
会返回nil
,导致逻辑错误。解决方案是在初始化库存时,确保使用正确的数字类型设置库存值,例如在Python中使用r.set('product_stock', 100, ex = 3600)
设置初始库存为100且设置过期时间(如果有需求)。
- 脚本未加载问题:如果在执行