当前位置: 首页 > news >正文

Apache Ignite 的分布式锁Distributed Locks的介绍

以下这段内容是关于 Apache Ignite 的分布式锁(Distributed Locks) 的介绍。这是一个非常重要的功能,用于在分布式系统中协调多个节点对共享资源的并发访问

下面我们来一步步深入理解它。


🎯 一、一句话理解:什么是 Ignite 分布式锁?

Ignite 分布式锁是一个跨多个服务器节点的“互斥锁”,确保同一时间只有一个节点可以操作某个共享数据(比如缓存中的某个 key)。

✅ 类比:

  • 就像一把“全球唯一的钥匙”:只有拿到这把钥匙的线程才能修改某个数据。
  • 单机环境下用 synchronizedReentrantLock
  • 分布式环境下就需要 IgniteCache.lock() 这种跨 JVM 的锁

🧩 二、核心概念解析

1️⃣ IgniteCache.lock(key) —— 获取一个分布式锁

Lock lock = cache.lock("keyLock");
  • 这个 lock 是一个实现了 java.util.concurrent.locks.Lock 接口的对象。
  • 它不是本地锁!它是集群范围内的分布式锁
  • 当你在 Node A 上调用 lock.lock(),Node B 和 Node C 上试图对同一个 key 加锁的线程都会阻塞等待,直到 Node A 释放锁。

2️⃣ 使用方式:try-finally 确保释放

lock.lock();  // 阻塞直到获取锁
try {// 安全地操作共享资源cache.put("Hello", 11);cache.put("World", 22);
} finally {lock.unlock(); // 必须释放,否则死锁!
}

⚠️ 注意:必须放在 finally 块中释放,防止异常导致锁未释放,造成死锁或资源饥饿


3️⃣ lockAll(keys) —— 批量加锁

Collection<String> keys = Arrays.asList("key1", "key2", "key3");
Lock lock = cache.lockAll(keys);
lock.lock();
try {// 同时锁定多个 keycache.put("key1", 1);cache.put("key2", 2);cache.put("key3", 3);
} finally {lock.unlock();
}
  • 适用于需要原子性地操作多个 key 的场景。
  • 所有 key 的锁会一起获取、一起释放
  • 避免因部分加锁成功而导致的数据不一致问题。

🔐 三、为什么需要分布式锁?

在分布式系统中,多个节点可能同时访问同一份数据。例如:

场景问题解决方案
多个节点同时更新用户余额超卖、余额错乱userId 加分布式锁
多个节点争抢执行定时任务重复执行"task-refresh" 加锁
缓存双写一致性缓存和数据库不一致更新时对 key 加锁

👉 没有锁 → 数据竞争(Race Condition) → 数据错误!


⚙️ 四、Atomicity Mode:必须是 TRANSACTIONAL

CacheConfiguration cfg = new CacheConfiguration("myCache");
cfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); // 必须设置
  • Ignite 支持两种原子性模式:
    • ATOMIC:高性能,无事务支持,不能使用显式锁。
    • TRANSACTIONAL:支持事务和显式分布式锁

❌ 如果你在 ATOMIC 模式下调用 cache.lock(),会抛出异常!

✅ 所以:要用分布式锁,缓存必须配置为 TRANSACTIONAL 模式。


🔄 五、Locks vs Transactions:锁与事务的关系

这是最容易混淆的部分,原文说得很清楚:

“Explicit locks are not transactional and cannot be used from within transactions.”

我们来拆解这句话:

✅ 情况 1:显式锁 ≠ 事务锁

类型显式锁 (cache.lock())事务中的锁
是否可嵌套在事务中❌ 不可以✅ 可以
是否自动提交/回滚❌ 不支持回滚✅ 支持
如何获取手动 lock.lock()自动由事务管理器获取
使用场景非事务性临界区事务性数据操作

🔴 错误写法(会抛异常):

IgniteTransactions txs = ignite.transactions();
try (Transaction tx = txs.txStart()) {Lock lock = cache.lock("key");lock.lock(); // ❌ 抛异常!不能在事务中使用显式锁cache.put("key", 1);tx.commit();
}

✅ 情况 2:想要“事务中的显式锁”?用 PESSIMISTIC 事务

如果你希望在事务中也能“显式控制锁”的行为(比如立即失败而不是等待),应该使用:

try (Transaction tx = ignite.transactions().txStart(TransactionConcurrency.PESSIMISTIC,  // 悲观并发控制TransactionIsolation.REPEATABLE_READ)) {// 第一次读/写就会自动加锁Integer val = cache.get("key");cache.put("key", val + 1);tx.commit(); // 提交时释放锁
}
悲观事务(PESSIMISTIC)的特点:
  • get()put()立即尝试获取分布式锁
  • 如果锁被占用,可以选择超时失败(避免无限等待)。
  • 行为类似于“显式锁 + 事务”的组合效果。

🧪 六、完整示例:银行转账(防止并发超支)

IgniteCache<String, Integer> cache = ignite.cache("accounts");// 模拟两个账户
String from = "account-A";
String to = "account-B";// 对两个账户加锁(避免死锁:按字母顺序加锁)
List<String> sortedKeys = Arrays.asList(from, to).stream().sorted().collect(Collectors.toList());
Lock lock = cache.lockAll(sortedKeys);lock.lock();
try {Integer balanceA = cache.get(from);Integer balanceB = cache.get(to);if (balanceA >= 100) {cache.put(from, balanceA - 100);cache.put(to, balanceB + 100);System.out.println("转账成功");} else {System.out.println("余额不足");}
} finally {lock.unlock(); // 释放所有锁
}

✅ 保证了即使多个节点同时发起转账,也不会出现“超卖”。


⚠️ 七、注意事项 & 最佳实践

项目建议
🔒 锁粒度尽量小(比如按用户 ID 锁),避免锁整个缓存
⏱️ 锁持有时间越短越好,不要在锁内做耗时操作(如网络请求)
💥 异常处理一定要 finally unlock(),建议用 try-with-resources(如果自定义封装)
🪢 死锁风险多 key 加锁时,按固定顺序加锁(如排序)
📈 性能影响分布式锁涉及网络通信,频繁使用会影响性能
🔄 替代方案考虑使用 EntryProcessorinvoke())进行原子更新,避免手动加锁

✅ 总结:一句话掌握精髓

Ignite 的 cache.lock(key) 提供了一种简单、直观的跨节点互斥机制,让你像使用本地 ReentrantLock 一样保护分布式共享资源,但前提是缓存必须是 TRANSACTIONAL 模式,并且不能与事务混用。


🔄 对比总结表

功能cache.lock() 显式锁悲观事务(PESSIMISTIC)EntryProcessor(invoke)
是否跨节点✅ 是✅ 是✅ 是
是否支持事务❌ 否✅ 是✅ 是(单 key)
是否自动加锁✅ 手动✅ 自动✅ 自动
适用场景非事务临界区多 key 事务操作单 key 原子更新
性能中等中等高(推荐)

如果你想实现高并发下的安全更新,优先考虑 EntryProcessor;如果逻辑复杂必须加锁,再用 lock() 或 悲观事务。

如有具体业务场景(如库存扣减、计数器、任务调度),欢迎继续提问,我可以给出更具体的代码建议!

http://www.dtcms.com/a/304199.html

相关文章:

  • VLA--Gemini Robotics On-Device: 将AI带到本地机器人设备上
  • SQL 怎么学?
  • 小程序发票合并功能升级!发票夹直接选,操作更便捷
  • Kafka——消费者组重平衡全流程解析
  • idea运行tomcat日志乱码问题
  • Vue El 基础
  • 考古学家 - 华为OD统一考试(JavaScript 题解)
  • npm : 无法加载文件 D:\Nodejs\node_global\npm.ps1,因为在此系统上禁止运行脚本
  • 复现cacti的RCE(CVE-2022-46169)
  • EM储能网关ZWS智慧储能云应用(17) — 动环监控
  • 鲸鱼小说分销系统v1.0.0公测版更新发布-完成了小说整体基础以及完整分销和数据看板
  • 应广MTP单片机在线烧录技巧
  • 嵌入式学习日志————TIM定时中断之定时器定时中断
  • git使用lfs解决大文件上传限制
  • 【PHP】Swoole:CentOS安装Composer+Hyperf
  • 【C++算法】76.优先级队列_前 K 个高频单词
  • 引领新一代 Web3 金融类应用开发,全景式探析 Injective 生态
  • 乳腺癌病理知识
  • 网络安全的变革:深入洞察 Web3 与传统网络模型
  • 黑客哲学之学习笔记系列(一)
  • 随机森林算法原理及优缺点
  • 华为光学设计面试题
  • 频谱周期性复制
  • 数据库管理-第352期 从需求看懂Oracle RAC多租户环境的Service(20250729)
  • C++ 1.面向对象编程(OOP)框架
  • SBB指令的“生活小剧场“
  • Excel工作簿合并工具,快速查找一键整合
  • 「源力觉醒 创作者计划」_DeepseekVS文心一言
  • JavaWeb 入门:CSS 基础与实战详解(Java 开发者视角)
  • 查询mac 安装所有python 版本