在redis里面实现分布式锁的思路是

setnx lock 1
expire lock 20
// 举个例子如上:设置一个标志位lock来标志是否上锁,然后对这个lock设置过期时间来防止别人无限忙等
// 问题:由于这两歩是分开的,有一个case就是lock设置完了,但是还没来得及设置过期时间,client就没了
// 这个就会导致该lock一直存在,而且别人也无法获得这个锁,也就无法触碰到业务

可实现的一个思路就是利用lua脚本来实现一个原子操作,也就是上面两歩并一步来做。ok,首先来稍微捋一下lua脚本。基本语法可以去网上搜一下,这里就不做过多的介绍了,在lua脚本里面有如下方法可以对redis-server进行类似于redis-cli的调用

redis.call("set", "name", "jackellove")
redis.call("expire", "name", 30)
redis.call(里面的形式可以和redis-cli终端下的一样)

但是这里就会有一点不方便, 如果我想实现参数从go语言传到lua脚本,然后从lua脚本的执行获得值到go ,然后我们就可以用得到的值来进行业务判断等等。另一种写法:

local key1 = KEYS[1]
local key2 = KEYS[2]

local arg1 = ARGV[1]
local arg2 = ARGV[2]

local lock = redis.call("set", key1, arg1)
redis.call("expire", key1, arg2)
return lock

这里的KEYS和ARGV就是我们在go语言那边的参数列表,其中索引是从1开始的,我这里使用 redigo/redis作为redis的操作库来演示

其中atom.lua如下所示:

local key1 = KEYS[1]
local arg1 = ARGV[1]
local arg2 = ARGV[2]

-- set a lock for redis
local Flag = redis.call("setnx", key1, arg1)
-- assume the average time of booking ticket is 30 seconds
redis.call("expire", key1, arg2)
return Flag

运行的结果可以,最后返回1表示加锁成功,然后设置了过期时间为20s,可以把这段代码加入到业务逻辑里面去实现分布式一致。