毕竟判断和绑定座位(或者下单)非原子性,为了降低锁的粒度,可以将判断和绑定座位锁在一个事务里。集群:Redisson
- Key为xx_座位号,过期时间为随机1-5s(用setex的命令,该命令是key和过期时间是原子性的)
- 每次先Redis中判断该key存在不存在,如果存在,要么阻塞,要么就返回给用户,座位已被选择。
- 如果不存在,先上锁,然后再判断和绑定座位(或者下单)。其实这里有个隐藏的问题。如果绑定座位非常耗时,超过了过期时间1-5s,就凉凉了。其实这里设置过期时间,就是防止一直因为某种原因阻塞而不释放锁
- 前三步,少了个签证value,如果不设置,那么当锁过期了,业务逻辑才走完,准备删除的时候,B客户端获取到了该锁,但是A把B的key锁删除了,然而B还不知道。
- 因此,要解决这个问题,可以设置value签证,结束的时候判断一次,该value是不是自己的value,这样就不会误删。
首先有这样的问题:
- 客户端 A 从 Master 上获取锁。
- 在锁未被复制到某 Slave 节点的时候,Master 节点 Down 掉了。
- 某 Slave 节点成为新的 Master。
- 客户端 B 可从新 Master 上获取锁。
假设有5个实例
- 比如过期时间为TTL:10min
- 记录当前时间:比如T1 = 12:00
- 客户端分别向5个实例获取锁,比如申请锁的时间依次为:12:01...12:05,最后获取实例的锁为T2:12:05(获取锁的超时时间要远远小于过期时间,防止死等。)
- 如果获取锁的实例大于3个(过半机制),那么就相当于获取到锁了,该锁的真正的有效时间为TTL-(T2-T1) = 5min
- 如果客户端由于某些原因获取锁失败,便会开始解锁所有redis实例;因为可能已经获取了小于3个锁,必须释放,否则影响其他client获取锁