我希望您能提供一些关于如何处理微服务间数据依赖和关系的不同解决方案的反馈。
简要说明:有一个银行服务和一个账户服务。账户服务保存账户并始终使用bankId与银行连接。
困境在于如何处理和验证此关系和bankId,以及每个决策所带来的利弊。
选项1:
完全忽略验证。对账户进行POST / PATCH操作将永远不会验证给定的BankId是否存在。
优点
- 服务互相独立,它们之间没有硬性依赖关系,如果一个服务停止工作,另一个服务不会停止工作。(这是一个重大的优点)
缺点
- 如果BankId不正确,则无法访问账户。
- 报告服务和/或任何读取器必须考虑缺失或不正确的银行,并呈现其具有的任何数据而不崩溃。
反思
服务完全解耦,这将有利于性能、正常运行时间和复杂度。所有读取器和应用程序都需要“响应式”,并能够处理交叉服务关系“断裂”的情况。
选项2:
始终使用同步REST调用进行验证。如果BankId不存在或BankService无法响应或已损坏,则对账户进行POST / PATCH操作将失败。
优点
- 100%数据完整性。
- 读取器不需要处理和期望破碎的关系。
缺点
- 服务之间的依赖性过于紧密,您可以认为它们不再是真正的微服务,而是单一服务。
- 性能受到负面影响。
- 如果BankService关闭,AccountService的POST / PATCH将无法工作,但GET仍将工作。
反思
服务之间的依赖性过于紧密,这非常糟糕,这更像“旧方法”,通常我觉得这是错误的做法。在这种情况下合并服务甚至更糟,如果您开始通过合并解决问题,您可能会继续这样做,并很快以大型服务结束,从而未能实现整个微服务原则。当然,读取仍将工作,但这是一个牵强的借口。
选项3:
在AccountService中保留BankEntity的只读副本。 AccountService通过事件总线更新此副本。对POST / PATCH进行验证。
优点
- 100%数据完整性。
- 读取器不需要处理和期望破碎的关系。
- 没有可测量的负面影响。
缺点
- 复杂性增加了
- 由于事件的异步性质,我们不能假设银行只读副本已经100%更新。在创建BankEntity后快速连续POST/PATCH Account,可能会失败。
- 尽管是一个松散的依赖关系,但AccountService对其他服务的了解更多了
反思
这是最复杂的方式,读者不需要处理破裂的关系和性能/可用性问题得到解决,但是,相反你必须处理只读的Banks副本可能尚未更新并稍后再试的事实。与Option 1相比,这意味着你仍然必须以某种方式处理它,而且由于这将在各方面更加复杂,我认为这不是最有利的方法。
最终想法
总的目标是使服务之间不同步地交互,并尽可能保持数据完整性。
然而,在微服务架构中,我认为关系完整性可能只是你接受失去的这些事情之一。
我们的决定倾向于Option 1,实际上就是忽略它,任何时候需要使用它时,都必须预期并处理它可能不正确的情况。这似乎是最“微服务”解决方案,服务彼此并不真正了解,只有需要执行跨服务操作的应用程序和报告服务知道彼此。
所有服务都需要完全负责,以确保它们在任何时候都具备完全运行所需的所有数据。例如,假设AccountEntity出于某种原因需要Location来成为可用和完整的域实体,则不能指望依赖BankId,而必须将Location存储在AccountEntity上,如果更改,您可以收到事件并更新它。
简短概括 你对此有什么经验、观点和想法?你会怎样做?哪种策略会选择?