在构建分布式系统时,必须确保客户端和服务器最终能够以一致的方式查看它们正在运行的数据,即它们永远不会失去同步。需要格外小心,因为网络不能被认为是可靠的。换句话说,在网络故障的情况下,客户端永远不知道操作是否成功,并且可能决定重试该呼叫。
考虑一个微服务,它暴露了简单的CRUD API,以及由同一团队,不同团队和不同公司在内部维护的无限客户端集。
在该示例中,客户端请求创建新实体,微服务成功创建并保留,但网络出现故障并且客户端连接超时。客户端很可能会重新尝试,不知不觉地第二次持续存在同一个实体。以下是我提出的一个可能的解决方案:
这可能意味着主键,客户端和服务器生成的复合键的一半,或服务发出的令牌。如果具有该标识符的实体已存在,则服务将持久保存该实体,或使用OK消息进行回复。
但是还有更多内容:如果客户端在网络故障后放弃(但实体得到了持久性),会改变它的实体内部视图,然后决定将其保留在具有相同功能的服务中,该怎么办? ID。在这一点上,一般来说,服务只是默默地是合理的:
或者该服务是否应该使用更具体的状态代码来回答发生的事情?关键是,该服务的开发人员无法真正影响客户端设计解决方案。
那么,在网络和系统故障的情况下,保持状态在分布式系统中保持一致并避免最常见陷阱的一些合理做法是什么?
答案 0 :(得分:2)
您可以采取一些措施来最大限度地减少客户端 - 服务器不同步情况的影响。
您可以采取的第一个措施是让客户端生成实体ID ,例如使用GUID。这可以防止服务器在每次客户端重试CreateEntityCommand时生成新实体。
此外,您可以使命令处理幂等。这意味着如果服务器收到第二个CreateEntityCommand,它只是默默地忽略它(即它不会抛出异常)。这取决于每个用例;某些命令不能成为幂等的(如updateEntity
)。
您可以做的另一件事是重复删除命令。这意味着您发送到服务器的每个命令都必须使用唯一ID进行标记。这也可以是GUID。当服务器收到一个具有已经处理过的ID的命令时,它会忽略它并给出肯定响应(即200
),可能包括一些关于命令已被处理的元信息。重复数据删除命令可以放在堆栈顶部,作为一个单独的层,独立于域(即Application layer
之前)。