【51CTO.com快译】如果您的组织正打算采用和实施微服务,那么您一定听说过诸如:领域驱动设计(Domain-Driven Design)、事件驱动架构(Event-Driven Architecture)、核心域(Core Domain)、子域(Subdomain)、限界上下文(Bounded Context),防腐层(Anti-corruption Layer)等概念。同时,您的团队是否有能力以正确的方式,分解业务域逻辑(或称业务空间),并将其与微服务架构(或称代码空间)相映射,以便受益于微服务架构带来的优势呢?
微服务分解架构逻辑图
在本文中,我将为您总结分解微服务的十项原则与相关策略。
1.使用限界上下文和通用语言(Ubiquitous Language)来查看业务域
在进行分解之前,我们首先要做的是缩小产品所有者与开发人员之间的距离。产品所有者可能并不了解技术术语,而技术团队也可能不了解术语在解释业务中的重要性。因此,为了弥合这种“鸡同鸭讲”的差距,我们需要采取以下步骤:
- 将产品所有者聚拢到看板前,询问他们:“业务目标是什么?”、“在特定功能中有什么角色?”、“他们在定义功能时使用了哪些术语?”这些问题将有助于技术人员弄清可能引起误解的业务术语。例如“订单上下文客户”与“架构支持上下文客户”之间的区别。
- 一旦理解了容易产生歧义的术语,请结合相关功能绘制出上下文,以保证在每个上下文中,每个域实体的名称都足够清晰。
- 为每个上下文定义一种通用语言,以便业务团队和技术团队在交流时,可以使用相同的通用语言进行同步。
- 先从一个粗粒度(coarse-grained)的限界上下文开始。除非以后出现了令人信服的业务理由,否则不再细分限界上下文。
2.确定核心域并运用创新思想
核心域是那些能够为您的业务带来收益的部分。对于B2C的在线购物应用而言,其购物车模块便属于核心域。我们需要通过思考如何改进那些竞争对手所不具备的模块,以充分了解自己的核心模块。任何自动化、或创新都会增加您的营收与优势,因此你需要针对核心域进行重点研发和投入,以保持自身竞争优势。
3.对通用域进行成本优化
通用域是每个企业所共有的部分。通常,不同的第三方会针对商业化市场,提供通用的解决方案。例如,各个业务配套的通知模块,或是广告推送模块。为了避免重复“造轮子”,我们需要以成本优化的方式创建通用域,或是以相对便宜的价格,采用第三方解决方案。
4.适当考虑支持域
通常,核心域需要支持域的协助,来丰富自身。当然在某些情况下,支持域不但可以带来收益,也可能在将来转换为核心域。例如,在前面的例子中,相比购物车域,库存管理属于支持域。那么,通过对支持领域进行投入,也能够产生营收。例如,为了降低运输的成本,我们既可以选择增加库存的站点,又可以运用算法,识别客户订单最近的库存位置。
5.引入防腐层
防腐层是微服务设计中不可或缺的部分,它可以保护微服务免受外界变化的影响。例如,在实际情况下,一些旧的项目会受到大型主机环境、或依赖某种语言的构建限制。由于它们是微服务输入数据的重要来源,因此它们不但需要与微服务架构并存,甚至阻碍对系统进行分解。因此,在旧版架构和微服务通信之间创建外包层(facade),比起直接使用旧版中的数据,并在微服务和旧版架构上创建耦合,要好得多。
同时,由于通用域会调用第三方库,我们与其根据合约直接使用(consume)/发布数据,不如引入一个防腐层,将微服务与外部合约的API,端口与hub模式隔离开来。也就是说,我们可以通过创建合约和防腐层,来充当微服务与第三方联系间的“翻译器”,以协助调用第三方库。
6.识别数据通信模式
一旦您基于功能分解了微服务,并在核心服务中封装了自己的数据库与持久层(即,基于每个服务的数据库),接下来需要理解的重要事项便是,UI的视图/组件将如何与每个组件进行通信(包括流程)。例如:用户在以异步的方式获取某项功能时,您可以在执行部分功能后创建中间状态,以便另一个系统对该中间状态执行处理,并以回调的方式通知用户继续后续的操作。
7.引入事件驱动架构(EDA)
在实时应用中,您的业务用例可能具有复杂的工作流,并且需要根据数据的状态变化,在工作流上产生许多分支。由于工作流程可以采取不同的策略,因此如果您需要通过Rest API公开所有的内容,则会发现每个微服务都需要与其他微服务耦合。这势必会造成“意大利面”式的代码和分布式的“泥球”。
可见,我们需要的是一个干净的架构。其中每个微服务都可以独立运行,而不会产生耦合。这正是事件驱动架构能够起作用的地方--每个事件都能够包含某个状态的变化。微服务通过遵循pub/sub模型,产生状态更改,并以事件的形式包含必要的数据。其他微服务则会侦听该事件,并能够基于事件中的数据,采取相应的策略。由于事件是不可变的,因此它也会保存实体或聚合器的历史记录。据此,如果您要采用事件存储和事件风暴,则会生成相应的统计信息和事件报告。
8.让API合约简洁明了
在微服务中,您往往需要以API的形式,来发布合约。那么,在发布API时,请确保您的API不会发布内部状态信息。考虑到网络调用与封装,发布API其实就是一种使其他服务可以获取足够的信息,以便继续其流程的方式。不过,它们不应该为了获取派生信息,而有多次返回。因此,在规划事件时,您应该考虑哪些事件可以被发布,而哪些事件需要被保留在内部。您甚至可以只发布一个粗粒度的事件,而非多个小型内部事件。例如:如果您内部产生了地址更改事件和个人信息更改事件,那么就应该发布一个名为CustomerUpdateEvent的粗粒度事件,而不是在API合约中同时发布这两者。
9.将相关的微服务合并为更大的服务
在分解之后,您可能会遇到在需要添加或更新功能时,某些微服务总会一起发生变化的情况。此时,您才会意识到自己以错误的方式分解了它。由于属于同一逻辑单元的不同部分,因此它们一定不能够被隔离到更小的服务中。对此,您可以将它们合并为一个大服务,以减少不必要的耦合和网络调用。
10.引入支持无缝开发的工具
通过采用微服务,我们既可以提高可扩展性和高可用性,又能够缩短产品上市的时间。不过由于该架构是基于分布式网络工作的,因此在出现不可避免的故障之前,我们需要事先购置各种支持软件。例如,您可以在CI/CD管道上采用云基础架构,使用配套的跟踪工具,采用日志聚合器来搜索日志,以及使用各种混沌工具(chaos tools)来检测各种失败。
原文标题:10 Commandments of Microservice Decomposition,作者:Shamik Mitradecomposition
【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】