【问题标题】:How to keep state consistent across distributed systems如何在分布式系统中保持状态一致
【发布时间】:2018-07-29 10:30:30
【问题描述】:

在构建分布式系统时,必须确保客户端和服务器最终以一致的视图结束它们正在操作的数据,即它们永远不会不同步。需要格外小心,因为网络不能被认为是可靠的。也就是说,在网络故障的情况下,客户端永远不知道操作是否成功,可能会决定重试调用。

考虑一个微服务,它公开了简单的 CRUD API 和无限的客户端集,由同一团队、不同团队和不同公司在内部维护。

在示例中,客户端请求创建新实体,微服务成功创建并持久化该实体,但网络失败,客户端连接超时。客户端很可能会重试,在不知情的情况下第二次持久化同一个实体。这是我想出的一种可能的解决方案:

  • 使用客户端生成的标识符来防止重复发布

这可能意味着主键,客户端和服务器生成的组合键的一半,或服务发布的令牌。如果具有该标识符的实体已经存在,则服务将保留该实体,或者回复 OK 消息。

但还有更多:如果客户端在网络故障后放弃(但实体被持久化),改变它对实体的内部视图,然后决定将其持久化到具有相同 id 的服务中。在这一点上,一般来说,静默服务是否合理:

  • 更新具有客户发布状态的现有实体

或者服务应该用一些更具体的状态代码来回答发生了什么?关键是,服务的开发者并不能真正影响客户端的设计解决方案。

那么,有哪些明智的做法可以在分布式系统中保持状态一致并避免网络和系统故障时最常见的陷阱?

【问题讨论】:

  • 我不理解用例“将现有实体分配给客户发布的实体”。你能给我更多的细节或帮助我理解吗?
  • 嗯,这只是意味着删除旧实体(如果存在),并插入新的客户发布。旧的和新的具有相同的主键。或者,服务器可以回答实体已经存在(因为它确实存在),但它的状态与客户端发布的状态不同
  • 但是服务器为什么要删除旧实体呢?为什么不让它保持这种状态,当客户端更新它时,它们会同步。
  • 是的,基本上是一样的
  • 服务器不知道客户端知道什么,所以除非客户端请求,否则它不应该做任何事情。

标签: rest web-services architecture microservices distributed-computing


【解决方案1】:

您可以采取一些措施来最大程度地减少客户端-服务器不同步情况的影响。

您可以采取的第一个措施是让客户端生成实体 ID,例如使用 GUID。这可以防止服务器在每次客户端重试 CreateEntityCommand 时生成新实体。

此外,您可以使命令处理幂等。这意味着如果服务器接收到第二个 CreateEntityCommand,它只是默默地忽略它(即它不会抛出异常)。这取决于每个用例;某些命令不能具有幂等性(如updateEntity)。

您可以做的另一件事是删除重复命令。这意味着您发送到服务器的每个命令都必须使用唯一 ID 进行标记。这也可以是 GUID。当服务器接收到一个带有它已经处理过的 ID 的命令时,它会忽略它并给出一个肯定的响应(即200),可能包括一些关于命令已经处理过的元信息。命令去重可以放在栈顶,作为一个单独的层,独立于域(即在Application layer前面)。

【讨论】:

  • 这意味着如果服务器接收到第二个 CreateEntityCommand,它只是默默地忽略它。我在这里看到一个问题,如果客户端同时改变了实体。然后两个系统都会很高兴地以不一致的状态结束。
  • 不一定。例如,即使客户端随后发送了UpdateEntity 命令,实体仍处于created 状态。第二个CreateEntityCommand 并没有改变这个事实,这意味着它可以是幂等的。
猜你喜欢
  • 1970-01-01
  • 2019-12-09
  • 2012-08-30
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
  • 2013-07-04
  • 2013-06-10
  • 1970-01-01
相关资源
最近更新 更多