繁体   English   中英

如何在分布式系统中保持状态一致

[英]How to keep state consistent across distributed systems

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

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

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

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

这可能意味着主键,客户端和服务器生成的组合键的一半,或服务发布的令牌。 服务要么持久化实体,要么在具有该标识符的实体已经存在的情况下回复 OK 消息。

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

  • 使用客户端发布的状态更新现有实体

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

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

您可以采取一些措施来最小化客户端-服务器不同步情况的影响。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM