Apache Ignite 关于 **负载均衡(Load Balancing)** 的详细介绍
这段内容是 Apache Ignite 关于 负载均衡(Load Balancing) 的详细介绍。这是分布式系统中非常关键的一个机制,决定了任务如何在集群节点之间分配。
我来用通俗易懂的语言 + 类比 + 图解思维,帮你彻底理解 Ignite 的负载均衡机制。
🌐 一句话理解:什么是负载均衡?
负载均衡就是“公平地把工作分给所有人干”,避免有人累死、有人闲死。
就像一个项目经理要把 10 个任务分给 5 个员工:
- 如果全给一个人做 → 他累垮了,其他人没事干。
- 如果每人分 2 个 → 工作均衡,效率最高。
Ignite 的负载均衡就是这个“智能分配员”。
🔧 Ignite 负载均衡的三大核心机制
机制 | 作用 |
---|---|
1. Round-Robin(轮询) | 默认方式,像发牌一样轮流分配任务 |
2. Weighted Random(加权随机) | 强的机器多干活,弱的少干点 |
3. Job Stealing(任务窃取) | 忙不过来时,别人主动帮你抢活干 |
下面我们逐个讲解。
🎯 一、Round-Robin 轮询负载均衡(默认)
✅ 原理
像发扑克牌一样,按顺序一个接一个地把任务分给节点。
例如有 3 个节点 A、B、C,要执行 6 个任务:
任务1 → A
任务2 → B
任务3 → C
任务4 → A
任务5 → B
任务6 → C
✅ 这是最简单、最公平的分配方式。
⚙️ 两种模式
模式 | 特点 | 适用场景 |
---|---|---|
Global Mode(全局轮询) | 所有任务共享一个“发牌顺序” | 默认,适合大多数情况 |
Per-Task Mode(每任务轮询) | 每个任务从随机起点开始轮询 | 保证每个任务都能均匀分布到所有节点 |
🔍 区别举例:
假设集群有 A、B、C 三个节点。
任务 | Global Mode 分配结果 |
---|---|
Task1 的 job1 | A |
Task1 的 job2 | B |
Task2 的 job1 | C |
Task2 的 job2 | A |
任务 | Per-Task Mode 分配结果 |
---|---|
Task1 开始随机选 B → | job1→B, job2→C, job3→A |
Task2 开始随机选 A → | job1→A, job2→B, job3→C |
✅ Per-Task 的好处:即使多个任务并发执行,也能确保每个任务的 jobs 尽量均匀分布。
🛠️ 配置方式(XML)
<bean class="org.apache.ignite.configuration.IgniteConfiguration"><property name="loadBalancingSpi"><bean class="org.apache.ignite.spi.loadbalancing.roundrobin.RoundRobinLoadBalancingSpi"><property name="perTask" value="true"/> <!-- 启用 per-task 模式 --></bean></property><!-- per-task 模式需要开启这些事件 --><property name="includeEventTypes"><list><util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FINISHED"/><util:constant static-field="org.apache.ignite.events.EventType.EVT_TASK_FAILED"/><util:constant static-field="org.apache.ignite.events.EventType.EVT_JOB_MAPPED"/></list></property>
</bean>
🏋️ 二、Weighted Random 加权随机负载均衡
✅ 原理
不是完全随机,而是根据“权重”来决定谁更可能被选中。
💡 权重越高 → 越容易被分配任务。
举个例子:
节点 | 配置 | 权重 | 分配概率 |
---|---|---|---|
Node-A | 16核 CPU,64GB内存 | 20 | 50% |
Node-B | 8核 CPU,32GB内存 | 10 | 25% |
Node-C | 8核 CPU,32GB内存 | 10 | 25% |
总权重 = 20+10+10 = 40
Node-A 概率 = 20/40 = 50%
🛠️ 配置方式
<bean class="org.apache.ignite.configuration.IgniteConfiguration"><property name="loadBalancingSpi"><bean class="org.apache.ignite.spi.loadbalancing.weightedrandom.WeightedRandomLoadBalancingSpi"><property name="useWeights" value="true"/><property name="nodeWeight" value="10"/> <!-- 当前节点的权重 --></bean></property>
</bean>
✅ 你可以为不同硬件配置的服务器设置不同的
nodeWeight
,实现“能者多劳”。
🦹♂️ 三、Job Stealing 任务窃取(高级功能)
这才是真正的“智能负载均衡”!
❓ 问题背景
传统负载均衡是“提交时决定谁干”(early balancing),但可能出现:
- 某个节点突然变慢(GC、IO阻塞)
- 某些任务特别耗时
- 导致任务堆积,整体变慢
✅ 解决方案:Job Stealing
允许空闲节点“偷走”别人队列里还没开始的任务,自己去执行。
📌 这是一种“事后调整”机制,也叫 Late Load Balancing(延迟负载均衡)。
🔄 工作流程:
- 所有任务最初按 Round-Robin 分配。
- 系统监控每个节点的负载。
- 如果发现:
- A 节点:等待中的任务太多(wait queue 很长)
- B 节点:很空闲
- → B 节点主动向 A 请求:“你那有几个任务还没开始吧?给我两个我帮你做!”
- A 把任务“转让”给 B,B 开始执行。
✅ 就像办公室里:小李忙得焦头烂额,小王做完了自己的事,主动说:“你那边还有活吗?我帮你干点。”
🛠️ 配置方式
<bean class="org.apache.ignite.configuration.IgniteConfiguration"><!-- 必须配置对应的 Failover SPI --><property name="failoverSpi"><bean class="org.apache.ignite.spi.failover.jobstealing.JobStealingFailoverSpi"/></property><!-- 启用 Job Stealing --><property name="collisionSpi"><bean class="org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi"><property name="activeJobsThreshold" value="50"/> <!-- 活跃任务阈值 --><property name="waitJobsThreshold" value="0"/> <!-- 等待任务超过0个就可被偷 --><property name="messageExpireTime" value="1000"/> <!-- 消息过期时间 --><property name="maximumStealingAttempts" value="10"/> <!-- 最大尝试次数 --><property name="stealingEnabled" value="true"/> <!-- 启用窃取 --><property name="stealingAttributes"><map><entry key="node.segment" value="foobar"/> <!-- 只在相同segment内窃取 --></map></property></bean></property>
</bean>
⚠️ 注意事项
- 不是所有任务都能被“偷”:只有还没开始执行的任务(在等待队列中)才能被转移。
- 需要 Failover SPI 配合:因为任务转移涉及故障恢复逻辑。
- 增加网络开销:节点之间要频繁通信判断负载。
📊 三种机制对比
特性 | Round-Robin | Weighted Random | Job Stealing |
---|---|---|---|
分配时机 | 提交时决定(Early) | 提交时决定(Early) | 执行前动态调整(Late) |
公平性 | 高 | 中(按权重) | 非常高(动态适应) |
复杂度 | 低 | 中 | 高 |
是否需要额外 SPI | 否 | 否 | 是(Collision + Failover) |
适合场景 | 均匀负载 | 异构集群 | 动态负载变化大 |
🚫 什么时候不启用负载均衡?
文档提到:
Load balancing does not apply to colocated computations.
意思是:如果你的任务和数据在同一个节点上(Colocation),就不需要负载均衡。
比如:
- 你要查 key=123 的数据
- 数据在 Node-A 上
- 那么任务必须发送到 Node-A 执行(本地计算)
- 不能为了“负载均衡”而发到 Node-B,那样反而要远程取数据,更慢!
📌 所以:数据局部性(Data Locality)优先于负载均衡。
✅ 实际建议
场景 | 推荐配置 |
---|---|
普通集群,硬件相同 | 默认 Round-Robin(Global Mode) |
硬件差异大(有的强有的弱) | Weighted Random + 设置 nodeWeight |
任务执行时间差异大,常有“长尾任务” | 启用 Job Stealing |
强调任务顺序或一致性 | 可关闭负载均衡,手动指定节点 |
🧠 总结:负载均衡的本质
机制 | 类比 |
---|---|
Round-Robin | 发牌员按顺序发牌 |
Weighted Random | 给能力强的人发更多牌 |
Job Stealing | 发完牌后,发现有人手忙脚乱,旁边的人说:“我帮你出几张!” |
✅ 最终结论:
Ignite 的负载均衡不是“一种”算法,而是一套多层次的智能调度体系:
- 第一层:提交任务时,用 Round-Robin 或 Weighted Random 初步分配;
- 第二层:运行时监控,用 Job Stealing 动态纠偏;
- 第三层:遇到失败,用 Failover 重新分配。
这三者结合,才能真正实现“高效、稳定、自适应”的分布式计算。