Bootstrap

架构设计篇之微服务实战笔记(三)

第四章、新功能设计

基于业务能力和使用用例划分微服务

按技术能力划分微服务的时机

服务边界不明确时的设计决策

多团队负责微服务场景下的有效范围划分

良好的服务三大特性:只负责单一职责,可独立部署以及可替换。

4.1、新功能需求的完成步骤

  • 了解业务问题,用户案例和潜在的解决方案

  • 确定服务所要支持的不同实体和业务功能

  • 为负责这些功能的服务划定范围

  • 根据当前和未来的潜在需求验证设计方案

确定业务领域的用例流程时候,可以使用BDD 行为驱动开发(Behavior-Driven Development)

4.2、按业务能力划分

  • 按照业务能力和限界上下文划分

  • 按照用例划分

  • 按照易变性划分(未来可能发现变化的领域封装在内部)

4.2.1、能力和领域建模

一个领域的任何解决方案都是由若干个限界上下文组成的。每个上下文内的各个模型都是高度内聚的,并且对现实世界抱有相同的认知。

API网关可以做为边界的划分分割线

4.2.2、创建投资策略

根据UML类图/或者实体图 进行服务的划分,识别出属于不同能力的实体和职责,确定了微服务应用的边界;将系统划分到一个个能够反映这些业务领域边界的服务中。

4.2.3、内嵌上下文和服务

将内部嵌套的上下文和对外暴露的信息隔离开

4.2.4、挑战和不足

  • 需要大量的业务知识

  • 粗粒度服务不断发展(未来服务还是需要变化的)

4.3、按用例划分

根据实际的行为驱动开发的用例来进行划分领域。通过时序流程图来进行划分

4.3.2、动作和存储

简洁架构

实体 (Entities)

实体封装了企业级的业务逻辑。一个实体可以是一个带有方法的对象,或者一个数据结构和函数的集合,实体可以被企业内的多个应用使用的。如果没有企业只是写单个应用的话,这些实体就是应用的业务对象。他们在外部变化时改动最少,例如,不希望页面导航的改变影响到实体对象的改变或者安全性。应用的操作性改变不应该影响实体层。

用例 (Use cases)

这一层的软件包含了应用相关的特定业务逻辑,封装了所以的系统用例。这些用例编排了实体之间的数据流,目标是将实体指向企业层面的业务规则。同样不希望这一层影响到实体,也不希望这一层被外部元素所影响例如 数据库, UI, 或其他通用框架。然而,希望应用操作的改变影响这一层的用例,如果一个用例的实现细节改变了,这一层的一些代码一定受到影响。

接口适配器 (Interface Adapters)

该层的软件是一组适配器的集合,这些适配器将数据转换成用例和实体方便使用的格式,以及一些外部代理方便使用的格式例如数据库或者Web。例如,一个包含MVC架构的图形界面,Presenters, Views, 和 Controllers 都位于该层。models就像数据结构一些从controllers传递到use cases,然后从用例返回到presenters 和 views。

类似的,来自实体和用例的数据会被转换到驻留框架,例如数据库。这一层没有向内的代码来感知外部的数据库。如果数据库是一个SQL 数据库的话, 那么所有SQL被限制在该层,这一层中特殊的部分处理数据库。这一层中还有其他一些适配器转换外部服务的数据到内部使用的用例和实体。

框架与驱动(Frameworks and Drivers)

最外层油框架和工具组成,如数据库,Web框架等。 一般地,不需要写大量的代码就可以和内部的圆进行通信了。这一层细节密布,Web 是细节实现,数据是另一种细节,把他们保持在外可以减少伤害。

大叔的简洁架构只有四层么?绝对不是的,这些圆不过是示意而言,可以远多于4层的。但依赖原则总是适用的,最外圈总是底层的具体实现。

右下角的框图展示了是如何跨越边界的,描绘了Controllers 和Presenters 如何与下一层的用例通信。注意一下控制流,开始于controller, 穿过用例在presenter中执行。这也是源代码依赖,向内执行用例。这就是通常使用的DIP,在Java中,可以通过接口和继承关系来实现跨边界的控制流,动态的多态性可以跨越这一架构的所有边界。跨越边界的典型数据是简单的数据结构。可以使用基本结构或者简单的数据传输对象,或者函数的调用参数,重要的是相互隔离。例如,很多数据库框架都在查询时返回一个数据集, 最好不要让它跨边界传递,它违反了依赖原则即内圆知道了外圆的事情。

六角架构

六角架构原理

六边形体系结构基于三个原则和技术:

  • 明确区分应用程序,领域和基础结构三个层

  • 依赖关系是从应用程序和基础结构再到领域

  • 我们使用端口和适配器隔离它们的边界

\1. 原则:独立的应用程序,域和基础结构三个层

第一个原则是明确地将代码分成三个大层。

左侧Application是应用程序端

这是用户或外部程序与应用程序交互的一面。它包含允许这些交互的代码。通常,您的用户界面代码,API的HTTP路由,以及使用您的应用程序的程序的JSON序列化都在这里。(banq注:Spring Boot的控制器)

这里也是Actor角色驱动领域所在。注意:Alistair Cockburn谈的是应用程序方面的左侧或用户侧。

领域层Domain中心位置

通过领域层隔离左侧和右侧。它包含所有关注和实现业务逻辑的代码。业务词汇和纯粹的业务逻辑。

右侧基础设施层

在这里,我们可以找到您的应用程序需要什么,它驱动哪些组件进行工作。它包含必要的基础结构详细信息,例如与数据库交互的代码,调用文件系统或处理对您所依赖的其他应用程序的HTTP调用的代码(集成)。

以下原则将实现在应用程序基础结构之间实现逻辑分层。

这种分离的第一个重要特征是它将问题分开。在任何时候,您都可以选择专注于某个逻辑,几乎独立于其他两个逻辑:应用程序的逻辑,业务的逻辑或基础架构的逻辑。它们在不混合的情况下更容易理解,并且每个逻辑的约束对其他逻辑的影响较小。

另一个特点是我们将业务逻辑放在代码的最前端。它可以在目录或模块中隔离,以使其对所有开发人员都明确。它可以在不承担程序其余部分的认知负荷的情况下进行定义,改进和测试。这很重要,因为最终,开发人员对生产中的业务有了解。

4.3.3、编配与编排

平衡服务的内部编配和编排,达到平衡点

4.4、按易变性划分

易变和不变的进行区分,可以减小未来系统服务的复杂度

4.5、按技术能力划分

4.5.1、发送通知

比如邮箱通知只是举个例子,来实现说明技术能力的划分来提高复用性

4.5.2、何时使用技术能力

比如面向SOA服务,之前在京东我们经常会发现一个需求的上线,会联动多个系统,比如一个运营和产品的给用户促销的需求,则会联动如下这么多系统。

那么假设现在订单系统拆分为订单业务,订单数据,订单页面,订单存储多个微服务,则需要修改四个微服务。但是如果只是根据业务功能拆分为订单系统,那么只需要修改一个服务。所以单体应用和微服务在何时用技术能力来划分的时候,还是要贴合业务来搞。

4.6、处理不确定性

  • 不断迭代

  • 预测未来发展

4.6.1、从粗粒度服务开始

为了防止过早分解,但是业务不熟导致的后果

4.6.2、准备进一步分解

通过清晰的公共API来规范内部模块的边界

4.6.3、下线和迁移

平滑迁移,数据双写。保证我们的模式为 “扩展->迁移->收缩”

4.7、组织中的服务所有权

微服务带来的影响

  • 控制变弱(无法全面掌控所依赖的服务)

  • 设计受限(消费者的需求会限制服务的契约)

  • 开发速度不一致(不同团队的规模、效率和工作优先级不同)

减少上面的影响

  • 开放化

  • 组件化

  • 接口明确化

  • 明确的期望

对于这块我的感受是我们可以共享 团队内部资料,提炼出公共组件化,统一技术栈,让技术实施更加统一规范。