架构
架构满足了应用程序的非功能性需求:可维护性、可测试下、可扩展性、可部署性等。
软件架构的最高优先级是保持系统正常工作,软件架构的策略就是京可能长时间保留尽可能多的可选项
架构是什么
开发
一个软件系统的开发,应该就是要方便其开发团队
- 流行的不一定好,适合的才是最好的
一个系统的架构,反映了开发该系统的团队组织结构
部署
良好的软件结构可以让系统构建完成就能部署,同时实现一键式的轻松部署是设计软件架构的一个目标
运行
设计良好的架构能明确地反映出系统运行时的需求
架构是系统运行时的一个表示
维护
维护的主要成本
- 探秘:解决问题的最佳方式
- 风险:解决问题衍生出的新问题
保持可选项
用例:对系统如何响应外接请求的描述
软件系统可降解为
- 策略:业务逻辑
- 细节:具体实现技术,数据库、web等
在大部分时间,无法预知系统的所有用例,越晚决定实现细节,就能掌握更多信息,更有利于决策
设备无关性
高层策略与低层实现细节分离
解耦
系统可以被按层解耦,将不同层隔离开来,避免变化扩散到其他层
当对用例进行分组时,增加新用例就会对旧的用例影响降低
解耦模式
- 源码解耦:控制源代码模块的依赖关系
- 部署层次解耦:控制可部署模块的依赖关系
- 服务解耦:依赖关系降低到服务层次
软件架构是生长的,从单体到相互独立可部署单元,再到服务化
设计良好的架构应该允许软件系统从单体到服务,也可以从服务退化到单体
重复
重复需要分清表面重复还是实际重复,随着软件的演进,两段重复的代码可能会变得不同
独立性
- 开发独立性:当对系统进行解耦时,不同的模块就可以由多个团队来分工开发
- 部署独立性:同样,解耦之后部署就可以互不影响
分类
基础架构
- 以云平台 操作系统等基础设施为主
中间件与大数据架构
业务系统架构
- 通用软件系统 办公软件 浏览器等一类
- 离线业务系统 大数据分析 数据挖掘系统
- 在线业务系统 在线为特定业务服务的系统
这些不同分类的架构界限不是很清晰 随着时间演进 各个类型之间的系统边界会互相渗透
架构视图
- 架构的表现形式通常是各种图
绘图原则4R:
- 明确 Rank:也就是说,不要事无巨细地把一个大系统的方方面面都在一张架构图中展现出来,而应该明确你要阐述的系统所属的级别(L0~L4),然后只描述这个级别的架构信息。
- 画出 Role:从不同的角度来分解系统,看看系统包含哪些角色,角色对应架构图中的区块、图标和节点等。
- 画出 Relation:有了角色后,画出角色之间的关系,对应架构图中角色之间的连接线,不同的连接线可以代表不同的关系。
- 最后画出 Rule:挑选核心场景,画出系统角色之间如何协作来完成某项具体的业务功能,对应系统序列图。
四加一
- 逻辑视图:对系统职责进行划分,通常还要求对各逻辑元素间的关系,也就是接口进行描述
- 实现视图:描述逻辑架构元素代码位置 描述代码构建相关的包括构建依赖、构建工具链、构建环境信息
- 部署视图
- 进程视图:组件之间的交互 常见的如时序图描述
- 场景视图:从用户角度看系统需要实现的需求
业务架构图
描述系统对用户提供了什么业务功能
- 通过不同颜色来标识业务状态
- 业务分组管理
- 区块对齐
前端架构图
描述客户端和前端的领域逻辑架构
- 不同颜色来标识不同角色
- 通过连接线来表示关系
- 分层或分组
系统架构图
描述后端的逻辑架构
- 不同颜色来标识不同角色
- 连接线来表示关系
- 逻辑分组
应用架构图
跟系统架构图很像,唯一需要注意的点就是复杂系统分域来画
部署架构图
描述后端系统具体是如何部署的
- 用图标代替区块,这样看起来更加美观和容易理解
系统序列图
描述某个业务场景下,系统各个角色如何配合起来完成业务功能
架构立方体
- 逻辑
- 物理
- 应用
- 技术
- 功能
- 部署
架构体系框架
- ABSD
- DSSA
- AT
架构的演进
站在后端开发人员的角度上软件架构风格从大型机(Mainframe),到原始分布式(Distributed),到大型单体(Monolithic),到面向服务(Service-Oriented),到微服务(Microservices),到服务网格(Service Mesh),到无服务(Serverless)
谈起微服务,会想到技术异构,便于部署,高性能等等,但这些似乎都只是锦上添花,架构的核心在于解决软件的存活问题,如果一个软件压根就不能提供服务,这些锦上添花的功能也毫无作用
架构认知派别
组成派
架构由 模块/服务/领域 组成
本质在描述组件与组件之间的交互(画各种架构图)
决策派
软件架构由一个个决策组成的有机整体(把架构比作城市规划)
每个做的决策都有它背后的原因
架构的目标
用最小的人力成本来满足构建和维护该系统的需求,主要目的是为了解决软件系统复杂度带来的问题
复杂性的来源:
- [高并发](/软件工程/架构/系统设计/高并发.html)
- [可用性](/软件工程/架构/系统设计/可用性.html)
- 扩展性
- 成本 安全性 规模大小
在乱麻系统下工作,过度的自信导致软件维护成本持续上升
软件的两个价值:
- 行为价值 让系统正常运行 完成需求
- 架构价值 让系统更容易修改
维护架构价值,是研发人员所需要进行斗争的
架构的意义
项目干系人交流的手段
语境不同、立场不同、渠道问题等导致的语义失真 所以使用架构作为手段沟通
架构演进有助于原型的确定与设计
早期设计决策的体现
如果做架构决策:
- SWOT分析
- RASCI决策
明确系统实现的约束条件
RAID矩阵:
- | Risk | Assumption | Issue | Dependency |
---|---|---|---|---|
决策1 | ||||
决策2 | ||||
决策3 |
是组织架构的反映 会影响组织架构
- 康威定律
是可复用、可传递的模型
- 方法论
- 模型
架构可复用的内容一般都是比较少的,每个项目的架构肯定不能照搬 需要裁剪
为了复用,需要对架构资产进行更新与保留,拥有一个知识传承的平台
实现细节
数据库
- 为系统中的数据设计结构
web
- web只是一种io设备
应用程序框架
- 引入框架带来的风险
架构边界
边界划分
软件架构设计就是一门划分边界的艺术
为了划分划分边界线,软件系统被分割成组件,这些组件的一部分是核心的业务相关组件,另一部分是非核心的但是是提供必要功能的组件,让这些非核心组件去依赖系统的核心组件
通过划清边界,可以推迟一些细节性的决策
- 领域划分
- 按需求划分
- 定制裁剪
何时何地划分
- 画在不相关的事情中间
IO是无关紧要的,软件系统的核心,是业务逻辑
插件式架构
软件开发技术发展的历史就是如何想方设法增加插件,这些插件要么可以去掉,要么要多种实现
跨边界调用
边界线一侧的函数调用另外一侧的函数
- 自律式的组件划分
边界形式
- 部署层次的组件
- 线程
- 进程
- 服务
单向边界
设计架构时,往往需要使用反向接口来维护边界两侧组件的隔离性
边界与层次
作为架构师,需要考虑:
- 什么地方需要设计架构边界设计
- 设计这些边界会带来多大的成本
同时,设计边界需要深思熟虑,过度的工程设计往往比工程设计不足还要糟糕
策略与层次
本质上,软件系统是一组策略语句的集合
软件架构的重点之一,是将策略彼此分离
直接管理IO的策略,层次是最低的
- 高层策略一般变更没有低层策略频繁
当源码依赖方向统一调整低层指向高层策略,可以大幅度降低系统变更带来的影响
业务逻辑
业务逻辑就是系统中真正用于赚钱或者省钱的过程,这些过程被称为关键业务逻辑,关键业务逻辑通常会处理一些数据,这些数据叫做关键业务数据,关键业务逻辑与关键业务数据通常是紧密相连的,所以将他们两个放在一起,这种对象称之为业务实体
用例
- 输入
- 步骤
- 输出
请求和响应模型
对用例的输入输出对象,应该保持独立
COLA
- 阿里提出的一套通用架构方案,吸收了DDD、整洁架构、六边形架构
扩展设计
在系统设计时,针对业务或者场景预留一些扩展点
整洁架构
许多架构都是按照不同关注点对软件进行切割
- 分离技术复杂度与业务复杂度
特点
- 独立于框架
- 独立于UI
- 独立于数据库
- 独立于外部机构
- 可测试
依赖关系规则
- 内层圆不应该依赖外层圆
- 外层圆的变更不应影响到内层圆
谦卑对象
谦卑对象模式是让单元测试的编写者区分容易测试的行为与难以测试的行为
一个优秀的架构,应该拥有强大的可测试性
- 展示器与视图
Main组件
系统中,至少需要一个组件来负责创建、协调、监督其他组件,这个组件称为Main组件
Main组件是系统中细节信息最多的组件,即Main组件是一个底层模块,处于架构圈的外层
测试
测试组件,可以视为最外圈的最外圈程序
可测试设计
脆弱的测试问题
不良的测试设计,会导致一个对通用组件的修改产生许多测试错误
解决方法就是测试不要依赖于多变的东西
整洁的嵌入式架构
固件程序也可以指针对具体平台的编码
程序适用测试
仅仅停留在让代码能跑起来的阶段
架构的未来
- 云化:XaaS
- 演进式
具体技术下的架构
- 单体架构:Spring Boot
使用传统的分层,打成一个jar包 运行它
- 微服务:Spring Cloud
高可用 高性能等需求使我们不得不对系统进行拆分,在前面的单体架构下,分成多个工程 业务代码与服务基础设施代码耦合在一起 构成了传统的微服务,也是目前最流行的架构
- 微服务:K8S
在传统的微服务下,基础设施代码与业务代码耦合在一起,这个阶段下使用了K8S的容器基础设施来完成大部分服务治理功能,应用程序可以更专注我们的业务
- 服务网格:Istio
K8S将服务治理沉淀到基础设施只是第一步,接下来服务网格将这事做的更加彻底,更加可管理 可观测
- 另外一条支线:无服务
上传代码,某些事件会触发你的代码运行它,彻底不用管理基础设施,一切交给云