写点什么

模块分解总结

用户头像
Mars
关注
发布于: 2020 年 12 月 27 日

微服务:服务设计、维护与治理

微服务产生背景:网站系统越来越复杂,随着系统复杂性提高,维护也越困难。

解决方案:将模块独立部署,降低系统耦合。

纵向拆分:将大应用拆成小应用,如果新应用比较独立,将其设计部署为一个独立的web应用。

水平拆分:将负用的业务拆分,独立部署为微服务,新增业务只需要调用这些微服务即可快速搭建一个应用系统。

Web service与企业级分布式服务

缺点

l  臃肿的注册与发现机制。

l  低效的xml序列化手段。

l  开销相对较高的HTTP远程通信。

l  复杂的部署与维护手段。

以上缺点导致web service难以满足大型网站系统对高性能、高可用、易部署、易维护要求。

微服务框架需求

服务注册与发现

负载均衡:对于集群部署提供者,服务请求者可以使用加权轮询等手段访问,使服务提供者集群实现负载均衡。

失效转移:对于大型互联网的微服务而言,即使是很少访问的简单访问,也需要集群部署。同时微服务框架还需要支持服务提供者的失效转移机制,以实现服务高可用。

高效的远程通信

对于大型网站,核心服务每天的调用次数会达到数以亿计,如果没有高效的远程通信手段,服务调用可能会成为整个系统性能瓶颈。

对应用最少侵入

网站技术是为业务服务的,是否使用微服务需要根据业务发展规划,微服务也需要渐进式的演化,甚至会出现反复,使用微服务后又退回集中式部署,微服务框架需要支持这种渐进式演化和反复。当然服务模块本身需要支持可集中式部署,也可分布式部署。

版本管理

为应对快速变化需求,服务版本升级不可避免,如果仅仅是服务实现升级,那这种升级对服务请求者而言是透明的,无需关注。

微服务框架(dubbo)框架



Service mesh服务网格

Service mesh是基础设施层,用于处理服务间通信,通常表现为一组轻量级网络代理,他们与应用程序部署一起,而对应用程序透明。

Service mesh的sidecar模式





微服务架构落地

l  业务先行,先理顺业务边界和依赖,技术是手段而不是目的。

l  现有独立模块,再有分布式服务。

l  业务耦合严重,逻辑复杂多变的系统进行微服务重构时要谨慎。

l  要搞清实施微服务的目的是什么?业务复用?开发边界清晰?分布式集群提升性能?

命令与查询职责隔离(CQRS)

在服务接口层面将查询(读操作)与命令(写操作)隔离,实现服务层的读写分离。

l  更清晰的领域模型。

l  针对读写分别优化,实现更好性能。

l  查询服务不会修改数据,更好的保护数据。

事件溯源

将用户请求处理过程中的每次状态变化都记录在事件日志中,并按时间顺序进行持久化存储。

l  利用事件溯源,可以精确复现用户任何状态,进行复核审计。

l  利用事件溯源,可以有效监控用户状态变化,并在此基础上实现分布式事务。

断路器

当服务出现故障,响应延迟或者失败率增加,继续调用这个服务会导致调用请求阻塞,资源消耗增加,进而出现服务级联失效,这种情况下使用断路器阻断对故障服务的调用。

断路器三种状态:关闭、打开、半开。





微服务网关的技术架构

基于网关的微服务架构





网关作用





网关管道技术

网关本身没有什么业务,主要职责就是做各种校验与拦截,这些职责可以通过管道技术连接起来。

Request –> 参数校验 -> 限流控制 -> 接口调用 -> request

使用责任链模式实现管道技术





开放平台网关

API接口:是开放平台暴露给合作者的使用的一组API,其形式可以是Restful、webservice、RPC等形式。

协议转换:将各种API输入转换成内部服务可以识别的形式,并将内部服务的返回封装成API的格式。

安全:除了一般应用需要的身份识别、权限控制等安全手段,开放平台还需要分级的访问带宽控制,保证平台资源被第三方应用公平合理使用,也保护网站内部服务不会被外部应用拖垮。

审计:记录第三方应用的访问情况,并进行监控、计费等。

路由:将开放平台的各种访问路由映射到具体的内部服务。

流程:将一组离散的服务组织成一个上下文相关的新服务,隐藏服务细节,提供统一接口供开发者调用。





开放授权协议OAuth2.0





授权码授权

OAuth2.0一共有四种授权方式:授权码、隐式授权、资源所有者密码、凭据和客户端凭据。

目前互联网使用最多也是最安全的一种方式是授权码授权。





领域驱动设计DDD

多数项目现状

l  用户和产品经理需求零零散散,不断变更。

l  工程师在各处代码中寻找可以实现这些需求变更的代码,修修补补。

l  软件只有需求分析,并没有真正的设计,系统没有一个统一的领域模型维持其内在的逻辑一致性。

l  功能特性并不是按照领域模型的内在的逻辑设计,而是按照各色人等自己的主观想象设计。

事务脚本





领域模型





贫血模型VS充血模型

由于事务脚本中,Service、Dao这些对象中只有方法,没有数值成员变量,而方法调用时传递的数值对象,比如contact,没有方法(只有一些setter getter方法),因此事务脚本被称为贫血模型

领域模型的对象则包含了对象的数据和计算逻辑,比如合同对象,既包含合同数据,也包含合同相关的计算。因此从面向对象的角度看,领域模型是真正的面向对象。收入确认是和合同强相关,是合同对象的一个职责,那么合同对象就应该提供一个calculateRecognition方法计算收入。

领域模型是合并了行为和数据的领域的对象模型。通过领域模型的对象的交互实现业务逻辑。也就是说,设计好了领域模型对象,也就设计好了业务逻辑实现,因此领域模型被称为充血模型

 

DDD战略设计

领域是一个组织要做的事情以及包含的一切,通俗的说,就是组织的业务范围和做事方式,也就是软件开发的目标范围。

领域驱动设计就是从领域出发,分析领域内模型及其关系,进而设计软件系统的方法。





子域

通常将整个领域拆分成多个子域。比如:用户、商品、订单、库存、物流、发票等。

限界上下文

在一个子域中,会创建一个概念上的领域边界,在这个边界中,任何领域对象都只表示特定于该边界内部的确定含义。这个边界称为限界上下文。限界上下文和子域一对一,用来控制子域边界,保证子域内的概念统一性。

通常限界上下文对应一个组件或者一个模块,或者一个服务、一个子系统。

上下文映射图

不同的限界上下文,也就是不同的子系统或者模块之间会有各种的交互合作。DDD使用上下文映射图来设计这种关联和交互。

 

实体

领域模型对象也被称为实体,每个实体都是唯一的,具有唯一标识,一个订单对象是一个实体,一个产品对象也是一个实体,订单ID或者产品ID是它们的唯一标识。实体可能会发生变化,比如订单的状态变化,但是它们的唯一标识不会变化。

DDD核心所在,通过业务逻辑分析,识别出实体对象,然后通过相关的业务逻辑设计实体的属性和方法。这里是最重要的,是要把握住实体的特征是什么,实体应该承担什么职责,不应该承担什么职责,分析的时候要放在业务场景和界限上下文中,而不是想当然的认为这样的实体应该承担这样的角色。

值对象

领域内的对象兵不应该都设计为实体,DDD推荐尽可能将对象设计为值对象。比如像住址这样的对象就是典型的值对象,建在住址上的房子可以被当做一个实体,但住址仅仅是房子一个描述,像这样仅仅用来做度量或描述的对象应该被设计为值对象。

值对象的一个特点是不变性,一个值对象创建以后就不能再改变了。如果地址改变了,那就是一个新地址,而一个订单实体则可能会经历创建、待支付、已支付、待发货、已发货等各种变化。

聚合

聚合是关联对象的集合,我们将其作为一个单元来处理数据更改。每个集合都有一个根和一个边界。边界定义了聚合内部的内容。根是聚合中包含的单个特定实体。

聚合根:将多个实体和值对象聚合在一起的对象。

DDD分层架构

领域实体的组合调用和事务控制在应用层。

 



DDD六边形架构

领域模型通过应用程序封装成一个相对独立的模块,而不同的外部系统通过不同的适配器和领域模型交互,比如可以通过HTTP接口访问领域模型,也可以通过webservice或者消息队列访问领域模型,只需要为这些不同的访问接口提供不同适配器。

DDD战略设计:领域、子域、界限上下文、上下文映射图。

DDD战术设计:实体、值对象、聚合、CQRS、事件溯源。

通过战略设计,划分模块和服务的边界及依赖关系,对微服务架构的设计至关重要。

软件组件设计原则

组件内聚原则

复用发布等同原则

版本号约定建议:

       主版本号升级,表示组件发生了不向前兼容的重大变更。

       次版本号升级,表示组件进行重要功能修订或bug修复,但组件向前兼容。

       修订号升级,表示组件进行不重要功能修订或bug修复。

共同封闭原则

通常将那些会同时修改,为相同目的而修改的类放在同一个组件中,将不会为相同目的而修改的类放在不同组件中。

共同复用原则

不会强迫一个组件的用户依赖它们不需要的东西。

 

组件耦合原则

无循环依赖原则

稳定依赖原则

稳定抽象原则

 

案例:用领域驱动设计驱动系统重构

随着业务发展如何做到高内聚、低耦合





发布于: 2020 年 12 月 27 日阅读数: 16
用户头像

Mars

关注

还未添加个人签名 2018.06.12 加入

还未添加个人简介

评论

发布
暂无评论
模块分解总结