Redis原子操作
Redis命令的原子操作
redis虽然是单线程,但是一个客户端发送的一组命令却不是原子操作。
redis自带的原子操作命令有incr {key}、decr {key}等,但是更为复杂的命令,比如先获取值,然后乘以2,最后置为新值这三步操作,有可能中间会有其他客户端的命令插入导致值已经变化,出现并发问题。
可以利用LUA脚本解决这个问题,比如常见的判断分布式锁是否为当前客户端的锁,判断成功才进行释放操作。
if redis.call('get',KEYS[1])==ARGV[1]
then
return redis.call('del',KEYS[1])
else
return 0
end
利用Redis实现的分布式锁
JDK自带的锁只锁协调一个实例中的临界区并发调用,但是分布式锁可以跨越实例上的限制。利用Redis天生单线程执行命令的特性,可以很简单的实现分布式锁。
首先获取一个随机的字符串作为锁的值,并利用原子命令set {key} {val} nx ex {time}
同时设置值和过期时间即可。需要释放锁的时候,利用前文中的LUA脚本完成锁的释放操作。
LUA脚本中判断值是为了避免这样一种情况,线程A执行时卡顿了,导致A加的锁过期自然解锁,此时线程B重新加锁后,线程A继续执行,把线程B的锁给释放掉了。通过加锁时赋予一个独一的随机值,可以避免这种情况的发生。