一 前言
二 业务现状:
常见的分布式锁是为了解决不同进程需要互斥地访问共享资源。常见的业务场景有“秒杀”。
对于账单来说,存在个订单多个账单的情况,而且不同的业务线字段不同,不能依靠数据库两个字段简单的唯一性索引约束。
对性能要求高,允许偶发的失败。
三 Redis实现分析
- 安全属性:互斥,不管任何时候,只有一个客户端能持有同一个锁。
- 效率属性A:不会死锁,最终一定会得到锁,就算一个持有锁的客户端宕掉或者发生网络分区。
- 效率属性B:容错,只要大多数Redis节点正常工作,客户端应该都能获取和释放锁。
- 获取锁的时候,使用setnx加锁,并使用expire命令为锁添加一个超时时间,超过该时间则自动释放锁,锁的value值为一个随机生成的UUID,通过此在释放锁的时候进行判断。
- 获取锁的时候还设置一个获取的超时时间,若超过这个时间则放弃获取锁。
- 释放锁的时候,通过UUID判断是不是该锁,若是该锁,则执行delete进行锁释放。
四 其他实现方案:
一个客户端需要做如下操作来获取锁:
1.获取当前时间(单位是毫秒)。
2.轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。
比如如果锁自动释放时间是10秒钟,那每个节点锁请求的超时时间可能是5-50毫秒的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。
3.客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁(在这里是3个),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。
4.如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。
5.如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,客户端都会到每个master节点上释放锁,即便是那些他认为没有获取成功的锁。
可靠性是更高了,要求也高,性能肯定比单节点的redis锁要差(因为要5个节点去计算)。
更可靠的是zookeeper分布式锁。
对比下:zk锁的优点是不依靠超时时间释放锁,可靠性高,缺点:性能比不上redis锁,要频繁的创建节点,删除节点。
还是要结合业务来。