第一部分:概念和基础
1.架构设计的目的
为了解决软件系统复杂度带来的问题
- 复杂度主要来源于这些原因
- 高性能
- 高可用
- 可拓展
- 成本、安全、规模
2.架构设计的原则
- 简单:简单架构优于复杂的架构
- 合适:合适的架构优于业界领先的架构
- 演化:架构随着业务的发展不断的演化
3.架构设计的流程
- 识别问题真正的复杂度
- 使用了解的技术和架构,设计多个备选方案
- 不需要太详细
- 3-5个为佳
- 差异要明显,不要仅限于自己熟悉的
- 评估备选方案:360 度评估(错误思路:最简派,最熟派,最牛派,领导派)
- 精雕细琢详细方案
- 数据库表如何设计
- 主备如何转换
- 业务如何读、写
- 业务和队列的通信协议
第二部分:高性能架构模式
4.存储高性能
读写分离
- 将访问压力分散到多个节点,但是每个节点存储的还是全量数据
- 引入了 主从延迟 问题,需要考虑解决方案
分表分库
- 分散了访问压力和存储压力
- 分库引入了 join、事务、成本问题
- 分表引入了表操作数量增加(例如分 100 张表,业务逻辑会操作几张表)
数据归档:对历史数据进行归档
高性能 NoSQL
- kv 数据库:解决关系型数据库无法存储数据结构问题(Redis)
- 文档数据库:解决强 schema 问题(mongo)
- 新增字段简单
- 容易存储复杂数据
- 全文搜索引擎:解决全文搜索问题(ES)
- 列式数据库:解决大数据场景的 IO 问题(HBase)
5.计算高性能
单服务器高性能
集群高性能
复杂性
- 增加一个任务分配器,也叫负载均衡器
- 选择任务分配的算法
负载均衡分类
- DNS 负载均衡
- 更新不及时、拓展性差(客户端先请求 DNS 服务器获取服务的 IP 地址)
- 简单便宜、就近访问速度快
- 硬件负载均衡
- 功能强大,高性能(百万级),高稳定,支持防火墙,防DDOS攻击
- 贵、拓展性差
- 软件负载均衡(Nginx 负载均衡)
- 性能较差
- 便宜、拓展性强
负载均衡算法分类
- 轮询/加权轮询:简单
- 负载最低优先:任务分配给当前负载最低的服务器
- 性能最优:分配给响应时间最低的机器
- hash算法:用户的请求访问到一个机器上
第三部分:高可用架构模式
6.CAP 理论
在一个分布式系统(指相互连接并共享数据的节点的集合)中,当涉及读写操作时, 只能保证一致性(Consistence),可用性(Availability),分区容错性(Partition Tolerance)三者中两个,另外一个必须牺牲。
- 一致性: 读操作保证能够返回最新的写操作结果
- 可用性:非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
- 分区容忍性:当出现网络分区后,系统能够继续履行职责
必须选择 P 因为网络无法100%可靠。如果我们选择了 CA 放弃了 P,发生分区现象时,为了保证 C 就得禁止写入,有写入请求时候系统返回 Error,这又和 A 冲突了。 所以分布式系统理论上只能用(保证 CA 发生 P 的时候矛盾),只能选择AP/AP
ACID 理论
为了保证数据库事务的正确性提出来的一个理论
- 原子性(Atomicity)一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚。
- 一致性(Consistency)数据库总是从一个一致性的状态转换到另一个一致性的状态。
- 隔离性(Isolation)事务的结果只有提交了其他事务才可见。
- 持久性(Durability)一旦事务提交,则其所做的修改不会永久保存到数据库
BASE 理论
CAP理论中 AP 理论的延伸
- (Basically available)基本可用
- (Soft state)软状态
- Eventual Consistency(最终一致性)
8.存储高可用
通过将数据复制到多个存储设备,通过数据冗余的方式实现高可用,引入的问题如下
- 数据如何复制
- 各个节点的职责是什么
- 如何应对复制延迟或者中断
双机架构
- 主备复制: 备机起备份作用,不承担业务读写操作。适用于内部系统
- 主从复制: 从机起负责读业务,可分散压力,但客户端需要感知主从关系
- 主主复制: 都负责读写,互相复制数据。对数据设计有要求,适用于可丢失可覆盖的数据
数据集中集群和数据分散集群
数据集中集群 (比如zookeeper): 类似于主备主从,区别是至少3台
- 写操作都由主机完成,适合数据量不大的场景
- 复杂度提升,体现在数据复制,监测主机状态,新主机决策
数据分散集群 (比如hadoop)
- 需要考虑均衡性,容错性,可伸缩性
9.计算高可用
通过增加服务器达到计算高可用,复杂度主要体现在下面
- 哪些服务器可执行任务
- 任务失败如何重新执行
- 已经失败的不做处理,系统只保证新的任务分配到正常的机器上
- 任务执行完成后请求任务管理器,任务管理器决定释放重新分配到其他服务器
10.业务高可用
如何应对接口级别故障
- 内部原因: 程序bug导致死循环,某个接口导致慢查询,程序逻辑不完善导致耗尽内存等
- 外部原因: 黑客攻击、促销或抢购,三方系统大量请求,响应慢等
一些解决方式
- 降级:功能降级或者完全停掉所有功能(应对自身系统故障)
- 熔断:熔断目的是应对依赖的外部系统的故障
- 限流:丢弃超出系统访问能力的请求
- 排队:限流的一种形式,排队模块将超量请求放入消息队列,调度模块读取队列,调用服务模块提供服务处理
11.理解微服务架构
拆分方法(结合之前的工作,列举下做过哪些拆分,为了服务更稳定、解耦、效率更高)
- 基于业务逻辑。确定合适的职责范围。
- 基于可扩展拆分。按照稳定性排序,拆分为稳定服务和变动服务
- 基于可靠性。可靠性要求高的和低的
- 基于性能。压力大的模块拆出来
微服务的陷阱
- 划分过细,服务之间的关系复杂
- 服务数量过多,团队效率下降:功能改动需要N个服务同时配合改动
- 调用链太长,性能下降,也增加了定位问题的成本:rpc 链路长,增加了网络耗时
- 如果没有自动化支撑,无法快速交付
- 如果没有服务治理,微服务数量多了后管理混乱
微服务基础设施
- 自动化测试
- 自动化部署
- 配置中心
- 接口框架:微服务之间的通信方式
- API网关:外部系统接入系统需要通过 API 网关
- 服务发现、服务路由、服务监控、服务跟踪