Service Fabric:在有状态服务之间更新状态时的一致性

时间:2016-04-18 15:47:20

标签: architecture microservices azure-service-fabric

让我们假设在有状态的服务中有一些这样的代码:

public async Task<bool> UpdateTheThing()
{
    using (var tx = StateManager.CreateTransaction())
    {
        await UpdateLocalState(tx);
        // point a
        bool isOK = await otherServiceProxy.UpdateServiceState();
        // point b
        if(isOK)
        {   
            await tx.CommitAsync();
        }
        return isOK;
    }
}

如果在任何地方出现不好的事情,我们都很安全 - 交易将会处理 确保数据一致。如果在a点和b点之间发生了某些事情,我们可以 或者可能没有更新其他服务的状态。

如果发生的坏事是抛出异常,我们就可以做到 恢复其他服务上的状态,但如果我们的节点在那时关闭,我们就会 永远不会恢复状态。

我知道解决此类问题的一种方法是执行以下操作:

  1. 使UpdateTheThing除了向队列添加命令之外什么也不做。
  2. 实施一些逻辑来处理队列
  3. 创建一些方法将结果(isOk)返回给调用者
  4. 使UpdateServiceState具有幂等性
  5. 如果出现问题,请让队列继续重试命令
  6. 如果问题一直发生并以某种方式告知某人存在问题,请创建一些从队列中删除命令的方法。
  7. 这是相当多的基础设施。我正在寻找更简单方法的建议。

    我注意到Service Fabric样本似乎都没有处理这个问题。

1 个答案:

答案 0 :(得分:1)

我认为您在上面描述的六步法是正确的。 Service Fabric目前不支持跨服务交易:

UserVoice request to consider that feature

我推测,要么永远不会支持,要么以某种有限的方式支持。分布式系统中的事务一致性是已知的难题。这就是为什么最终一致性是现代云架构中当前首选模式的原因:

eventual consistency description

关于这个问题的更多背景知识:

CAP theorem

links to related research

至于你的解决方案,我会说你的方法虽然不是很简单,但却是正确的方法。如上所述,UpdateTheThing()具有两个状态的隐含概念......“没有更新”和“一切都已更新”。您需要引入调用者明确知道的一些其他状态,并相应地处理:

  • 没有更新
  • 本地状态已更新
  • 更新本地状态+发送远程状态更新请求
  • 更新本地状态+调用者异步接收远程更新成功/失败的确认

您还可能希望在超过某个超时期限之后未收到远程更新确认时出现错误情况,等等。您也可能需要正式的状态进行重试行为等。

根据您的具体情况,除此之外显然还有很多复杂性。关键是你可能不希望UpdateTheThing()试图从调用者隐藏它的复杂性......调用者需要知道可能的状态并适当地处理/响应它们。

正如你所说的复杂,但这是分布式工作的本质(在云端或其他方面)。

祝你好运!