架构师训练营 10 周 -- 学习总结
微服务:服务本身的设计、维护和治理
单体巨无霸应用带的痛点:
编译部署困难
代码分支管理困难:多个团队共同维护,merge 冲突严重
数据库连接耗尽:集群部署应用,建立了大量的连接
新增业务困难:维护旧功能和添加新业务一样困难
解决方案:拆分--模块独立,降低耦合
横向拆分:拆分出复用的业务,独立部署成微服务
纵向拆分:大应用拆分成小应用
微服务框架
a. Web service 与企业级分布式服务
缺点:总之,不适用于大型的网站
臃肿的注册与发现机制
低效的 XML 序列化手段
相对高昂的 http 远程通信
复杂的服务和维护
1)服务提供者使用 WSDL 描述自身的服务,并行服务中心注册
2)服务中心使用 UDDI 对外发布服务
3)服务请求者通过服务中心得到服务信息,通过 SOAP 协议和服务提供者通信
b. 微服务框架需求
服务注册和发现
失效转移 fail over:集群部署,以实现服务高可用
负载均衡:平衡集群内机器的负载
高效的远程通信:不要让服务调用成为系统性能瓶颈
对应用最少侵入:微服务是手段,不是目标。过程会有反复,根据业务要求,可能退回集中式部署,微服务框架需要支持这种变化
版本管理:服务升级对使用者透明。接口升级需要提供历史版本的服务,直到请求都转向访问新接口。
c. 微服务框架(Dubbo)架构
d. Service Mesh 服务网格
轻量级的网格代理,和应用服务一起部署,负责服务发现和服务间的通信
边车模式 side car
服务请求者不再和注册中心通信,由 service mesh 负责缓存服务信息,请求者直接调用 service mesh 即可
微服务:落地实践的策略和思路
微服务架构落地的指导原则:
业务先行,先理顺业务边界和依赖,技术是为业务服务的
从单体应用中,先分离独立模块,在形成分布式服务,一步步演进
业务严重耦合,逻辑复杂的系统,重构成微服务需要谨慎
明确实施微服务的目的:业务复用 or 分布式提升性能 or 清晰划分开发边界 等
具体落地的实现手段:
命令与查询职责分离(CQRS)
读写服务分离,分别优化,实现更好的性能
更清晰的领域模型
查询服务不会修改数据,更好的保护数据
事件溯源
记录用户请求处理过程中的状态变化,并按照时间序列进行持久化存储
可以复现用户的状态
可以监控用户状态的变化,并在此基础上实现分布式事务
断路器:
防止对失效服务的大量请求,造成资源消耗
三个状态:关闭、打开、半开
当某个服务器失效的时候,当失败请求超过阈值,断路器打开,对请求直接返回调用失败信息。
当断路器打开一段时间后,进入半开状态,尝试调用服务,如果成功次数超过阈值,则进入关闭状态;如果失败次数超过阈值,则进入打开状态。
服务重试以及调用超时
上游服务调用的超时时间,要大于下游调用者超时时间之和
否则,下游服务还在等待返回结果,上游服务已经超时,这样没有意义
微服务网关
基于网关的微服务架构
对外:是提供服务的唯一入口
对内:鉴权,防护,协议适配,限流、降级等
网关管道技术
网关本身没有业务,可以通过管道技术串联各种校验和拦截
主要使用责任链模式实现
开放平台网关
API 接口:多种形式的接口,供合作者使用
协议转换:转换外部请求的协议;封装内部服务的响应
安全:身份识别、鉴权、访问带宽限制、限流
审计:记录访问日志、监控、计费
路由:将 API 请求路由到具体服务
流程:将一组服务组织成完整的新服务,向调用者屏蔽其中的服务细节
开发授权协议 OAuth2.0
a. 服务本身不提供用户注册功能,依赖第三方的应用(比如微信)来认证用户,或者需要用户授权访问第三方应用的某些资源
b. OAuth2.0
有四种授权方式:授权码、隐式授权、资源所有者密码凭据、客户端凭据
最安全的是 授权码 方式:先获得 Authentication Code, 再换取 Access Token
领域驱动设计 DDD
事务脚本 -- 通常使用贫血模型
典型的 spring 框架下的业务开发
可以应对不复杂的业务
Controller,server,dao 对象只有业务方法,少有成员变量
业务对象只有成员变量,和简单的 set,get 方法。业务对象作为参数在方法调用中传递
领域模型 -- 使用充血模型
领域对象中包括数据(成员变量)和计算逻辑(方法)
采用了面向对象的设计理念
可以应对复杂的业务
领域驱动设计
a. 战略设计 -- 划分模块,梳理服务的边界和依赖关系
领域:组织的业务范围,也是软件开发的目标范围
子域:领域太大,拆分成多个子域,子域内业务高内聚
限界上下文:概念上的领域边界,任何领域对象在这个边界内表示的含义是明确的。通常限界上下文和子域是一一对应的,用来控制子域的边界。
通常限界上下文对应一个组件,模块,微服务,子系统。
上下文映射图:描述不同限界上下文之间的交互合作
b. 战术设计
实体:具有唯一标识的领域对象。实体属性发生了改变,只要标识未变,实体就没有改变。
实体是 DDD 的核心所在,需要通过业务分析,识别出实体对象,然后在限界上下文中设计实体的属性和方法。
值对象:具有不变性的特点。对象属性发生了改变,值对象就不在是原先的那个值对象,是一个新的值对象
聚合:一个实体作为聚合根,将其他实体和值对象关联起来。聚合是数据修改和持久化的基本单元。一个限界上下文内,可以有多个聚合根。
分层架构:实体的组合调用和事务应该控制在应用层
六边形架构:
领域模型是核心
应用程序是封装领域模型的独立模块
与外部系统通过适配器通信
c. 用限界上下文识别微服务的边界和依赖关系
组件设计原则
组件的内聚原则 -- 组件包含的功能和类
a. 复用发布等同原则
你希望别人以怎样的粒度复用你的软件,你就应该以怎样的粒度发布你的软件。这个粒度就是组件的最小粒度
版本号约定:三位数字版本号,<主版本>.<次版本>.<修订版本>
b. 共同封闭原则
应该将那些会同时修改,并且为了相同目的而修改的类放到同一个组件中
当变更发生时,修改将限定在组件内,只要重新发布这个组件。
c. 共同复用原则
不要强迫一个组件的用户依赖他们不需要的东西
将相互依赖,共同复用的类放入一个组件中。比如,hashmap 等数据容器类和对数据遍历的类就应该放入同一个组件中。
不是相互依赖的类,不要放入同一个组件。如果不被依赖的类发生变化,会引起组件重新发布,导致调用程序也需要改变,造成了组件复用困难。
组件耦合原则 -- 组件间的关系
a. 无循环依赖原则
组件的依赖关系中不应该出现环
通常,循环依赖是在组件变更的过程中逐渐形成的。避免的方法是,组件设计边界清晰,组件依赖管理有统一的规则
b. 稳定依赖原则
不稳定(变更多)的组件应该依赖稳定(变更少)的组件,而不是反过来
如果一个组件依赖了很多的组件,那它是相对不稳定的组件,因为它依赖的任何组件发生了变更,都可能导致它自己变更
c. 稳定抽象原则
一个稳定的组件应该是抽象的,而不稳定的组件应该是具体的
可以为组件对外服务的类设计一组接口,并将这组接口放入专门的组件中,这个接口组件就是比较抽象和稳定的,而实现了具体服务的组件就是具体的,不稳定的
比如 jdbc 的接口,和 mysql,oracle 的具体实现类
组件的边界与依赖关系
不仅仅是技术问题,也关系到业务、人、组织部门的问题
康威定律
版权声明: 本文为 InfoQ 作者【骏马】的原创文章。
原文链接:【http://xie.infoq.cn/article/c0fca746d6161f51cf292f047】。未经作者许可,禁止转载。
评论