“从零开始学架构” 提纲梳理
上半年在极客时间里买了 “从零开始学架构” 的课程,这里做个归纳了一个提纲出来,具体理解学习还是看原文比较好。顺便吐槽一下,这个学期学院开了一门 “软件架构和质量” 的课程,第一天上课老师就说 “我已经 4 年没参与过实际的架构设计实践了”,我都不知道该说什么……
架构是指什么
系统与子系统
系统 泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。它的意思是 “总体” “”整体 或 “联盟” 。
- 关联 :系统是由一群有关联的个体组成的,没有关联的个体堆在一起不能成为一个系统。
- 规则 :系统内的个体需要按照指定的规则运作,而不是单个个体各自为政。
- 能力 :系统能力与个体能力有本质差别,系统能力不是个体能力之和,而是产生了新的能力。
子系统 也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。
模块与组件
软件模块(Module) 是一套一致而互相有紧密关联的软件组织。它分别包含了程序和数据结构两部分。现代软件开发往往利用模块作为合成的单位。模块的接口表达了由该模块提供的功能和调用它时所需的元素。模块是可能分开被编写的单位。这使它们可再用和允许人员同时协作、编写及研究不同的模块。
软件组件 定义为自包含的、可编程的、可重用的、与语言无关的软件单元,软件组件可以很容易被用于组装应用程序中。
模块 和 组件 都是系统的组成部分,只是从不同的角度拆分系统而已。
从 逻辑的角度 来拆分系统后,得到的单元就是 “模块”;从 物理的角度 来拆分系统后,得到的单元就是 “组件”。划分模块的主要目的是 职责分离 ;划分组件的主要目的是 单元复用 。
框架与架构
软件框架(Software Framework) 通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。
软件架构 指软件系统的 “基础结构”,创造这些基础结构的准则,以及对这些结构的描述。
架构
软件架构指软件系统的顶层结构。
架构是顶层设计;框架是面向编程或配置的半成品;组件是从技术维度上的服用;模块是从业务为度上的职责划分;系统是相互协同可运行的实体。
架构设计的目的
架构设计的主要 目的 是 为了解决软件系统复杂度带来的问题 。
- 通过熟悉和理解需求,识别系统复杂性所在的地方,然后针对这些复杂点进行架构设计。
- 架构设计并不是要面面俱到,不需要每个架构都具备高性能、高可用、高扩展等特点,而是要识别出复杂点然后有针对性地解决问题。
- 理解每个架构方案背后所需要解决的复杂点,然后才能对比自己的业务复杂的,参考复杂点相似的方案。
复杂度来源
高性能
软件系统中 高性能 带来的复杂度主要体现在两方面,一方面是 单台计算机内部为了高性能带来的复杂度 ,另一方面是 多台计算机集群为了高性能带来的复杂度 。
单机复杂度
计算机内部复杂度最关键的地方就是 操作系统 。操作系统是软件系统的运行环境,操作系统的复杂度直接决定了软件系统的复杂度。操作系统和性能最相关的就是 进程 和 线程 。
让多个 CPU 能够同时执行计算任务,从而实现真正意义上的多任务并行。目前这样的解决方案有 3 种:SMP (Symmetric Multi-Processor,对称多处理器结构)、NUMA(Non-Uniform Memory Access,非一致存储访问结构)、MPP(Massive Parallel Processing,海量并行处理结构)。
集群的复杂度
- 任务分配 :指每台机器都可以处理完整的业务任务,不同的任务分配到不同的机器上执行。
- 需要增加 任务分配器 ,可能是 硬件网络设施(F5,交换机等) ,可能是 软件网络设备(LVS) ,也可能是 负载均衡软件(Nginx、HAProxy) 。
- 任务分配器和真正的业务服务器之间有连接和交互,需要选择合适的连接方式。
- 任务分配器需要增加分配算法。
- 任务分解 :把原来大一统但复杂的业务系统,拆分成小而简单但需要多个系统配合的业务系统。
- 简单的系统更加容易做到高性能
- 可以针对单个任务进行扩展
高可用
系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。
系统的高可用方案本质上都是通过 “冗余” 来实现高可用。
高性能增加机器的目的在于 “扩展” 处理性能,高可用增加机器目的在于 “冗余” 处理单元。
计算高可用
计算 指业务的 逻辑处理 。
- 需要增加一个 任务分配器
- 任务分配器和真正的业务服务器之间有连接和交互,需要选择合适的连接方式,并且对连接进行管理
- 任务分配器需要增加分配算法。常见的双机算法有 主备、主主 ,主备方案有可以细分为 冷备、温备、热备
存储高可用
存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响。
CAP 定理: 存储高可用不可能同时满足 “一致性、可用性、分区容错性”,最多满足其中两个。
高可用状态决策
- 独裁式:存在一个独立的决策主体,负责收集信息然后进行决策;所有冗余的个体,都将状态信息发送给决策主体。
- 协商式:两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策就是 主备决策 。
- 民主式:指多个独立的个体通过投票的方式来进行状态决策。民主式决策的系统一般采用 “投票节点数必须超过系统总节点数一半” 的规则来处理。
可扩展性
可扩展性系统 为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无需整个系统重构或重建。
设计具备良好可扩展性的系统,有两个基本条件:正确预测变化、完美封装变化 。
预测变化
预测变化的复杂性在于:
- 不能每个设计点都考虑可扩展性
- 不能完全不考虑可扩展性
- 所有的预测都存在出错的可能性
应对变化
- 系统需要查分出变化层和稳定层
- 需要设计变化层和稳定层之间的接口
低成本、安全、规模
低成本
低成本很多时候不是架构设计的首要目标,而是架构设计的附加约束。
低成本给架构设计带来的主要复杂度体现在,往往只有 “创新” 才能达到低成本目标。
安全
安全可以分为两类:一类是功能上的安全,一类是架构上的安全 。
- 功能安全 :更多地是和具体的编码相关,与架构关系不大。
- 架构安全 :传统的架构安全主要依靠防火墙。互联网系统的架构安全更多地依靠运营商或者云服务商强大的带宽和流量清洗的能力。
规模
规模带来复杂度的主要原因就是 “量变引起质变”。
- 功能越来越多,导致系统复杂度指数级上升。
- 数据越来越多,系统复杂度发生质变。
架构设计三原则
合适原则、简单原则、演化原则
- 合适优于业界领先
- 简单优于复杂
- 演化优于一步到位
软件架构需要根据业务发展不断变化。
- 设计出来的架构要满足当时的业务需要
- 架构要不断地在实际应用过程中迭代,保留优秀的设计,修复有缺陷的设计,改正错误的设计,去掉无用的设计,使得架构逐渐完善
- 当业务发生变化时,架构要扩展、重构,甚至重写;代码或许会重写,但有价值的经验、教训、逻辑、设计等却可以在新架构中延续。
架构师在进行架构设计时需要牢记这个原则,时刻提醒自己不要贪大求全,或者盲目照搬大公司的做法。应该认真分析当前业务的特点,明确业务面领的主要问题,设计合理的架构,快速落地地以满足业务需要,然后在运行过程中不断完善架构,不断随着业务演化架构。
架构设计流程
识别复杂度
将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。
设计备选方案
- 常见错误:设计最优秀的方案
- 常见错误:只做一个方案
- 备选方案的数量以 3 ~ 5 个为最佳
- 备选方案的差异要比较明显
- 备选方案的技术不要只局限于已经熟悉的技术
- 常见错误:备选方案过于详细
评估和选择备选方案
- 最简派:挑选一个看起来最简单的方案。
- 最牛派:挑选技术上看起来最牛的方案
- 最熟派:挑选最熟悉的方案
- 领导派:领导选择方案
正确做法是 按优先级选择 ,即架构师综合当前的业务发展情况,团队成员规模和技能、业务发展预测等因素,将质量属性按照优先级排序,首先挑选满足第一优先级的,如果方案都满足,那就再看第二优先级 … 以此类推。
详细方案设计
- 架构师不但要进行备选方案设计和选型,还需要对备选方案的关键细节有较深入的理解。
- 通过分步骤、分阶段、分系统等方式,尽量降低方案的复杂度。
- 如果方案本身就很复杂,那就采取 设计团队 的方式来进行设计。
高性能数据库集群
读写分离
本质是将访问压力分散到集群中的多个节点,但是没有分散存储压力。
原理
将数据库读写操作分散到不同的节点上。
基本实现
- 数据库服务器搭建主从集群,一主一从、一主多从都可以
- 数据库主机负责读写操作,从机只负责读操作
- 数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据
- 业务服务器将写操作发给数据库主机,将读操作发送给数据库从机
复制延迟
解决主从复制延迟有几种常见的方法:
- 写操作后的读操作指定发给数据库主服务器
- 读从机失败后再读一次主机
- 关键业务读写操作全部指向主机,非关键业务采用读写分离
分配机制
程序代码封装:指在代码中抽象一个数据访问层(有的文章也成这种方式为 “中间层封装” ),实现读写操作分离和数据库服务器连接的管理。
- 实现简单,可以根据业务做较多定制化功能。
- 每个编程语言都需要自己实现一次,无法通用。
- 故障情况下,如果主从发生切换,则可能需要所有系统都修改配置并重启。
中间件封装:指的是独立一套系统出来,实现读写操作分离和数据库服务器连接的管理。
- 能够支持多种编程语言
- 数据库中间件要支持完整的 SQL 语法和数据库服务器的协议,实现比较复杂
- 数据库中间件自己不执行真正的读写操作,但所有的数据库操作请求都要经过中间件,性能要求很高
- 数据库主从切换对业务服务器无感知,数据库中间件可以探测数据库服务器的主从状态
分库分表
业务分库
业务分库指的是按照业务模块将数据分散到不同的数据库服务器。
join操作问题:业务分库后,原本在同一个数据库中的表分散到不同的数据库中,导致无法使用 SQL 的join查询。- 事务问题:原本在同一数据库中不同的表可以在同一事务中修改,业务分库后,表分散到不同的数据库中,无法通过事务统一修改。
- 成本问题
分表
单表数据拆分有两种方式:垂直分表 和 水平分表 。
单表进行切分后,是否要将切分后的多个表分散在不同的数据库服务器中,可以根据实际的切分效果来确定,并不强制要求单表切分为多表后一定要分散到不同的数据库中。
- 垂直分表:适合将表中某些不常用且占了大量空间的列拆分出去。垂直分表引入的复杂性主要体现在表操作的数量要增加。
- 水平分表:水平分表适合表行数特别大的表。
高性能 NoSQL
常见的 NoSQL 方案分为 4 类:
- K - V 存储:解决关系数据库无法存储数据结构的问题,以 Redis 为代表。
- 文档数据库:解决关系数据库强 schema 约束的问题,以 MongoDB 为代表。
- 列式数据库:解决关系数据库大数据场景下的 I/O 问题,以 HBase 为代表。
- 全文搜索引擎:解决关系数据库的全文搜索性能问题,以 Elasticsearch 为代表。
K - V 存储
K - V 存储的全称是 Key - Value 存储 ,其中 Key 是数据的标识,和关系数据库的主键含义一样,Value 就是具体的数据。
Redis 的缺陷主要体现在并不支持完整的 ACID 事务,Redis 的事务只能保证隔离型和一致性(I 和 C),无法保证原子性和持久性(A 和 D)。
文档数据库
文档数据库可以存储和读取任意的数据。目前绝大部分文档数据库的数据格式 JSON。文档数据库的缺点是不支持事务和无法实现关系数据库的 join 操作。
列式数据库
列式数据库就是按照列来存储数据的数据库。
除了节省 I/O,列式存储还具备更高的存储压缩比,能够节省更多的存储空间。一般将列式存储应用在离线的大数据分析和统计场景中,因为这种场景主要是针对部分列单列进行操作,且数据写入后就无须再进行更新删除。
全文搜索引擎
技术原理被称为 “倒排索引(Inverted Index),也常被称为 反向索引、置入档案或反向档案 。其基本原理是 建立单词到文档的索引。
高性能缓存架构
缓存就是为了弥补存储系统在这些复杂业务场景下的不足,其基本原理是将可能重复使用的数据放到内存中,一次生成、多次使用,避免每次使用都去访问存储系统。
- 缓存穿透:指缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去存储系统查询数据。
- 存储数据不存在
- 缓存数据生成耗费大量时间或者资源
- 缓存雪崩:指当缓存失效(过期)后引起系统性能急剧下降的情况。
- 更新锁
- 后台更新
- 缓存热点:解决方案是复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力。不同的缓存副本不要设置统一的过期时间,否则会出现所有缓存副本同时生成同时失效的情况,从而引发缓存雪崩效应。
单服务器高性能模式
单服务器高性能的关键之一就是 服务器采取的并发模型 。
PPC
PPC 是 Process Per Connection 的缩写,其含义是指每次有新的连接就新建一个进程去专门处理这个连接的请求。
- 父进程接受连接
- 父进程 “fork” 子进程
- 子进程处理连接的读写请求
- 子进程关闭连接
Prefork
Prefork 就是提前创建进程。系统在启动的时候就预先创建好进程,然后才开始接受用户的请求。
TPC
TPC 是 Thread Per Connection 的缩写,其含义是指每次都有新的连接就新建一个线程去专门处理这个连接的请求。
- 父进程接受连接
- 父进程创建子线程
- 子线程处理连接的读写请求
- 子线程关闭连接
Prethread
Prethread 模式会预先创建线程,然后才开始接受用户的请求。
Reactor
Reactor 模式 也叫 Dispatcher 模式 ,核心组成部分包括 Reactor 和 处理资源池 ,其中 Reactor 负责监听和分配事件,处理资源池负责处理事件。
- 单 Reactor 单进程 / 线程
- 单 Reactor 多线程
- 多 Reactor 多进程 / 线程
Proactor
异步网络模型,可以理解为 “来了事件我处理,处理完了我通知你” 。
高性能负载均衡
高性能集群的复杂性主要体现在需要增加一个任务分配器,以及为任务选择一个合适的任务分配算法。
负载均衡分类
DNS 负载均衡
DNS 是最简单也是最常见的负载均衡方式,一般用来实现地理级别的均衡。
DNS 负载均衡实现简单、成本低,但也存在粒度太粗、负载均衡算法少等缺点。
硬件负载均衡
硬件负载均衡 是通过单独的硬件设备来实现负载均衡功能,这类设备和路由器、交换机类似,可以理解为一个用于负载均衡的基础网络设备。业界典型的负载均衡设备有两款:F5 和 A10 。
软件负载均衡
软件负载均衡 通过负载均衡软件来实现负载均衡功能,常见的有 Nginx 和 LVS ,其中 Nginx 是软件的 7 层负载均衡,LVS 是 Linux 内核的 4 层负载均衡。
负载均衡典型架构
DNS 负载均衡用于实现地理级别的负载均衡;硬件负载均衡用于实现集群级别的负载均衡 ;软件负载均衡用于实现机器级别的负载均衡。
算法
- 任务平分类:负载均衡系统将收到的任务平均分配给服务器进行处理。
- 负载均衡类:负载均衡系统根据服务器的负载来进行分配。
- 性能最优类:负载均衡系统根据服务器的响应时间来进行任务分配,优先将新任务分配给响应最快的服务器。
- Hash 类:负载均衡系统根据任务中的某些关键信息进行 Hash 运算,将相同 Hash 值的请求分配到同一台服务器上。
轮询
负载均衡系统收到请求后,按照顺序轮流分配到服务器上。
加权轮询
负载均衡系统根据服务器权重进行任务分配,这里的权重一般是根据硬件配置进行静态配置的,采用动态的方式计算会更加契合业务,但复杂度也会更高。主要目的是为了解决不同服务器处理能力有差异的问题。
负载最低优先
负载均衡系统将任务分配给当前负载最低的服务器。
性能最优类
站在客户端的角度来进行分配,优先将任务分配给处理速度最快的服务器。
Hash 类
负载均衡系统根据任务中的某些关键信息进行 Hash 运算,将相同 Hash 值的请求分配到同一台服务器上,这样做的目的主要是为了满足特定的业务需求。
CAP 理论
CAP 定理(CAP Theorem),又被称作 布鲁尔定理(Brewer’s Theorem)。
在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。
- 一致性:对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。
- 可用性:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。
- 分区容忍性:当出现网络分区后,系统能够继续 “履行职责”。
分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构。
CAP 关键细节点
- CAP 关注的粒度是 数据 ,而不是整个系统。
- CAP 是忽略网络延迟的。
- 正常运行情况下,不存在 CP 和 AP 的选择,可以同时满足 CA 。
ACID
ACID 是数据库管理系统为了保证事务的正确性而提出来的一个理论。
- Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会在中间某个环节结束。事务在执行过程中发生错误,会被回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
- Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
- Isolation(隔离性):数据库允许多个并发事务同时对数据进行读写和修改的能力。隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
- Durability(持久性):事务处理结束后,对数据的修改就是永久的,即使系统故障也不会丢失。
BASE
BASE 是指 基本可用(Basically Available)、软状态(Soft State)、最终一致性(Eventual Consistency) ,核心思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但应用可以采用合适的方式达到最终一致性。
- 基本可用:分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
- 软状态:允许系用存在中间状态,而该中间状态不会影响系统整体可用性。
- 最终一致性:系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。
FMEA 方法
FMEA(Failure Mode and Effects Analysis,故障模式与影响分析)又称为失效模式与后果分析、失效模式与效应分析、故障模式与后果分析等。
具体分析方法
- 给出初始的架构设计图
- 假设架构中某个部件发生故障
- 分析此故障对系统功能造成的影响
- 根据分析结果,判断架构是否需要进行优化
FEMA 分析表格
- 功能点:当前的 FEMA 分析涉及的功能点,注意这里的 “功能点” 指的是从用户角度来看的。
- 故障模式:故障模式指的是系统会出现怎么样的故障,包括故障点和故障形式。
- 故障影响:当发生故障模式中描述的故障时,功能点具体会受到什么影响。
- 严重程度:指站在业务的角度故障的影响程度。
- 故障原因
- 故障概率:硬件、开源系统、自研系统。
- 风险程度:就是综合严重程度和故障概率来一起判断某个故障的最终等级。
- 已有措施:检测告警、容错、自恢复。
- 规避措施:技术手段、管理手段。
- 解决措施
- 后续规划
高可用存储架构
双机架构
- 主备复制
- 主从复制:主机负责读写操作,从机只负责读操作,不负责写操作。
- 双机切换:互连式、中介式、模拟式
- 主主复制:两台机器都是主机,互相将数据复制给对方。
数据集群
- 数据集中集群:一主多备、一主多从。
- 数据分散集群:均衡性、容错性、可伸缩性。
数据分区
- 数据量
- 分区规则
- 复制规则 : 集中式、互备式和独立式。
设计
主备
- 冷备:备机上的程序包和配置文件都准备好,但备机上的业务系统没有启动(备机的服务器是启动的),主机故障后,需要人工手工将备机的业务系统启动,并将任务分配器的任务请求切换发送给备机。
- 温备:备机上的业务系统已经启动,只是不对外提供服务,主机故障后,人工只需要将任务分配器的任务请求切换发送到备机即可。
主从
- 正常情况下,主机执行部分计算任务,备机执行部分计算任务。
- 当主机故障时,任务分配器不会自动将原本发送给主机的任务发送给从机,而是继续发送给主机,不管这些任务是否成功。
- 如果主机能够恢复,任务分配器继续按照原有的设计策略分配任务。
- 如果主机不能够恢复,则需要人工操作,将原来的从机升级为主机,增加新的机器作为从机,新的从机准备就绪后,任务分配器继续按照原有的设计策略分配任务。
集群
- 对称集群:更通俗叫法是 负载均衡集群。
- 正常情况下,任务分配器采取某种策略将计算任务分配给集群中的不同服务器。
- 当集群中的某台服务器故障后,任务分配器不再将任务分配给它,而是将任务分配给其他服务器执行。
- 当故障的服务器恢复后,任务分配器重新将任务分配给它执行。
- 非对称集群:
- 集群会通过某种方式来区分不同服务器的角色。
- 任务分配器将不同任务发送给不同服务器。
- 当制定类型的服务器故障时,需要重新分配角色。
异地多活架构
异地多活架构 可以分为 同城异区、跨城跨区、跨国异地 。
- 同城异区:指的是将业务部署在同一个城市不同区的多个机房。
- 跨城异地:指的是业务部署在不同城市的多个机房,而且距离最好要远一些。
- 跨国异地:指的是业务部署在不同国家的多个机房。
技巧
- 保证核心业务的异地多活
- 优先实现核心业务的异地多活架构
- 保证核心数据最终一致性
- 数据同步是异地多活架构设计的核心
- 尽量减少异地多活机房的距离,搭建高速网络
- 尽量减少数据同步,只同步核心业务相关的数据
- 保证最终一致性,不保证实时一致性
- 采用多种手段同步数据
- 消息队列方式
- 二次读区方式
- 存储系统同步方式
- 回源读取方式
- 重新生成数据方式
- 只保证绝大部分用户的异地多活
步骤
- 业务分级:
- 访问量大的业务
- 核心业务
- 产生大量收入的业务
- 数据分类:
- 数据量
- 唯一性
- 实时性
- 可丢失性
- 可恢复性
- 数据同步:
- 存储数据同步
- 消息队列同步
- 重复生成
- 异常处理:
- 多通道同步
- 同步和访问结合
- 日志记录
- 用户补偿
应对接口级故障
接口级故障的典型表现就是系统并没有宕机,网络也没有中断,但业务却出现问题了。
解决方法
优先保证核心业务和优先保证绝大部分用户。
降级:指系统将某些业务或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能。
- 系统后门降级
- 独立降级系统
熔断:目的在于应对依赖的外部系统故障的情况。关键是 需要有一个统一的 API 调用层 ,由 API 调用层来进行采样或者统计。另一个关键是 阈值的设计 。
限流:从用户访问压力的角度来考虑如何应对故障。限流指只允许系统能够承受的访问量进来,超出系统访问能力的请求将被丢弃。
- 基于请求限流:限制某个指标的累积上限,常见的是限制当前系统服务的用户总量。限制时间量指限制一段时间内某个指标的上限。
- 基于资源限流:找到系统内部影响性能的关键资源,对其使用上进行限制。
排队:由于排队需要临时缓存大量的业务请求,单个系统内部无法缓存这么多数据,一般情况下,排队需要用独立的系统去实现。
可扩展架构
分层架构
- C / S 架构、B / S 架构:划分的对象是整个业务系统,划分的维度是用户交互,即将和用户交互的部分独立为一层,支撑用户交互的后台作为另外一层。
- MVC 架构、MVP 架构
- 逻辑分层架构:逻辑分层架构中的层是自顶向下依赖的。
分层架构设计最核心的一点就是需要保证各层之间的差异足够清晰,边界足够明显,让人看到架构图后就能看懂整个架构。分层架构之所以能够较好地支撑系统扩展,本质在于 隔离关注点(Separation of Concerns)。另外一个特点是 层层传递。
SOA
SOA 的全称是 Service Oriented Architecture,中文翻译为 “面向服务的架构”。
SOA 出现的背景是企业内部的 IT 系统重复建设且效率低下。
三个关键概念
- 服务:所有业务功能都是一项服务,服务就意味着要对外提供开放的能力,当其他系统需要使用这项功能时,无须定制化开发。
- ESB:ESB 的全称是 Enterprise Service Bus ,中文翻译为 “企业服务总线” 。SOA 使用 ESB 来屏蔽异构系统对外提供各种不同的接口方式,以此来达到服务间高效的互联互通。
- 松耦合:目的是减少各个服务间的依赖和互相影响。
微服务架构
- 微服务是 SOA 的实现方式
- 微服务是去掉 ESB 后的 SOA
- 微服务是一种和 SOA 相似但本质上不同的架构理念
基础设施
- 自动化测试:代码级的单元测试、单个系统级的继承测试、系统间的接口测试
- 自动化部署:版本管理、资源管理、部署操作、回退操作
- 配置中心:配置版本管理、增删改查配置、节点管理、配置同步、配置推送等功能
- 接口框架:一般以库或者包的形式提供给所有微服务调用。
- API 网关:是外部系统访问的接口,所有的外部系统接入系统都需要通过 API 网关、主要包括接入鉴权、全县控制、传输加密、请求路由、流量控制
- 服务发现:核心功能是服务注册表,注册表记录了所有的服务节点的配置和状态,每个微服务启动后都需要将自己的信息注册到服务注册表,然后由微服务或者 LOAD BANLANCER 系统到服务注册表查询可用服务。
- 自理式
- 代理式:微服务之间有一个负载均衡系统,由负载均衡系统来完成微服务之间的服务发现。
- 服务路由:从所有符合条件的可用微服务节点中挑选出一个具体的节点发起请求。
- 服务容错:请求重试、流控和服务隔离。
- 服务监控:
- 实时收集信息并进行分析,避免故障后再来分析,减少了处理时间
- 服务监控可以在实时分析的基础上进行预警,在问题萌芽的阶段发觉并预警,降低了问题影响的范围和时间
- 服务跟踪
- 服务安全
- 接入安全
- 数据安全
- 传输安全
微内核架构
微内核架构(Microkernel Architecture),也被称为 插件化架构(Plug-in Architecture),是一种面向功能进行拆分的可扩展性架构,通常用于实现基于产品的应用。
基本架构
微内核架构包含两类组件:核心系统(Core System)和插件模块(Plug-in Modules)。核心系统负责和具体业务功能无关的通用功能,插件模块负责实现具体的业务逻辑。
微内核的架构本质就是 将变化部分封装在插件里面,从而达到快速灵活扩展的目的,而又不影响整体系统的稳定。
设计关键点
- 插件管理:
- 插件注册表机制:插件系统提供插件注册表(可以是配置文件,也可以是代码,还可以是数据库),插件注册表含有每个模块的信息,包括它的名字,位置,加载时机等。
- 插件连接:插件连接指插件如何连接到核心系统。常见的连接机制由 OSGi、消息模式、依赖注入,甚至使用分布式的协议都是可以的,比如 RPC 或者 HTTP Web 的方式。
- 插件通信:指插件间的通信。
OSGi 架构简析
OSGi 的全称是 Open Services Gateway initiative。
逻辑架构
- 模块层:实现插件的管理功能。
- 生命周期层:实现插件连接功能,提供了执行时模块管理、模块对底层 OSGi 框架的访问。
- 服务层:实现插件通信的功能。
互联网架构模版
存储层技术
- SQL:Oracle、MySQL、PostgreSQL;DBProxy、TDDL、MySQL Router、Atlas
- NoSQL:Memcache、Redis、MongoDB
- 小文件存储:HBase、Hadoop、Hypertable、FastDFS;TFS、JFS、Haystack
- 大文件存储:Bigtable、MapReduce、GFS;HDFS、HBase
开发层技术
- 开发框架:优选成熟的框架,避免盲目追逐新技术
- Web 服务器:Tengine;Tomcat、JBoss、Resin;Nginx;Apache
- 容器:Docker
服务层技术
- 配置中心:集中管理各个系统的配置
- 服务中心:解决跨系统依赖的配置和调度问题
- 服务名字系统
- 服务总线系统
- 消息队列:实现跨系统异步通知的中间件系统,如 RocketMQ,Kafka,ActiveMQ
网络层技术
- 负载均衡:
- DNS:地理级别的均衡,HTTP - DNS。
- Nginx、LVS、F5
- CDN:分布式存储、全局负载均衡、网络重定向、流量控制等
- 多机房:
- 同城多机房
- 跨城多机房
- 跨国多机房
- 多中心
用户层技术
- 用户管理:
- 单点登录(SSO),统一登录:cookie、JSONP、token;CAS
- 授权登录:OAuth 2.0
- 消息推送:设备管理(唯一标识、注册、注销)、连接管理和消息管理;APNS、GCM
- 存储云、图片云:CDN + 小文件存储
- 业务层技术
平台技术
- 运维平台:标准化、平台化、自动化、可视化
- 配置:负责资源的管理。
- 部署:负责将系统发布到线上。
- 监控:负责收集系统上线运行后的相关数据并进行监控,以便及时发现问题。
- 应急:负责系统出故障后的处理。
- 测试平台:
- 用例管理
- 资源管理
- 任务管理
- 数据管理
- 数据平台:
- 数据管理:
- 数据采集:从业务系统收集各类数据。
- 数据存储:将从业务系统采集的数据存储到数据平台,用于后续数据分析。
- 数据访问:负责对外提供各种协议用于读写数据。
- 数据安全:通常情况下数据平台都是多个业务共享的,部分业务敏感数据需要加以保护,防止被其他业务读取甚至修改,因此需要设计数据安全策略来保护数据。
- 数据分析:
- 数据统计:根据原始数据统计出相关的总揽数据。
- 数据挖掘
- 机器学习、深度学习
- 数据应用
- 数据管理:
- 管理平台:核心职责就是权限管理
- 身份认证
- 权限控制
架构重构
架构师的首要任务是 从一大堆纷繁复杂的问题中识别出真正要通过架构重构来解决的问题,集中力量快速解决,而不是想着通过架构重构来解决所有问题 。
开源项目
如何选择开源项目
- 聚焦是否满足业务:聚焦于是否满足业务,而需要过于关注开源项目是否优秀。
- 聚焦是否成熟:尽量选择成熟的开源项目,降低风险。
- 聚焦运维能力:
- 开源项目日志是否齐全
- 开源项目是否有命令行、管理控制台等维护工具,能够看到系统运行时的情况
- 开源项目是否有故障检测和恢复的能力,例如告警、切换等
如何使用开源项目
- 深入研究,仔细测试:
- 通读开源项目的设计文档或者白皮书,了解其设计原理。
- 核对每个配置项的作用和影响,识别出关键配置项。
- 进行多种场景的性能测试。
- 进行压力测试,连续跑几天,观察 CPU、内存、磁盘 I/O 等指标波动。
- 进行故障测试:kill、断电、拔网线、重启 100 次以上、切换等。
- 小心应用,灰度发布:再怎么深入地研究,再怎么仔细地测试,都只能降低风险,但不可能完全覆盖所有线上场景。
- 做好应急,以防万一
如何基于开源项目做二次开发
- 保持纯洁,加以包装:不要改动原系统,而是要开发辅助系统
- 发明你要的轮子
架构设计文档模版
备选文档模版
- 需求介绍:主要描述需求的背景、目标、范围等。
- 性能问题
- 耦合问题
- 效率问题
- 需求分析:主要全方位地描述需求相关的信息。
- Who:需求利益干系人,包括开发者、使用者、购买者、决策者等。
- When:需求使用时间,包括季节、时间、里程碑等。
- What:需求的产出是什么,包括系统、数据、文件、开发库、平台等。
- Where:需求的应用场景,包括国家、地点、环境等,例如测试平台只会在测试环境使用。
- Why:需求需要解决的问题,通常和需求背景相关。
- How:关键业务流程。
- 8 个约束和限制,Constraints:性能(Performance)、成本(Cost)、时间(Time)、可靠性(Reliability)、安全性(Security)、合规性(Compliance)、技术型(Technology)、兼容性(Compatibility)。
- 复杂度分析:分析需求的复杂度,复杂度常见的有高可用、高性能、可扩展等。
- 备选方案:至少 3 个备选方案,每个备选方案需要描述关键的实现,无须描述具体的实现细节。
- 备选方案评估:架构师首先给出自己的备选方案评估,然后举行备选方案评估会议,再根据会议结论修改备选方案文档。
架构设计模版
备选方案评估后会选择一个方案落地实施,架构设计方案就是用来详细描述细化方案的。
- 总体方案:需要从整体上描述方案的结构,其核心内容就是架构图,以及针对架构图的描述,包括模块或者子系统的职责描述、核心流程。
- 架构总览:给出架构图以及架构的描述。
- 核心流程:
- 消息发送流程
- 消息读取流程
- 详细设计:描述具体的实现细节
- 高可用设计
- 消息发送可靠性
- 消息存储可靠性
- 消息读取可靠性
- 高性能设计
- 可扩展设计
- 安全设计
- 身份识别
- 队列权限
- 其他设计
- 部署方案:硬件要求、服务器部署方式、组网方式等。
- 架构演进规划
- 高可用设计