如何销毁Hazelcast动态分配的FencedLock?多进程场景下的方案
Hazelcast FencedLock 动态创建后的销毁策略
首先明确:FencedLock完全适用于动态按需创建的多进程场景,关键是选对销毁时机和策略,避免内存泄漏。以下是几种可行方案:
1. 自动TTL销毁(推荐)
利用Hazelcast CP锁的自动过期销毁特性,在创建锁时指定闲置超时时间,锁释放后若超过设定时间无人使用,会被集群自动销毁,无需手动干预。
修改示例代码如下:
public void updateClient(ClientId id, ClientData data) { String lockName = id.toString(); // 配置锁:释放后闲置1小时自动销毁 LockConfig lockConfig = new LockConfig(lockName) .setLockDestroyOnExpire(true) .setExpireAfter(3600, TimeUnit.SECONDS); // 加载配置并获取锁(锁不存在则自动创建) var lock = this.hz.getCPSubsystem().getLock(lockConfig); lock.lock(); try { // 更新客户端信息 } finally { lock.unlock(); } }
- 核心逻辑:
setLockDestroyOnExpire(true)开启自动销毁,setExpireAfter设置锁释放后的闲置超时时间,只有当锁处于未持有状态时才会触发计时销毁,完全不影响正常业务的锁使用。 - 优势:无需手动管理销毁逻辑,适合锁数量未知、生命周期不明确的场景。
2. 业务触发销毁(适用于有明确生命周期的资源)
如果客户端数据存在明确的删除/归档操作,可以在执行这些操作时同步销毁对应锁,确保资源及时清理。
示例代码:
public void deleteClient(ClientId id) { String lockName = id.toString(); var lock = this.hz.getCPSubsystem().getLock(lockName); // 先获取锁,避免销毁时还有并发更新操作 lock.lock(); try { // 执行客户端数据删除逻辑 // 销毁锁 lock.destroy(); } finally { lock.unlock(); } }
- 注意:必须先获取锁再销毁,防止销毁正在被使用的锁,导致后续业务报错。
3. 定期兜底清理(补充方案)
针对无法通过前两种方式覆盖的场景,可以在集群中运行定时任务,定期扫描并清理长期闲置的锁。
示例代码:
// 初始化时注册定时任务,每日凌晨清理一次闲置超7天的锁 hz.getScheduledExecutorService().scheduleAtFixedRate(() -> { CPSubsystem cpSubsystem = hz.getCPSubsystem(); // 获取集群中所有CP锁名称(需Hazelcast 4.0+版本支持) Collection<String> lockNames = cpSubsystem.getLockNames(); for (String lockName : lockNames) { FencedLock lock = cpSubsystem.getLock(lockName); // 检查锁最后一次释放时间,判断是否闲置超7天 Long lastUnlockTime = lock.getLastUnlockTime(); if (lastUnlockTime != null && System.currentTimeMillis() - lastUnlockTime > 7 * 24 * 3600 * 1000) { // 尝试非阻塞获取锁,确保锁未被使用再销毁 if (lock.tryLock(1, TimeUnit.SECONDS)) { try { lock.destroy(); } finally { lock.unlock(); } } } } }, 0, 1, TimeUnit.DAYS);
- 注意点:
- 不同Hazelcast版本获取锁列表的API可能有差异,需确认版本兼容性;
- 清理前要尝试获取锁,避免销毁正在被持有的锁。
场景适配说明
如果你的业务是极端高频创建短生命周期锁(毫秒级),FencedLock的集群同步开销可能略高,此时可以考虑基于Redis的自动过期锁实现;但如果需要强一致性的分布式锁保障,FencedLock仍是最优选择。
内容的提问来源于stack exchange,提问作者Xavier Dury
相关产品推荐
相关产品推荐

