前面我们一起探讨了一个微服务的概念了解,微服务,也称为微服务架构,是一种架构风格,它将应用程序构建为服务的集合。集合里的每个服务具有高度可维护和可测试、松耦合效果、围绕业务能力组织,由一个小团队拥有。
我们知道,微服务架构是一种架构风格,所谓的架构风格就是一种抽象的结构,它由软件的各个组成部分和这些部分之间的依赖构成。或许看着概念有些抽象,但只要记住任何涉及抽象的设计,它的目的都是为了很好地适应大型业务应用,构建一个稳健的系统。
作为开发者就深有体会,一个应用初次开发完成了并不是真正的完成,它会伴随着时间或者用户的需求而不断的更迭,随着时间更迭就会存在人员因素和历史系统设计的局限性,日常维护糟糕且不稳定的系统一定会让人崩溃吧。这是每一位开发者都需考虑和面临的问题。
那么,假如你所负责的应用变得庞大,需要进行重构,我们采用微服务架构,对你现在的需求进行拆分设计,你会怎么拆分呢?
▲图/ 微服务架构策略图,橙色为当前内容
微服务拆分策略
首先,我们需要考虑的是共享类库的角色,也就是我们在开发过程中,习惯把一些通用的功能(帮助类)打包成一个公共类库或者包中。其他服务需要使用直接引用调用即可,增加代码的复用性。但是很可能存在隐患,这个公共类库不断地叠加导致出错或者版本问题会影响到其他服务。
更好的做法就是努力使得这个共享库都是一些不太可能改变的功能,同时由专门的人去维护而不是人人都去更迭它。或者是把这些可能会变更的通用功能作为一个服务来实现,而不是共享库。
其次,在拆分服务时,我们需要精心设计的服务将适合由一个小团队开发的服务,并且交付时间最短,与其他团队的协作最少。同时,将一些小的、松耦合的服务组织到一起,以便提升开发阶段效率,特别是可维护性、可测试性和可部署性,这样能够让组织的软件开发速度更快。
接下来,我们需要对一个应用程序来定义微服务架构,进行拆分了。
第一步通常在开始之前,我们需要收集这个应用有关的信息,比如说需求文档,领域专家的信息(具有这个领域的丰富知识和技能)等。之后,我们便需要从这些信息中提炼出各种关键信息,使用抽象的系统操作来描述服务之间协作方式的架构场景,这是一种抽象化的,而不是具体的,它既可以是更新数据的命令,也可以是检索数据的查询。每个命令的行为都是根据抽象的领域模型定义的,抽象领域模型也是从需求派生出来的。
第二步,就是如何分解服务。这里有两种广为熟知的策略,一种是源于业务架构学派的策略是定义与业务能力相对应的服务。另一种策略是围绕领域驱动设计的子域来分解和设计服务。这两种方式最终都是围绕业务概念而非技术概念分解和设计的服务,所以最后的设计结果往往会有些相像。
第三步,即是确定每个服务的API。这一步设计过程中需要采用哪种进程间通讯机制来实现每个服务API的通讯。同时,需要考虑几个困难,第一个就是网络延迟,如果服务之间往返太多,导致网络延迟,那么你需要重新审视你拆分的服务是否合理。第二个就是服务之间同步通信降低了可用性。第三个就是需要维护跨服务的数据一致性,例如使用Saga,共享数据库,领域事件来解决,当然这些将会在后续探讨。第四个,就是上帝类带来的阻碍,上帝类即是整个应用中的全局类,可以通过驱动领域的概念来消除这个上帝类。
细心的伙伴会发现,在采用微服务架构时,很多难啃的骨头都可以通过DDD(驱动领域)来化解,这也是广为使用的原因之一,能够很好的配合微服务架构。
这里我们展开讲解第二步,如何分解服务。第三步将会涉及更多内容,将在后续逐一探讨。
业务能力拆分服务
使用业务能力进行服务拆分,是微服务架构的策略之一。或许不用讲也知道,业务能力是指一些能够为公司(或组织)产生价值的商业活动。每个企业也有自己的特定的业务类型。例如,在线商店所包含的业务能力包括:订单管理、库存管理和发货。保险公司业务能力包含承保、理赔管理、账务和合规等。
公司的业务能力通常是指这个组织的业务是做什么,它们通常是稳定的。与之相反公司采用何种方式来实现它的业务能力,是随着时间不断变化的。例如以往的支付方式,除了线下支付,还支持财付通支付,现如今还支持支付宝,微信支付。但是始终属于支付业务,稳定不变的,仅仅只是实现方式发生了变坏。
▲图/ 某大型餐饮系统架构
业务能力的拆解,我们可以举一个例子:例如一个餐厅管理系统,其业务能力包含:
- 供应商管理。送餐员相关信息,餐馆菜单和其他信息管理,例如营业时间和地址。
- 消费者管理:消费者相关信息的管理。
- 订单获取和履行(直接运送、第三方派送,自己运送等)。具备消费者创建和管理订单,餐馆管理订单生产过程,送餐,跟踪外卖员的实时状态,订单送到用户手中。
- 会计记账。管理跟消费者相关的会计记账,管理跟餐馆相关的会计记账,管理外卖员相关的会计记账。
- 其他。
通过上面的业务梳理,我们可以对应到API服务。
子域拆分服务
Eric Evans 于 2003 提出的领域驱动设计构建复杂软件的方法论,这些软件通常都以面向对象和领域模型为核心。领域模型以解决具体问题的方式包含了一个领域内的知识。它定义了当前领域相关团队的词汇表,DDD也称之为通用语言。领域模型会被紧密地映射到应用的设计和实现环节。在微服务架构的设计层面,DDD有两个特别重要的概念,子域和限定上下文。
领域驱动为每一个子域定义单独的领域模型,这跟传统的企业架构建模为整个企业建立一个单独的模型不同。子域是领域的一部分,领域是DDD中用来描述应用问题域的一个术语。识别子域的方式跟识别业务能力一样:分析业务并识别业务的不同专业领域,分析产出的子域定义结果也会跟业务能力非常接近。例如上例某餐馆服务的子域包括:订单获取、订单管理、餐馆管理、送餐和会计。能够看出和上面业务能力拆分服务非常相近。
DDD把领域模型的边界称为限界上下文。限界上下文包括实现这个模型的代码集合。当使用微服务架构时,每一个限定上下文对应一个或者一组服务。换一种说法,我们可以通过DDD的方式来定义子域,并把子域对应为每一个服务,这样就完成了微服务的设计工作。
或许这些内容需要多读多理解,下面我们使用一个小案例来助解。
假如我们要为一个小卖部设计一套进销存系统,她为我们提供的业务描述是这样的:每天凌晨从布吉农批市场买苹果、梨、葡萄、橘子、香蕉、荔枝、核桃等等,反正哪些好卖她就买回来卖。葡萄、荔枝不能长久保留,一般要当天卖出去…。
针对上面这段业务描述,我们怎么进行领域模型设计?将给出以下几个步骤来完成领域模型设计。
总结业务描述中的名词。首先建一个名词表,把涉及到的名词列出来:
1. 布吉农批市场 |
2. 买东西的人是一个隐含的名词,每天凌晨从农批市场拿货 |
3. 苹果 |
4. 梨 |
5. 葡萄 |
6. 橘子 |
7. 香蕉 |
8. 荔枝 |
9. 核桃 |
10. 顾客是一个隐含的名词,买回来卖的对象 |
11. 凌晨、当天时间名词,与实体及角色无关 |
这个名词列表包括了业务的行为主体:角色,以及业务过程中的操作实体:模型,对我们接下来的用例描述、领域模型分析、需求分析很有帮助。当然这个名词列表需要经过进一步分析提炼,成为领域模型
确定业务实体,用序号名词描述;
1. 布吉农批市场不是本业务的一个实体 |
2. 买东西的人是本业务的一个角色 |
3. 苹果是一个实体 |
4. 梨是一个实体 |
5. 葡萄是一个实体 |
6.橘子是一个实体 |
7. 香蕉是一个实体 |
8. 荔枝是一个实体 |
9. 核桃是一个实体 |
10. 顾客是本业务的一个角色 |
11. 凌晨、当天时间名词,与实体及角色无关 |
经过分析,我们得出的实体是苹果、梨、葡萄、橘子、香蕉、荔枝、核桃,这些是不是模型呢?应该说还不是,还要经过进一步分析:在我们分析的业务领域内,它们有没有共性?苹果、梨、葡萄、橘子、香蕉、荔枝属于水果,核桃属于干果,它们都是果品的一个具体实例。而在水果中葡萄和荔枝属于不宜保存水果,通过这样进一步的分析得出如下的领域模型:
果品进销存领域模型
这个领域模型不但能反映当前的经营实体,同时给我们需求分析人员和系统功能提供了一定的扩展视野:将来会不会经营食品,短期保持水果采取什么利润空间来促销,长期保存的水果会不会因为保存成本而导致利润下降。
那么,我们根据领域模型对业务能力拆分的某餐馆系统进行设计如下:
可以看到,DDD和微服务架构简直是天生的一对。DDD的子域和限定上下文的概念,可以很好的跟微服务架构中的服务进行匹配。
以上两种是微服务拆分的主要策略,但是也有一些有用的拆分原则是源于面向对象的设计。分别是单一职责和闭包原则,熟悉面向对象的伙伴也不陌生,这里不展开讲解。
好了,本篇我们一起探讨完了微服务拆分设计,如果有所收获的话,点个?也是鼓励呀。
下面我们继续探讨拆分服务之后,服务间的通讯。