Apache Ignite 关于 容错(Fault Tolerance)的核心机制

发布于:2025-08-03 ⋅ 阅读:(14) ⋅ 点赞:(0)

这段内容是 Apache Ignite 关于 容错(Fault Tolerance) 的核心机制——任务失败重试(Failover)

这在分布式系统中极其重要:节点随时可能宕机、网络可能中断、任务可能出错。Ignite 的“容错”能力就是确保:即使发生故障,任务也不会丢,系统依然能完成工作。


🌐 一句话理解:什么是 Fault Tolerance(容错)?

“不怕出错,错了就换个地方重试” —— 这就是 Ignite 的容错哲学。

就像快递员送包裹:

  • 快递员突然生病了 → 公司立刻派另一个快递员接手。
  • 只要公司还在运营,你的包裹就不会丢。

Ignite 的 Failover SPI 就是这个“调度替补队员”的机制。


🔧 核心机制:Failover(故障转移)

当一个任务(Job)在某个节点上执行失败时(比如节点宕机、抛异常),Ignite 会自动尝试:

把这个任务“转移”到另一个健康的节点上重新执行。

这个过程对用户是透明的,你提交的任务最终依然会完成。

📌 关键承诺

As long as there is at least one node standing, no job is ever lost.

只要集群中还有任意一个节点活着,你的任务就不会丢失!


🎯 三种 Failover 策略(SPI 实现)

Ignite 提供了三种内置的故障转移策略:

策略 行为 适用场景
AlwaysFailoverSpi 总是尝试重试(默认) 通用,推荐大多数情况
NeverFailoverSpi 从不重试,失败就报错 调试、或任务不允许重复执行
JobStealingFailoverSpi 配合 Job Stealing 使用 启用任务窃取时必须配置

我们逐个详解。


✅ 1. AlwaysFailoverSpi(默认策略)

🧠 原理

这是最“积极”的重试策略。它会尽一切可能把失败的任务转移到其他节点执行。

🔁 重试顺序(智能转移)

Ignite 不是随便找个节点重试,而是有优先级的:

  1. 首选:转移到 从未执行过该任务任何子任务的节点

    • 目的:避免“同一个节点反复失败”
    • 更安全,减少重复失败风险
  2. 次选:如果找不到“干净”的节点,就转移到 正在执行该任务其他子任务的节点

    • 目的:至少保证任务能继续
  3. 放弃:如果所有节点都不可用或都执行过 → 放弃重试,任务失败

⚙️ 配置示例

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
    <property name="failoverSpi">
        <bean class="org.apache.ignite.spi.failover.always.AlwaysFailoverSpi">
            <!-- 最多重试5次 -->
            <property name="maximumFailoverAttempts" value="5"/>
        </bean>
    </property>
</bean>

maximumFailoverAttempts=5 表示每个失败的 job 最多尝试转移到 5 个不同的节点。


❌ 2. NeverFailoverSpi(禁止重试)

🧠 原理

  • 一旦任务失败,立刻报错,不再重试
  • 适用于:
    • 调试阶段,想快速看到错误
    • 任务具有“副作用”(如发邮件、扣款),不能重复执行
    • 强一致性要求,宁愿失败也不乱来

⚠️ 风险

  • 节点宕机 → 任务永久丢失
  • 不适合生产环境的一般计算任务

配置示例

<property name="failoverSpi">
    <bean class="org.apache.ignite.spi.failover.never.NeverFailoverSpi"/>
</property>

🦹‍♂️ 3. JobStealingFailoverSpi(配合任务窃取使用)

🧠 为什么需要它?

还记得前面讲的 Job Stealing(任务窃取) 吗?

  • Job Stealing 是“健康节点主动去偷别人队列里的任务”
  • 但这涉及到“任务从一个节点转移到另一个节点”
  • 这种“转移”本质上就是一种 Failover(故障转移)

所以,只要你启用了 Job Stealing,就必须配置 JobStealingFailoverSpi,否则无法完成任务转移。

🔗 与 Collision SPI 的关系

<property name="collisionSpi">
    <bean class="org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi">
        ...
    </bean>
</property>

<property name="failoverSpi">
    <bean class="org.apache.ignite.spi.failover.jobstealing.JobStealingFailoverSpi"/>
</property>

✅ 两者必须配套使用

  • JobStealingCollisionSpi:决定“什么时候可以偷”
  • JobStealingFailoverSpi:支持“偷成功后如何执行”

🔄 Failover 与 MapReduce 的关系

还记得 ComputeTask.result() 方法吗?

@Override
public ComputeJobResultPolicy result(ComputeJobResult res, List<ComputeJobResult> rcvd) {
    if (res.getException() != null)
        return ComputeJobResultPolicy.FAILOVER; // 手动触发重试
    return ComputeJobResultPolicy.WAIT;
}

这里返回 FAILOVER,其实就是在调用 Failover SPI

也就是说:

触发方式 说明
节点宕机 自动触发 Failover(由 SPI 处理)
任务抛异常 可通过 result() 方法手动返回 FAILOVER 触发
Job Stealing 通过 JobStealingFailoverSpi 实现任务转移

🛡️ 容错流程图(简化版)

提交任务
   ↓
分发到 Node-A 执行
   ↓
Node-A 宕机 或 任务抛异常
   ↓
Failover SPI 被触发
   ↓
查找可用的替代节点(优先选“没执行过”的)
   ↓
任务转移到 Node-B 重新执行
   ↓
成功 → 返回结果
失败 → 继续尝试,直到达到最大重试次数

✅ 实际建议

场景 推荐 Failover 策略
普通计算任务(如统计、分析) AlwaysFailoverSpi(默认,推荐)
任务有副作用(如写数据库、发消息) ⚠️ 谨慎使用 Failover,或用 NeverFailoverSpi + 外部重试机制
启用了 Job Stealing ✅ 必须用 JobStealingFailoverSpi
调试阶段 可临时用 NeverFailoverSpi 快速定位错误

🧠 总结:Fault Tolerance 的本质

机制 类比
AlwaysFailoverSpi “别放弃!换个人继续干!”
NeverFailoverSpi “要么一次成功,要么彻底失败”
JobStealingFailoverSpi “你忙不过来?我帮你抢活干,还得合法交接!”

最终结论

Ignite 的容错不是“被动等待恢复”,而是一套主动调度 + 智能转移 + 可配置策略的完整体系。

它和 负载均衡任务调度 紧密配合,共同保障了分布式计算的:

  • 高可用性(High Availability)
  • 高可靠性(Reliability)
  • 弹性伸缩能力(Resilience)

💡 小贴士:
AlwaysFailoverSpi + RoundRobinLoadBalancingSpi 是生产环境最常见的组合,简单、稳定、高效。