《从零开始学架构》读书笔记
2022-07-30 18:28:44 0 举报
AI智能生成
《从零开始学架构》的读书笔记,你将获得:1、理解架构设计的本质和目的;2、掌握高性能和高可用架构模式;3、从编程到架构,实现思维跃迁
作者其他创作
大纲/内容
为什么技术能力强,业务能力不错,但架构设计一般??
架构设计的关键思维是:判断和取舍(Trade-Off),结果没有标准答案
程序设计的关键思维是:逻辑和实现,结果非常明确
架构设计 vs 程序设计
架构设计:目前没有体系化的培训和训练机制
要成为架构师必须要有很强的技术天分
架构师必须有很强的创造力
架构设计必须要高大上才能体现架构师能力
架构一定要具备高可用、高性能
程序员对架构设计的理解存在很多误区
原因总结
架构师需要形成自己的一套架构设计方法论
开篇词
要想准确地理解架构的定义,关键就在于把如下三组容易混淆的概念梳理清楚
系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体
它的意思是“总体”、“整体”或“联盟”
系统能力不是个体能力之和,而是产生了新的能力
系统
子系统的定义和系统定义是一样的
只是观察的角度有差异,一个系统可能是另外一个更大系统的子系统
子系统
一个系统的架构,只包括顶层这一个层级的架构,而不包括下属子系统层级的架构,即所谓的顶层设计
系统与子系统
模块和组件都是系统的组成部分,只是从不同的角度拆分系统而已
从业务逻辑的角度来拆分系统
主要目的:职责分离
模块
从物理部署的角度来拆分系统
主要目的:单元复用
组件
架构师:首先从业务逻辑的角度把系统拆分成一个个模块角色,其次从物理部署的角度把系统拆分成组件角色
模块与组件
框架是一整套开发规范
架构是某一套开发规范下的业务的具体落地方案,包括各个模块之间的组合关系以及它们协同起来完成功能的运作规则
框架与架构
软件架构指软件系统的顶层(Rank)结构,它定义了系统由哪些角色(Role)组成,角色之间的关系(Relation)和运作规则(Rule)
软件架构是分层的,对应“系统”和“子系统”的分层关系
通常情况下,我们只需要关注某一层的架构,最多展示相邻两层的架构,而不需要把每一层的架构全部糅杂在一起
无论是架构设计还是画架构图,都应该采取“自顶向下,逐步细化”的方式
Rank:层级
软件系统包含哪些角色,每个角色都会负责系统的一部分功能
Role:角色
软件系统的角色之间的关系,对应到架构图中其实就是连接线
Relation:关系
软件系统角色之间如何协作来完成系统功能
Rule:规则
“4R架构”方法论
通过 系统架构图 来展示
通过 系统序列图 来展示
外框
架构到底是指什么?
直接使用二进制码 0 和 1 来表示机器可以识别的指令和数据
太难写、太难读、太难改!
机器语言(1940 年之前)
用助记符代替机器指令的操作码,用地址符号代替指令或操作数的地址
本质上还是面向机器的
不同 CPU 的汇编指令和结构是不同的,相同的逻辑汇编代码不相同
汇编语言(20 世纪 40 年代)
Fortran、LISP、Cobol等等
让程序员不需要关注机器底层的低级结构和逻辑,而只要关注具体的问题和业务即可
通过编译程序的处理,高级语言可以被编译为适合不同 CPU 指令的机器语言
高级语言(20 世纪 50 年代)
第一次软件危机的根源在于软件的“逻辑”变得非常复杂
软件质量低下、项目无法如期完成、项目严重超支等
因为软件而导致的重大事故时有发生
抛弃 goto 语句
自顶向下、逐步细化、模块化
将软件的复杂度控制在一定范围内,从而从整体上降低了软件开发的复杂度
结构化程序设计方法
结构化程序设计(面向过程):C语言
第一次软件危机与结构化程序设计(20 世纪 60 年代~20 世纪 70 年代)
面向对象与面向过程的区别
第二次软件危机主要体现在软件的“扩展”变得非常复杂
结构化程序设计虽然能够缓解软件逻辑的复杂性,但是对于业务变化带来的软件扩展却无能为力
面向对象:C++、Java、C#
第二次软件危机与面向对象(20 世纪 80 年代)
“软件架构”出现的背景并不是整个行业都面临类似相同的问题
“软件架构”也不是为了解决新的软件危机而产生的
系统规模庞大,内部耦合严重,开发效率低
系统耦合严重,牵一发动全身,后续修改和扩展困难
系统逻辑复杂,容易出问题,出问题后很难排查和修复
只有大公司开发的规模较大的软件系统才会面临软件架构相关的问题
结构化编程,创造了“模块”概念
面向对象编程,创造了“对象”概念
软件架构,创造了“组件”概念
软件架构的历史背景(从 20 世纪 90 年代开始)
差别在于随着软件的复杂度不断增加,拆分的粒度越来越粗,拆分的层次越来越高
架构设计的历史背景
架构设计的主要目的是为了解决软件系统复杂度带来的问题
架构设计的目的
按照 机器硬件 -> 操作系统 -> 软件程序 的顺序,性能逐渐损耗变低
进程:操作系统资源分配的最小单位
线程:操作系统调度的最小单位
进程 vs 线程
并发:分时系统,不是真正的多任务同时处理
并行:多核系统,真正的多任务同时处理
并发 vs 并行
单服务器的多个CPU对称工作,无主次或从属关系
资源共享,如CPU、内存、I/O等
SMP:Symmetric Multi-Processor,对称多处理器结构
利用NUMA技术,把多个CPU组合在一台机器中,而每个CPU可以访问整个系统的内存
访问异地内存的时延远远超过访问本地内存
当CPU数量增加时,系统性能无法线性增加
NUMA:Non-Uniform Memory Access,非一致存储访问结构
MPP是由多台SMP服务器通过一定的节点互联网络进行连接,协同工作,完成相同的任务,从用户的角度来看是一个服务器系统
例如:Hadoop
MPP:Massive Parallel Processing,海量并行处理结构
商用服务器的三种分类
并行的三种解决方案
单机复杂度
每台机器可以处理完整的任务,不同的任务分配到不同的机器上执行
增加任务分配器
任务分配器和真正的业务服务器之间的连接管理
分配算法
复杂度主要体现
任务分配
每台机器无法处理完整的任务,需要多台机器协作完成处理
大业务拆分成多个子业务,每个子业务是一个子系统
子系统之间的协作调度处理
任务分解
集群复杂度
复杂度来源1:高性能
定义:系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一
高性能增加机器目的在于“扩展”处理性能
高可用增加机器目的在于“冗余”处理单元
系统的高可用方案,本质上是通过“冗余”来实现
通过冗余增强了可用性,但同时也带来了复杂性,主要体现在如下3点:
计算是无状态的
计算高可用
存储是有状态的,存在数据同步问题(一致性问题)
存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响
CAP 定理
存储高可用
通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确
独裁式:单点问题
协商式:例如,主备决策,信息交换出问题(主备连接中断)
民主式:例如,投票选举,多数取胜,存在脑裂问题
几种常见的决策方式
对于多个任务分配器节点,如何选出主节点
对于主节点,需要判断业务服务器是否可用
状态决策
高可用状态决策
复杂度来源2:高可用
定义:系统为了应对需求变化而提供的一种扩展能力,系统不需要或者仅需要少量修改就可以支持
正确预测变化
完美应对变化
设计具备良好可扩展性的系统,有两个基本条件
不能每个设计点都考虑可扩展性
不能完全不考虑可扩展性
所有的预测都存在出错的可能性
预测变化的复杂性
提炼出“变化层”和“稳定层”
提炼出“抽象层”和“实现层”
应对变化的复杂性
1 写:新业务能否活下还不确定,暂不考虑太多可扩展性,直接实现业务
2 抄:业务前景还不明朗,暂不考虑太多可扩展,直接copy代码实现业务
3 重构:业务发展不错(活下来了),考虑重构系统,支持快速扩展
1 写 2 抄 3 重构原则
复杂度来源3:可扩展性
只预测 2 年内的可能变化,不要试图预测 5 年甚至 10 年后的变化
低成本 与高性能、高可用是冲突的,是架构设计的附加约束
往往只有“创新”才能达到低成本目标
各种开源技术
云服务商提供的各种能力
小公司:基本都是靠引入新技术来达到低成本的目标
大公司:有足够的资源、技术和时间去创造新技术
复杂度来源4:低成本
“量变引起质变”
功能越来越多,导致系统复杂度指数级上升
数据越来越多,系统复杂度发生质变
复杂度体现在
复杂度来源5:规模
功能安全更多地是和具体的编码相关,与架构关系不大
功能安全
网络隔离:将网络划分成不同的区域
访问控制:不同区域之间的数据访问策略
传统的架构安全主要依靠防火墙
互联网的业务具有海量用户访问和高并发的特点,瞬时流量巨大
互联网系统的架构安全目前并没有太好的方案,更多地依靠运营商或者云服务商强大的带宽和流量清洗的能力
架构安全
复杂度来源6:安全
合适原则:“合适优于业界领先”
在建筑领域,“复杂”代表的是“领先”
在软件领域,“复杂”代表的是“问题”
简单原则:“简单优于复杂”
在建筑领域,“永恒”是主题
在软件领域,“变化”是主题
演化原则:“演化优于一步到位”
架构设计三原则
架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面
实际上大部分场景下,复杂度只是其中的某一个,少数情况下包含其中两个
架构设计第 1 步:识别复杂度
设计最优秀的方案
只做一个方案
方案过于详细
架构设计常见的错误
方案的数量以 3 ~ 5 个为最佳
方案的差异要比较明显
方案的技术不要只局限于已经熟悉的技术
架构师需要设计多个方案
架构设计第 2 步:设计备选方案
列出我们需要关注的质量属性点
分别从这些质量属性的维度去评估每个方案
再综合挑选适合当时情况的最优方案
架构设计第 3 步:评估和选择方案
将方案涉及的关键技术细节给确定下来
详细设计方案阶段可能遇到的一种极端情况:发现方案不可行
架构师不但要进行方案设计和选型,还需要对方案的关键细节有较深入的理解
通过分步骤、分阶段、分系统等方式,尽量降低方案复杂度
这种情况可以通过下面方式有效地避免
架构设计第 4 步:详细方案设计
基础架构
系统复杂度来源
架构设计流程
搭建主从集群:主机负责读写操作,从机只负责读操作
主机通过复制将数据同步到从机,每台机器都存储了所有的业务数据
业务将写操作发给主机,将读操作发给从机
基本实现
主从复制延迟带来的数据不一致问题
写操作后的读操作指定发给数据库主服务器
读从机失败后再读一次主机
关键业务读写操作全部指向主机,非关键业务采用读写分离
解决问题的3种思路
读写分离
按照业务模块将数据分散到不同的数据库服务器
join 操作问题
事务问题
成本问题
带来的问题
分库
适合将表中不常用且占了大量空间的列拆分出去
表与表之间通过外键关联
垂直分表
基于查询key进行数据切分,存储到不同的表中
水平分表
范围路由
Hash路由
配置路由
路由算法
join 操作
count 操作
order by 操作
水平分表相比垂直分表,会引入更多的复杂性
分表
分库分表
程序代码封装(SDK方案),例如:淘宝的TDDL(java)
中间件封装(数据库代理方案),例如:MySQL Router,360公司的Atlas
具体实现方案
关系型数据库集群
关系数据库存储的是行记录,无法存储数据结构
关系数据库的 schema 扩展很不方便
关系数据库在大数据场景下 I/O 较高
关系数据库的全文搜索功能比较弱
关系型数据库的4个缺点
KV存储:解决关系数据库无法存储数据结构的问题,以 Redis 为代表
文档数据库:解决关系数据库强 schema 约束的问题,以 MongoDB 为代表
列式数据库:解决关系数据库大数据场景下的 I/O 问题,以 HBase 为代表
全文搜索引擎:解决关系数据库的全文搜索性能问题,以 Elasticsearch 为代表
常见的4类NoSQL方案
NoSQL数据库
基本原理:将可能重复使用的数据放到内存中(一次生成、多次使用),避免每次使用都去访问存储系统
缓存没有发挥作用:业务系统去缓存中查询无数据,而再次去存储系统查询数据
对于真不存在的数据设置一个默认值存在缓存中
存储数据真不存在
没有好的解决方案
只能拆分缓存数据生成计算的逻辑
缓存数据生成耗费大量时间或者资源
缓存穿透
当缓存失效(过期)后引起系统性能急剧下降的情况
保证同一条数据同一时刻只有一个更新任务
分布式锁
解决方案1:更新锁机制
业务只读,数据由后台更新
解决方案2:后台更新
缓存雪崩
某些数据访问量巨大,缓存系统也扛不住
解决方案:缓存副本,减轻单台缓存机器的压力
缓存热点
缓存架构
每次有新的连接就新建一个进程去专门处理这个连接的请求
父进程接受连接
父进程“fork”子进程
子进程处理连接的读写请求:read、业务逻辑、write
子进程关闭连接
主要流程
fork 代价高
父子进程通信复杂
支持的并发连接数量有限
性能问题
PPC:Process Per Connection
每次有新的连接就新建一个线程去专门处理这个连接的请求
父进程创建子线程
子线程处理连接的读写请求:read、业务逻辑、write
子线程关闭连接
创建线程还是有一定代价的
线程间的互斥和共享问题
某个线程出现异常时,则整个进程退出
TPC:Thread Per Connection
Reactor = Reactor监听(I/O多路复用) + 处理资源池(线程池、进程池)
Reactor 对象通过 select 监控事件,收到事件后通过 dispatch 进行分发
如果是连接建立的事件,则由 Acceptor 处理,并创建一个 Handler 来处理连接后续的各种事件
如果不是连接建立事件,则由连接对应的 Handler 来处理
Handler 会完成 read-> 业务处理 ->send 的完整业务流程
优点:模式简单,没有进程间通信,没有进程竞争
无法发挥多核CPU的性能
Handler在处理业务时,无法接入新连接,存在性能瓶颈
缺点:只有1个进程
该模式只适合处理业务简单的场景,例如:redis
单 Reactor 单进程
主线程中,Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行分发
Handler 只负责响应事件,不进行业务处理;Handler 通过 read 读取到数据后,会发给 Processor 进行业务处理
Processor 会在独立的子线程中完成真正的业务处理,然后将响应结果发给主进程的 Handler 处理
Handler 收到响应后通过 send 将响应结果返回给 client
架构图
优点:充分利用多核多 CPU 的处理能力
多线程数据共享和访问比较复杂
Reactor(主线程)承担所有事件的监听和响应,瞬间高并发时会成为性能瓶颈
缺点
单 Reactor 多线程
父进程中 mainReactor 对象通过 select 监控连接建立事件,收到事件后通过 Acceptor 接收,将新的连接分配给某个子进程
子进程的 subReactor 将 mainReactor 分配的连接加入连接队列进行监听,并创建一个 Handler 用于处理连接的各种事件
当有新的事件发生时,subReactor 会调用连接对应的 Handler 来进行响应
Handler 完成 read→业务处理→send 的完整业务流程
父进程和子进程的职责非常明确:父进程只负责接收新连接,子进程负责完成后续的业务处理
父进程和子进程的交互很简单:父进程只需要把新连接传给子进程,子进程无须返回数据
子进程之间是互相独立的,无须同步共享之类的处理
优点
例如:Nginx 采用的是多 Reactor 多进程;Memcache、Netty采用的是多 Reactor 多线程
多 Reactor 多进程 / 线程
Reactor:反应堆模式
理论上 Proactor 比 Reactor 效率要高一些,异步 I/O 能够充分利用 DMA 特性,让 I/O 操作与计算重叠
但要实现真正的异步 I/O,操作系统需要做大量的工作
Windows 通过 IOCP 实现了真正的异步 I/O
Linux 没有实现真正的异步 I/O
Proactor
单服务器
DNS负载均衡:一般用来实现地理级别的均衡
硬件负载均衡:通过单独的硬件设备来实现,例如:F5 和 A10
软件负载均衡:通过负载均衡软件来实现,例如:Nginx(7层) 和 LVS(4层)
Nginx 的性能是万级;LVS 的性能是十万级
F5 性能是百万级
span style=\
价格:软件 > 硬件
软件一般不具备防火墙和防DDoS攻击等安全功能
硬件一般具备防火墙和防DDoS攻击等安全功能
安全:软件 < 硬件
扩展性:软件 > 硬件
软件 vs 硬件
分类
DNS负载均衡:用于实现地理级别的负载均衡
硬件负载均衡:用于实现集群级别的负载均衡
软件负载均衡:用于实现机器级别的负载均衡
典型架构
轮询:按照顺序轮流分配到服务器上
加权轮询:根据服务器权重进行任务分配
负载最低优先:将任务分配给当前负载最低的服务器
性能最优类:优先将任务分配给处理速度最快的服务器
Hash 类:为了满足特定的业务需求,根据任务中的某些关键信息的Hash计算值来分配
算法
服务器集群:负载均衡
高性能架构模式
存储高性能
计算高性能
分布式系统:互相连接并共享数据的节点的集合
涉及数据读写的操作
Consistence:一致性
Availability:可用性
Partition Tolerance:分区容错性
CAP三者只能取二
CAP理论定义要点
分布式环境下,因为网络本身无法做到 100% 可靠,我们必须选择 P(分区容忍)
分布式系统理论上不可能选择 CA 架构,只能选择 CP 或者 AP 架构
CAP应用
系统中的一部分数据可以选择CP、另一部分系统可以选择AP
CAP 关注的粒度是数据,而不是整个系统
理论上是不可能有完美的 CP 架构
分布式场景下,没有办法保证数据的强一致性,只能保证最终一致性
CAP 是忽略网络延迟的
正常运行情况下,不存在 CP 和 AP 的选择,可以同时满足 CA
放弃并不等于什么都不做,需要为分区恢复后做准备
CAP关键细节点
CAP理论
ACID 是数据库管理系统为了保证事务的正确性而提出来的一个理论
一个事务中的所有操作,要么全部完成,要么全部不完成
Atomicity:原子性
在事务开始之前和事务结束以后,数据库的完整性没有被破坏
Consistency:一致性
数据库允许多个并发事务同时对数据进行读写和修改的能力
Isolation:隔离性
事务处理结束后,对数据的修改就是永久的
Durability:持久性
ACID理论
BASE 是指基本可用(Basically Available)、软状态( Soft State)、最终一致性( Eventual Consistency)
分布式系统在出现故障时,允许损失部分可用性,即保证核心可用
Basically Available:基本可用
允许系统存在中间状态,而该中间状态不会影响系统整体可用性
这里的中间状态就是 CAP 理论中的数据不一致
Soft State:软状态
系统中的所有数据副本经过一定时间后,最终能够达到一致的状态
Eventual Consistency:最终一致性
CAP 理论是忽略延时的,而实际应用中延时是无法避免的
AP 方案中牺牲一致性只是指分区期间,而不是永远放弃一致性
BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充
BASE理论
主备间状态判断
切换决策
数据冲突解决
设计关键
互连式:主备机直接建立状态传递的渠道
中介式:在主备两者之外引入第三方中介(例如:ZooKeeper)
模拟式:备机模拟成一个客户端来判断主机状态
常见方案
主备复制、主从复制
主主复制指的是两台机器都是主机,互相将数据复制给对方
主主复制架构对数据的设计有严格的要求,较少使用
主主复制架构,一般适合于那些临时性、可丢失、可覆盖的数据场景
主主复制
双机架构
数据集中集群:1主N从
均衡性:每个节点上数据量尽量平均
容错性:当某个节点故障时,数据要转移到正常的节点上去
可伸缩性:当集群容量不够,扩充新的服务器后,数据再分配
数据分散集群:每个节点都会负责存储一部分数据
数据集中集群中,只有主机可以处理读写请求
数据分散集群中,每台服务器都可以处理读写请求
数据集中集群中,主机负责执行数据分配算法;主机可以是指定的(例如,Hadoop集群),也可以是选举出来的(例如,ElasticSearch集群)
数据集中集群 vs 数据分散集群
集群
数据分区:应对地理级别的故障
存储高可用架构
冷备:程序部署文件准备好了,但是没有启动运行
温备:程序已经启动运行,等待请求
主备:主机提供服务,备机不提供服务
主从:主机、从机都提供服务,需要有一个任务分配器
对称集群(负载均衡集群):服务器角色相同
集群会通过某种方式来区分不同服务器的角色
任务分配器将不同任务发送给不同服务器
当指定类型的服务器故障时,需要重新分配角色
非对称集群:服务器角色不同
计算高可用架构
同城异区:将业务部署在同一个城市不同区的多个机房
如果是强一致性要求的数据,实际上是无法做到跨城异地多活,而采用同城异区多活
强一致性要求的数据,例如:银行存款余额、支付宝余额等金融相关数据
跨城异地:业务部署在不同城市的多个机房
跨国异地:业务部署在不同国家的多个机房
异地多活架构
技巧 1:保证核心业务的异地多活
技巧 2:保证核心数据最终一致性,不保证实时一致性
技巧 3:采用多种手段同步数据
技巧 4:只保证绝大部分用户的异地多活
异地多活设计4大技巧
访问量大的业务
核心业务
产生大量收入的业务
第 1 步:业务分级
第 2 步:数据分类
存储系统同步
消息队列同步
重复生成
第 3 步:数据同步
多通道同步
同步和访问结合
日志记录
用户补偿
第 4 步:异常处理
异地多活设计4步走
降级是指系统将某些业务或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能
降级的目的是应对系统自身的故障
降级
熔断是指按照规则停掉外部接口的访问,防止某些外部接口故障导致自己的系统处理能力急剧下降或者出故障
熔断的目的是应对依赖的外部系统故障的情况
熔断
限流指只允许系统能够承受的访问量进来,超出系统访问能力的请求将被丢弃
限流的目的是应对访问压力过大的情况
基于请求限流:限制一段时间窗口内的请求总量
基于资源限流
常见的限流方式
时间窗
桶算法
令牌桶算法
限流算法
限流
超出系统访问能力的请求,不是丢弃,而是排队等待处理
排队:限流的变种
接口级别高可用
业务高可用架构
应对系统级的故障
应对接口级的故障
高可用架构模式
所有的可扩展性架构设计,背后的基本思想都可以总结为一个字:拆!
面向流程拆分:将整个业务流程拆分为几个阶段,每个阶段作为一部分
面向服务拆分:将系统提供的服务拆分,每个服务作为一部分
面向功能拆分:将系统提供的功能拆分,每个功能作为一部分
常见的三种拆分思路
面向流程拆分:应用层 → 传输层 → 网络层 → 物理 + 数据链路层
面向服务拆分:应用层有 HTTP、FTP、SMTP 等服务
面向功能拆分:HTTP 服务提供 GET、POST 等功能
以 TCP/IP 协议栈为例来讲
扩展时大部分情况只需要修改某一层
少部分情况可能修改关联的两层
不会出现所有层都同时要修改
面向流程拆分 -> 分层架构
对某个服务扩展,或者要增加新的服务时,只需要扩展相关服务即可
无须修改所有的服务
面向服务拆分 -> SOA、微服务
对某个功能扩展,或者要增加新的功能时,只需要扩展相关功能即可
面向功能拆分:微内核架构
不同的拆分方式,本质上决定了系统的扩展方式,得到不同的可扩展系统架构
可扩展架构的基本思想和模式
划分的维度是用户交互
划分的对象是整个业务系统
C/S 架构、B/S 架构
Model:数据模型层
View:展示层
Controller:控制层
划分的维度是职责
划分的对象是单个业务子系统
MVC 架构、MVP 架构
划分的对象可以是单个业务子系统,也可以是整个业务系统
划分的维度也是职责
逻辑分层架构中的层是自顶向下依赖的
逻辑分层架构
根据不同的划分维度和对象,可以得到多种不同的分层架构
保证各层之间的差异足够清晰,边界足够明显
层与层之间的依赖是稳定的(接口),而不是变化的(具体实现)
设计核心
一旦分层确定,整个业务流程是按照层进行依次传递的,不能跨层跳跃
好处:强制将分层依赖限定为两两依赖,降低了整体系统复杂度
坏处:冗余开发量;性能损耗
传统的可扩展架构模式:分层架构
SOA 出现 的背景:企业内部的 IT 系统重复建设且效率低下
所有业务功能都是一项服务
服务要对外提供开放的能力
服务
ESB 将企业中各个不同的服务连接在一起
SOA 使用 ESB 来屏蔽异构系统对外提供各种不同的接口方式
ESB 很重很复杂
ESB:“企业服务总线”
松耦合的目的是减少各个服务间的依赖和互相影响
各个服务是相互独立运行的
松耦合
为了应对上述问题,SOA 提出了3个关键概念
一般情况下我们可以说某个企业采用了 SOA 的架构来构建 IT 系统
但不会说某个独立的系统采用了 SOA 架构
SOA 架构是比较高层级的架构设计理念
ESB 需要实现与各种系统间的协议转换、数据转换、透明的动态路由等功能,从而让各个服务简单化
当 ESB 承载的消息太多时,ESB 本身会成为整个系统的性能瓶颈
SOA 最广为人诟病的就是 ESB
传统的可扩展架构模式:SOA -“面向服务的架构”
SOA 和 微服务 本质上是两种不同的架构设计理念,只是在“服务”这个点上有交集而已
服务粒度:SOA 的服务粒度粗,而微服务的服务粒度细
服务通信:SOA 要兼容各种协议,重量级;微服务 是统一一种协议,轻量级
服务交付:SOA 没有特殊要求;微服务 要求快速交付
应用场景:SOA 更加适合于庞大、复杂、异构、稳定的企业级系统;微服务适合于快速、轻量级、业务变化快的互联网系统
微服务与 SOA 的关系
服务划分过细,服务间关系复杂
服务数量太多,团队效率急剧下降
调用链太长,性能下降,问题定位困难
没有自动化支撑,无法快速交付
没有服务治理,微服务数量多了后管理混乱
微服务的陷阱
“三个火枪手”原则:一个微服务三个人负责开发
“三个火枪手”的原则:主要应用于微服务设计和开发阶段
如果微服务处于稳定维护期,那么1 个人可以维护多个微服务
服务拆分粒度
基于业务逻辑拆分
将已经成熟和改动不大的服务拆分为稳定服务
将经常变化和迭代的服务拆分为变动服务
基于可扩展拆分
避免非核心服务故障影响核心服务
核心服务高可用方案可以更简单
能够降低高可用成本
基于可靠性拆分
将性能要求高或者性能压力大的模块拆分出来
基于性能拆分
服务拆分方法
微服务并没有减少复杂度,而只是将复杂度转移到了基础设施
服务发现、服务路由、服务容错:这是最基本的微服务基础设施
接口框架:提升内部服务的开发效率
API 网关:提升与外部服务对接的效率
自动化部署、自动化测试、配置中心:主要是为了提升测试和运维效率
服务监控、服务跟踪、服务安全:主要是为了进一步提升运维效率
基础设施
微服务架构最佳实践
微服务架构
微内核架构主要应用场景:大单体软件
负责与b style=\
例如:模块加载、模块间通信等
核心系统:core system
负责实现具体的业务逻辑
插件模块:plug-in modules
基本架构
插件管理:插件注册表
插件连接:插件如何连接到核心系统
插件通信:指插件间的通信
设计关键点
微内核架构示例:OSGi 架构、规则引擎架构
微内核架构(插件化架构)
可扩展架构模式
基于 业务发展 阶段进行 技术演进
面对层出不穷的新技术,架构师应该采取什么样的策略?
潮流派的价值观:新技术肯定能带来很大收益
成为新技术的实验小白鼠
新技术的学习成本,无法体现出业务价值
问题点
潮流派
稳定派的价值观:稳定压倒一切
不能享受新技术带来的收益
稳定派
跟风派的价值观:别人用了我就用
如果没有风可跟,怎么办
竞争对手的信息并不容易获取
适用于竞争对手的技术,并不一定适用于自己
跟风派
绝大部分情况下,业务发展推动技术的发展
极小部分情况下,技术创新推动业务的发展
技术演进的动力
基于业务发展阶段进行技术演进
技术演进的模式
架构师应该如何判断技术演进的方向?
站在 技术成长 的角度来思考问题
站在 业务发展 的角度来思考问题
互联网业务具有“规模决定一切”的特点
互联网业务发展一般分为4个时期,不同时期的差别主要体现:业务复杂性、用户规模
业务点的重点不在于“完善”,而在于“创新”:只有创新才能吸引用户
业务对技术的要求只有一个:“快”
初创期
业务快速发展时期:将原来不完善的业务逐渐完善
业务对技术的要求:在系统中不断的快速加入各种新功能
技术演化方式:堆功能 -> 优化 -> 架构升级 -> 堆功能 --> ...
发展期
业务继续发展已经形成一定规模后,新功能新系统越来越多
重复造轮子
系统交互乱
系统数量的量变 -> 技术工作的质变
存储平台化
数据库平台化
缓存平台化
......
平台化:解决“重复造轮子”问题
通过消息队列来完成系统间的异步通知
通过服务框架来完成系统间的同步调用
服务化:解决“系统交互乱”的问题
技术工作主要的解决手段
竞争期
当企业熬过竞争期,业务上“求快求新”已经没有增长空间,开始转向为“求精”
技术上其实也基本进入了成熟期,找出自己的弱项,然后逐项优化
成熟期
互联网技术演进的模式
单机、双机主备
例如:百度的 DBProxy、淘宝的 TDDL、MySQL 官方推荐的 MySQL Router、360 开源的数据库中间件 Atlas
分布式集群(分库分表)
例如:淘宝的 UMP(Unified MySQL Platform)系统
统一存储平台
SQL:关系型数据库
例如:Memcache 的一致性 Hash 集群、Redis 3.0 的集群
分布式集群:NoSQL 一般自身就提供集群的功能
NOSQL:
例如:淘宝的 TFS、京东 JFS、Facebook 的 Haystack
小文件存储
Hadoop 生态圈
大文件存储(大数据平台)
互联网架构模板:“存储层”技术
使用统一的开发框架能够解决上面提到的各种问题,大大提升组织和团队的开发效率
优选成熟的框架,避免盲目追逐新技术
开发框架(开发语言)
“拿来主义”
Web 服务器
运维方式会发生革命性的变化
设计模式会发生本质上的变化:启动一个新的容器实例代价如此低,将鼓励设计思路朝“微服务”的方向发展
容器运维也是有成本的
容器
开发层技术
配置中心
方案1:服务名字系统(服务注册发现机制)
方案2:服务总线系统(服务网格mesh机制)
服务中心
消息队列
服务层技术
互联网架构模板:“开发层”和“服务层”技术
DNS
Nginx 、LVS 、F5
负载均衡
CDN:将内容缓存在离用户最近的地方
同城多机房
跨城多机房
跨国多机房
多机房
不一定所有业务都能实现多中心
目前国内的银行、支付宝这类系统就没有完全实现多中心
不然也不会出现挖掘机一铲子下去,支付宝中断 4 小时的故障
多中心(多活)
互联网架构模板:“网络层”技术
开源单点登录方案当属 CAS
单点登录(SSO)
授权登录(OAuth 2.0)
用户管理
消息推送
基于“CDN + 小文件存储”的技术
存储云、图片云
用户层技术
系统“拆分”
系统“合并”
业务层技术
互联网架构模板:“用户层”和“业务层”技术
标准化
平台化
自动化
可视化
运维平台:配置、部署、监控、应急
用例管理
资源管理
任务管理
数据管理
测试平台
数据采集:从业务系统搜集各类数据
数据存储:将从业务系统采集的数据存储到数据平台,用于后续数据分析
数据访问:负责对外提供各种协议用于读写数据
数据安全
例如,PV、UV、交易额等
数据统计:根据原始数据统计出相关的总览数据(指标)
数据挖掘
机器学习、深度学习
数据分析
推荐、广告
在线业务
报表、BI分析、欺诈检测
离线业务
数据应用
数据平台
管理平台的核心职责就是权限管理
身份认证:证明你是你
权限控制:判断你是否有权限
管理平台
互联网架构模板:“平台”技术
从一大堆纷繁复杂的问题中识别出真正要通过架构重构来解决的一类问题,集中力量快速解决
而不是想着通过架构重构来解决所有的问题
第一式:有的放矢
合纵:凭借数据指标告诉业务产品重构的好处
连横:技术方,站在对方的角度思考,重构对他有什么好处,能够帮他解决什么问题,带来什么收益
第二式:合纵连横
将要解决的问题根据优先级、重要性、实施难度等划分为不同的阶段,每个阶段聚焦于一个整体的目标,集中精力和资源解决一类问题
第三式:运筹帷幄
如何推动架构重构
不管你是什么身份,都可以从开源项目中学到很多东西
不要只盯着数据结构和算法
源码不是第一步,而是最后一步
树立正确的观念
这个系统的依赖组件
使用和运行的基本信息
系统提供了哪些工具方便我们使用
第 1 步:安装
系统具备哪些能力
第 2 步:运行
关键特性的基本实现原理
系统将会如何运行
优缺点对比分析
第 3 步:原理研究
测试一定要在原理研究之后做,不能安装完成立马就测试
第 4 步:测试
源码研究的主要目的是学习原理背后的具体编码如何实现,通过学习这些技巧来提升我们自己的技术能力
不建议通读所有源码
第 5 步:源码研究
采用“自顶向下”学习的5个步骤
第 1、2、3 步骤,不管是架构师,还是技术人员,在研究开源项目时都是必不可少的
第 4 步骤,可以在准备采用开源项目的时候才实施
第 5 步骤,可以根据自身时间情况来进行灵活安排,非必须
“自顶向下”学习的5个步骤的时间分配
如何高效地学习开源项目
不要重复发明轮子,但要找到合适的轮子
聚焦是否满足业务
尽量选择成熟的开源项目,降低风险
版本号:至少选 1.X 版本的
使用的公司数量
社区活跃度
从这几个方面考察开源项目是否成熟
聚焦是否成熟
聚焦运维能力
选:如何选择一个开源项目
深入研究,仔细测试
小心应用,灰度发布
做好应急,以防万一
用:如何使用开源项目
不要改动原系统,而是要开发辅助系统
例如,redis没有集群版本时,开发一个proxy来支持,而不是改redis
保持纯洁,加以包装
发明你要的轮子
改:如何基于开源项目做二次开发
如何选择、使用以及二次开发开源项目
Web App:包壳架构(App实质是个浏览器)
原生 App:基于Android 或者 iOS 操作系统提供的API开发
Hybrid App:混合模式
超级APP承载的业务功能太多,每个功能都是一个子系统
子系统作为单独组件独立开发;组件之间通过事先定义好的协议进行消息通信
多个组件一起组成超级APP
组件化 & 容器化
问题:相同功能在 Android 和 IOS 都要实现一遍,浪费人力
解决方案:目前还不成熟
跨平台 App
谈谈App架构的演进
架构实战
互联网架构
《从零开始学架构》的读书笔记
0 条评论
下一页