MST

星途 面试题库

面试题:Redis分布式锁在电商库存管理中等场景下的实现细节

在电商库存管理中,当面临每秒几百次库存扣减操作时,如何基于Redis实现分布式锁来保证库存数据的一致性?请阐述具体的实现步骤和涉及的Redis命令。
46.5万 热度难度
数据库Redis

知识考点

AI 面试

面试题答案

一键面试

实现步骤

  1. 获取锁
    • 使用 SETNX(SET if Not eXists)命令尝试设置一个特定的键值对来表示锁。例如,以库存操作的唯一标识(如商品ID)作为键,一个随机生成的字符串作为值。如果设置成功(返回1),表示获取到锁;如果设置失败(返回0),表示锁已被其他进程持有。
  2. 执行库存扣减操作
    • 在获取到锁之后,从Redis中获取当前库存值,然后进行扣减操作,再将扣减后的库存值写回Redis。这一系列操作需要保证原子性,可以使用Lua脚本来实现。
  3. 释放锁
    • 在完成库存扣减操作后,使用 DEL 命令删除表示锁的键,释放锁资源。为了避免误删其他进程持有的锁,在删除之前需要验证锁的值是否与获取锁时设置的值一致,同样可以通过Lua脚本实现。

涉及的Redis命令

  1. SETNX
    • 语法:SETNX key value
    • 作用:只有在键 key 不存在时,才设置键的值为 value。如果设置成功返回1,否则返回0。用于尝试获取分布式锁。
  2. GET
    • 语法:GET key
    • 作用:获取指定键 key 的值。用于获取当前库存值。
  3. SET
    • 语法:SET key value [EX seconds] [PX milliseconds] [NX|XX]
    • 作用:设置键 key 的值为 value,可以设置过期时间(EX 为秒,PX 为毫秒),NX 表示只有键不存在时才设置,XX 表示只有键存在时才设置。用于更新库存值。
  4. DEL
    • 语法:DEL key [key ...]
    • 作用:删除指定的键及其值。用于释放分布式锁。
  5. EVAL
    • 语法:EVAL script numkeys key [key ...] arg [arg ...]
    • 作用:在Redis服务器端执行Lua脚本 scriptnumkeys 表示键参数的个数,后面跟着键参数和其他参数。用于实现库存扣减和锁释放的原子性操作。

示例Lua脚本(以库存扣减和锁释放为例):

-- 获取锁的值
local lockValue = redis.call('GET', KEYS[1])
-- 判断锁的值是否与预期一致
if lockValue == ARGV[1] then
    -- 获取当前库存
    local stock = redis.call('GET', KEYS[2])
    -- 扣减库存
    stock = stock - 1
    -- 更新库存
    redis.call('SET', KEYS[2], stock)
    -- 释放锁
    redis.call('DEL', KEYS[1])
    return stock
else
    return -1 -- 表示未获取到锁或锁已过期
end

在实际应用中,使用 EVAL 命令执行上述Lua脚本,将锁的键和库存的键作为 KEYS 参数,获取锁时设置的值作为 ARGV 参数传入。