微服务设计 - 原则

围绕业务概念建模

原文:经验表明,围绕业务的限界上下文定义的接口,比围绕技术概念定义的接口更加稳定。针对系统如何工作这个领域进行建模,不仅可以帮助我们形成更稳定的接口,也能确保我们能够更好地反映业务流程的变化。使用限界上下文来定义可能的领域边界。

这个原则关于微服务如何确认边界,主张以业务而非技术作为划分基准。缘由我有不同的理解。在互联网涉及的业务中,很大一部分都是原来有的,互联网使它更加简单。例如仓储系统,现实中仓储不是随着互联网的出现而发展的,它拥有悠久的例子,古代的粮仓也是呀。而我们设计服务最佳的方式,将现实中映射过来,当然也需要结合网络优点适当调整。

接受自动化文化

原文:微服务引入了很多复杂性,其中的关键部分是,我们不得不管理大量的服务。解决这个问题的一个关键方法是,拥抱自动化文化。前期花费一定的成本,构建支持微服务的工具是很有意义的。自动化测试必不可少,因为相比单块系统,确保我们大量的服务能正常工作是一个更复杂的过程。调用一个统一的命令行,以相同的方式把系统部署到各个环境是一个很有用的实践,这也是采用持续交付对每次提交后的产品质量进行快速反馈的一个关键部分。

请考虑使用环境定义来帮助你明确不同环境间的差异,但同时保持使用统一的方式进行部署的能力。考虑创建自定义镜像来加快部署,并且创建全自动化不可变服务器,这会更容易定位系统本身的问题。

自动化是微服务基础之一,是很关键的部分,如果无法做到足够简单,那么迟早会迎来崩盘。

隐藏内部实现细节

原文:为了使一个服务独立于其他服务,最大化独自演化的能力,隐藏实现细节至关重要。限界上下文建模在这方面可以提供帮助,因为它可以帮助我们关注哪些模型应该共享,哪些应该隐藏。服务还应该隐藏它们的数据库,以避免陷入数据库耦合,这在传统的面向服务的架构中也是最常见的一种耦合类型。使用数据泵(data pump)或事件数据泵(event data pump),将跨多个服务的数据整合到一起,以实现报表的功能。

在可能的情况下,尽量选择与技术无关的 API,这能让你自由地选择使用不同的技术栈。请考虑使用 REST,它将内部和外部的实现细节分离方式规范化,即使是使用 RPC,你仍然可以采用这些想法。

一句话,除边界外,其它都独自完成。

让一切都去中心化

原文:为了最大化微服务能带来的自治性,我们需要持续寻找机会,给拥有服务的团队委派决策和控制权。在这个过程初期,只要有可能,就尝试使用资源自助服务,允许人们按需部署软件,使开发和测试尽可能简单,并且避免让独立的团队来做这些事。

在这个旅程中,确保团队保持对服务的所有权是重要的一步,理想情况下,甚至可以让团队自己决定什么时候让那些更改上线。使用内部开源模式,确保人们可以更改其他团队拥有的服务,不过请注意,实现这种模式需要很多的工作量。让团队与组织保持一致,从而使康威定律起作用,并帮助正在构建面向业务服务的团队,让他们成为其构建的业务领域的专家。一些全局的引导是必要的,尝试使用共同治理模型,使团队的每个成员共同对系统技术愿景的演化负责。

像企业服务总线或服务编配系统这样的方案,会导致业务逻辑的中心化和哑服务,应该避免使用它们。使用协同来代替编排或哑中间件,使用智能端点(smart endpoint)确保相关的逻辑和数据,在服务限界内能保持服务的内聚性。

除了组织架构外,微服务设计也需要尽量避免中心出现。中心点一般而言,会成为未来性能的瓶颈点,比如在单体应用扩展常见的通过redis来session共享,如果将它应用在微服务中会怎样?但中心不可能完全避免,微服务本身的服务注册中心也是中心点之一,但它遇到瓶颈可能要成千上万微服务时,所以不是特别大的公司都可暂且不考虑。

可独立部署

原文:我们应当始终努力确保微服务可以独立部署。甚至当需要做不兼容更改时,我们也应该同时提供新旧两个版本,允许消费者慢慢迁移到新版本。这能够帮助我们加快新功能的发布速度。拥有这些微服务的团队,也能够越来越具有自治性,因为他们不需要在部署过程中不断地做编配。当使用基于 RPC 的集成时,避免使用像 Java RMI 提供的那种使用生成的桩代码,紧密绑定客户端 / 服务器的技术。

通过采用单服务单主机模式,可以减少部署一个服务引发的副作用,比如影响另一个完全不相干的服务。请考虑使用蓝 / 绿部署或金丝雀部署技术,区分部署和发布,降低发布出错的风险。使用消费者驱动的契约测试,在破坏性的更改发生前捕获它们。

请记住,你可以更改单个服务,然后把它部署到生产环境,无需联动地部署其他任何服务,这应该是常态,而不是例外。你的消费者应该自己决定何时更新,你需要适应他们

没什么补充的。。。

隔离失败

原文:微服务架构能比单块架构更具弹性,前提是我们了解系统的故障模式,并做出相应的计划。如果我们不考虑调用下游可能会失败的事实,系统会遭受灾难性的级联故障,系统也会比以前更加脆弱。

当使用网络调用时,不要像使用本地调用那样处理远程调用,因为这样会隐藏不同的故障模式。所以确保使用的客户端库,没有对远程调用进行过度的抽象。

如果我们心中持有反脆弱的信条,预期在任何地方都会发生故障,这说明我们正走在正确的路上。请确保正确设置你的超时,了解何时及如何使用舱壁和断路器,来限制故障组件的连带影响。如果系统只有一部分行为不正常,要了解其对用户的影响。知道网络分区可能意味着什么,以及在特定情况下牺牲可用性或一致性是否是正确的决定。

微服务相对于单体,故障的可能性更多,但也更加容易隔离。

高度可观察

原文:我们不能依靠观察单一服务实例,或一台服务器的行为,来看系统是否运行正常。相反,我们需要从整体上看待正在发生的事情。通过注入合成事务到你的系统,模拟真实用户的行为,从而使用语义监控来查看系统是否运行正常。聚合你的日志和数据,这样当你遇到问题时,就可以深入分析原因。而当需要重现令人讨厌的问题,或仅仅查看你的系统在生产环境是如何交互时,关联标识可以帮助你跟踪系统间的调用。

日志、请求链路追踪等,为微服务保障护航。

参考

  • 《微服务设计》 Sam Newman 著 崔力强 张俊 译

这几点,说起来容易,但实施过程中,很容易走入误区,所以需要时刻谨记!