Redis应用实践——分布式锁

应用

实现分布式锁的开始需要“占坑”, 使用setnx(set if not exists)命令,如果key存在了,其他客户端尝试set时就会报错;等到当前客户端完成任务执行del后,其他客户端方可进入。

为了避免拿到锁之后客户端挂了导致永远不能释放锁,加一个过期时间使用expire指令。

但是setnx 和 expire是两条指令不能原子执行,还是有发生死锁的风险,那怎么解决呢?在Redis 2.8中作者加入了set指令的拓展参数,set lockname true ex 5 nx , 原生支持了原子操作。

超时问题

上面的方案如果有些任务执行时间过长,那么释放了锁之后,临界区的代码还未执行完,第二个现成又拿到了锁,那么原来的的代码就不能严格的按照串行执行。所以redis分布式锁不推荐用于耗时较长的任务。

还有要避免其他线程del掉自己的锁,可以使用随机数或者uuid进行匹配,删除时先判断随机数是否一致,不一致不允许删除,但是匹配和删除也不能原子执行,所以这里可以借助lua脚本来执行。

可重入锁

java中也有可重入锁的类ReentrantLock,redis实现需要对set方法进行包装,使用ThreadLocal存放key的加锁次数。但是实际项目中最好不要使用可重入锁,可以通过业务的逻辑上调整完全避免使用可重入锁。

补充:可重入锁和不可重入锁参考

https://blog.csdn.net/rickiyeat/article/details/78314451