在我们进行单机应用开发,涉及并发同步的时候,我们往往采用synchronized或者Lock的方式来解决多线程间的代码同步问题。但当我们的应用是分布式集群工作的情况下,那么就需要一种更加高级的锁机制,来处理种跨机器的进程之间的数据同步问题。这就是分布式锁。
redis实现:
获取锁
String result = jedis.set(key, value, "NX", "PX", expireMillis);
if (result != null && result.equalsIgnoreCase("OK")) {
flag = true;
}
setnx不能设置时间,setnx+expire不是原子性,所以直接用set
释放锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(fullKey), Collections.singletonList(value));
if (Objects.equals(UNLOCK_SUCCESS, result)) {
flag = true;
}
一般key用 “常量”+resourceId,value用requestId(可以用随机UUID)
释放锁包括查询key,比较value,然后直接del,这些操作无法保证原子性。一般用lua脚本 保证原子性。
现在一般使用redission实现redis分布式锁
https://www.cnblogs.com/moxiaotao/p/10829799.html
zookeeper实现
使用zookeeper实现分布式锁的算法流程,大致如下:
-
如果锁空间的根节点不存在,首先创建Znode根节点。这里假设为“/test/lock”。这个根节点,代表了一把分布式锁。
-
客户端如果需要占用锁,则在“/test/lock”下创建临时的且有序的子节点。
-
客户端如果需要占用锁,还需要判断,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点。如果是则认为获得锁,否则监听前一个Znode子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁;
-
获取锁后,开始处理业务流程。完成业务流程后,删除对应的子节点,完成释放锁的工作。以便后面的节点获得分布式锁。
一般使用curator框架来实现zk分布式锁。