单实例分布式锁实现
应用场景
用于抢红包、抢票类似的服务,商城抢货。等场景中,对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题。
注:
如果是redis集群,每个redis master节点都是独立存储的,这种场景用单实例会有安全性问题
redis分布式锁实现思路
实现分布式锁的方式有很多,类似: 数据库(mongo)、基于分布式协调系统(ZooKeeper)、缓存(redis)
基于redis分布式锁实现,需要保证3个特性:安全性、死锁、容错
- 安全性:
一个萝卜一个坑,需要解决占位问题 - 死锁
避免用户操作为处理,锁一直存在,价格过期时间 - 容错
多节点情况下需要考虑的,只要能保证N/2+1节点可用,客户端就可以成功获取、释放锁(单实例不需要考虑,这种场景推荐redisLock依赖,开箱即用)
redis单实例实现过程
解决占位问题
对同一资源进行读写操作,避免不了的一个就是资源竞争问题,通过引入分布式锁这一概念,可以解决数据一致性问题。
方案
使用setnx 代替 set setnx key value
127.0.0.1:6379>
127.0.0.1:6379> get fg
(nil)
127.0.0.1:6379> SETNX fg 666
(integer) 1
127.0.0.1:6379> SETNX fg 777
(integer) 0
127.0.0.1:6379> get fg
"666"
解决死锁问题
为了防止用户拿到锁之后一直不处理所以设置过期时间,用户如果在一定时间内没有对这笔数据数据处理, 也会释放锁。
方案:
添加过期时间 expire key time
127.0.0.1:6379> setnx fg 666
(integer) 1
127.0.0.1:6379> expire fg 15
(integer) 1
127.0.0.1:6379> get fg
"666"
127.0.0.1:6379> ttl fg
(integer) 2
127.0.0.1:6379> get fg
(nil)
127.0.0.1:6379> ttl fg
(integer) -2
127.0.0.1:<