本文概述了分布式锁在微服务环境中的必要性及其实现方式,特别强调了苍穹平台使用zookeeper实现的两种模式:性能模式和稳定模式。性能模式在会话断开时锁自动消失,适用于能处理锁丢失的场景;稳定模式则在微服务节点不在注册中心时才失效,保证了锁的安全性。同时介绍了分布式锁接口`kd.bos.dlock.DLock`的主要方法,包括锁的申请、释放和模式切换,以及通过Monitor查看锁信息的方法。
1. 分布式锁概述
如果需要独占某个资源,在分布式环境下(微服务),不能用JDK的锁,需要使用分布式锁服务。
苍穹平台分布式锁使用zookeeper实现,有两种模式:
1) 性能模式:使用临时点存储锁信息,zk会话断开,锁自动消失。
2) 稳定模式:使用持久化节点存储锁信息,zk断开锁不消失,只有同时在微服务节点不在注册中心了,锁才会失效(在下次被申请时判断解锁)。
默认启用稳定模式(通过系统参数DLock.performance=false配置),在代码中,申请锁前可指定模式。
性能模式用于能自行处理可能存在锁丢失的情况。
性能模式下zk会话断开(如网络原因)锁自动消失,而微服务节点可能还在运行中,已获取锁的代码也可能还在跑,故存在锁同时被申请使用的风险。
稳定模式则无此问题,已获得锁在异常宕机后,下个锁申请者,只需等待宕机的微服务节点在注册中心消失,即可获得(解除旧锁),最快秒级,最迟约10分钟,依赖于注册中心的节点列表更新。
2. 分布式锁接口:kd.bos.dlock.DLock
public interface DLock extends AutoCloseable{ /** * 获取锁,一直等待,直到获取。 */ void lock(); /** * 尝试获取锁,不等待,获取到返回true(无锁竞争的情况下必为true),否则返回false。 */ boolean tryLock(); /** * 尝试获取锁,在timeoutMillis毫秒内获取到,返回true,否则返回false。 */ boolean tryLock(long timeoutMillis); /** * 释放锁 */ void unlock(); /** * 等同unlock */ void close(); /** * 快速模式 */ DLock fastMode(); /** * 稳定模式 */ DLock stableMode(); ////////////////////////////////////////////////////////////////////////////////////// /** * 分布式锁对象,不可重入。 */ static DLock create(String key); static DLock create(String key, String desc); /** * 分布式锁对象,可重入(仅在本jvm范围内)。 */ static DLock createReentrant(String key); static DLock createReentrant(String key, String desc); /** * 获取所有锁信息 */ static Map<String, DLockInfo> getAllLockInfo(); /** * 获取key对应的锁信息,不存在则返回null。 */ static DLockInfo getLockInfo(String key); }
3. 简单例子
tryLock
DLock lock = DLock.create("bos/test_key", "测试锁信息"); // lock.fastMode(); //转换未性能模式,须在申请(tryLock/lock)前设置。 // 未获得锁则返回false if (lock.tryLock()) { try { // 在这里处理业务逻辑... } finally { // 解锁 lock.unlock(); } }
lock
// lock(): 一直等待直到获得锁 try(DLock lock = DLock.create("bos/test_key", "测试锁信息").lock()) { // 在这里处理业务逻辑... }
获取锁信息
DLockInfo lockInfo = DLock.getLockInfo("bos/test_key");
4.Monitor查看锁信息
在monitor中,点击任一节点的“分布式锁”,即可查看到集群内所有分布式锁信息,列出的锁可操作unlock和clear:
1)分布式锁的配置信息
DLock.type=zookeeper DLock.performance=false
2)循环列出租户账套信息及其锁信息
tenantId=tenant_devcorelib_dev, accountName=devcorelib_dev_oracle, accountNumber=devcorelib_dev_oracle, accountId=201912161501544917, count=1
{ key: bos/test_key, desc: 测试锁信息, waitingLocks: 0, createTime: 2020-11-17 19:48:16.758, instance: 172.19.114.96, createThread: Thread[xxx/traceId:ea1185e16ef8700e/time:1605613684643,5,main], owner: 1710f598ce78d81, pttl: 0, storePath:/devcorelib_dev/runtime/__dlock__201912161501544917/ }
waitingLocks:表示该锁的申请者等待个数
instance:当前拥有锁的微服务节点ip
createThread:拥有锁的线程,结合monitor的线程堆栈可查到什么代码在调用。
owner:使用的zk连接ID
pttl: redis版的锁剩余时间,zk版无意义
storePath:锁在zk中的存储路径,含集群、账套信息(按集群、账套隔离)。