一. 基础架构
架构设计的目的是为了解决软件系统复杂度所带来的问题
复杂度的来源一——高性能
- 单台计算机内部为了高性能带来的复杂度
操作系统、多进程和多线程 - 多台计算机集群为了高性能带来的复杂度
a. 任务分配:每台机器都可以处理完整的业务任务,不同的任务分配到不同的机器上执行
b. 任务分解:把原来大一统但复杂的业务系统,拆分成小而简单但需要多个系统配合的业务系统
复杂度的来源二——高可用
高性能增加机器目的在于“扩展”处理性能;高可用增加机器目的在于“冗余”处理单元
- 计算高可用
主备(冷备、温备、热备)、主主 - 存储高可用
数据 + 存储 = 业务,存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响。 - 高可用状态决策
状态决策:系统需要能够判断当前的状态是正常还是异常,如果出现了异常就要采取行动来保证高可用
d. 独裁式:存在一个独立的决策主体,负责手机信息然后决策。
e. 协商式:是两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策为主备用决策。
f. 民主式:多个独立的个体通过投票的方式来进行状态决策
复杂度的来源三——可扩展性
设计具备良好可扩展性的系统,有两个基本条件:正确预测变化、完美封装变化。
预测变化的复杂性来源于:
- 不能每个设计点都考虑可扩展性
- 不能完全不考虑可扩展性
- 所有的预测都存在出错的可能性
应对变化:
- 方案一:将变化的部分封装到变化层,将不变的部分封装到稳定层。
- 方案二:提炼出抽象层和实现层
复杂度的来源四——低成本、安全和规模
低成本
设计三高架构的时候,往往需要增加更多的服务器,而低成本的不是架构设计的首要目标,而是约束,也就是说我们首先定一个成本目标,当我们按照三高的要求设计架构时,需要评估是否满足成本目标,不满足就需要重新设计。低成本给架构设计带来的复杂度主要体现在,只有创新才能达到低成本目标,创新既包括开创一个全新的技术领域,也包括引入新技术。
安全
功能安全、架构安全
规模
规模带来复杂度的主要原因就是“量变引起质变”,常见的规模带来的复杂度有:
- 功能越来越多,导致系统复杂度指数级上升
- 数据越来越多,系统复杂度发生质变
架构设计的三原则
合适原则
简单原则
演化原则
架构设计流程:识别复杂度
将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题
架构设计流程:设计备选方案
● 备选方案的数量以3 ~ 5个为最佳。少于3个方案可能是因为思维狭隘,考虑不周全;多于5个则需要耗费大量的精力和时间,并且方案之间的差别可能不明显。
● 备选方案的差异要比较明显。例如,主备方案和集群方案差异就很明显,或者同样是主备方案,用ZooKeeper做主备决策和用Keepalived做主备决策的差异也很明显。但是都用ZooKeeper做主备决策,一个检测周期是1分钟,一个检测周期是5分钟,这就不是架构上的差异,而是细节上的差异了,不适合做成两个方案。
● 备选方案的技术不要只局限于已经熟悉的技术。设计架构时,架构师需要将视野放宽,考虑更多可能性。很多架构师或者设计师积累了一些成功的经验,出于快速完成任务和降低风险的目的,可能自觉或者不自觉地倾向于使用自己已经熟悉的技术,对于新的技术有一种不放心的感觉。就像那句俗语说的:“如果你手里有一把锤子,所有的问题在你看来都是钉子”。
架构设计流程:评估和选择备选方案
列出我们需要关注的质量属性点,然后分别从这些质量属性的维度去评估每个方案,再综合挑选适合当时情况的最优方案。常见的方案质量属性点有:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等
架构设计流程:详细方案设计
二. 高性能架构模式
高性能数据库集群:读写分离
读写分离:将数据库的读写操作分散到不同的节点上。实现逻辑并不复杂,但是会引入两个复杂度,复制延迟和分配机制。
复制延迟:
- 读写黏连,写操作后的读操作指定发给数据库主服务器。
- 读从机失败后, 再读一次主机。
- 关键业务读写操作全部指向主机,非关键业务采用读写分离
分配机制:
- 程序代码封装
- 中间件实现
高性能数据库集群:分库分表
业务分库
业务分库:按照业务模块将数据分散到不同的数据库服务器。
分库分表虽然分散了存储和访问压力,但是会带来一下问题:
- JOIN操作问题
- 事务问题
- 成本问题
分表
单表数据拆分有两种方式:垂直分表和水平分表
垂直分表:
垂直分表适合将表中某些不常用且占了大量空间的列拆分出去。垂直分表引入的复杂性主要体现在表操作的数量要增加。例如,原来只要一次查询就可以获取所有的信息,现在需要两次查询,
水平分表:
- 水平分表相比垂直分表,会引入更多的复杂性,主要表现在下面几个方面:
路由:水平分表后,某条数据具体属于哪个切分后的子表,需要增加路由算法进行计算 - JOIN操作:水平分表后,数据分散在多个表中,如果需要与其他表进行join查询,需要在业务代码或者数据库中间件中进行多次join查询,然后将结果合并。
- COUNT操作:
高性能NoSQL
关系型数据库存在以下缺点:
- 关系数据库存储的是行记录,无法存储数据结构
- 关系数据库的schema扩展很不方便
- 关系数据库在大数据场景下I/O较高
- 关系数据库的全文搜索功能比较弱
常见的NoSql分为以下四种,分别可以解决关系数据库的四个缺点
- KV存储
- 文档数据库
- 列式数据库
- 全文检索数据库
高性能缓存架构
缓存穿透、缓存雪崩、缓存击穿
单服务器高性能模式:PPC与TPC
1.PPC: Process Per Connection的缩写,其含义是指每次有新的连接就新建一个进程去专门处理这个连接的请求
2.perfork: prefork就是提前创建进程(pre-fork)。系统在启动的时候就预先创建好进程,然后才开始接受用户的请求,当有新的连接进来的时候,就可以省去fork进程的操作,让用户访问更快、体验更好,但是会有 "惊群"现象,因为实际只有一个子进程能处理,但是所有阻塞的子进程都会被唤醒。
3.TPC: Thread Per Connection的缩写,其含义是指每次有新的连接就新建一个线程去专门处理这个连接的请求
4.PRETHREAD: prethread模式会预先创建线程,然后才开始接受用户的请求,当有新的连接进来的时候,就可以省去创建线程的操作。
单服务器高性能模式:Reactor与Proactor
高性能负载均衡:分类及架构
负载均衡包含三种:DNS负载均衡、软件负载均衡、硬件负载均衡
DNS负载均衡
优点
- 简单、成本低:负载均衡工作交给DNS服务器处理,无须自己开发或者维护负载均衡设备。
- 就近访问,提升访问速度:DNS解析时可以根据请求来源IP,解析成距离用户最近的服务器地址,可以加快访问速度,改善性能。
缺点
- 更新不及时:DNS缓存的时间比较长,修改DNS配置后,由于缓存的原因,还是有很多用户会继续访问修改前的IP
- DNS负载均衡的控制权在域名商那里,无法根据业务特点针对其做更多的定制化功能和扩展特性
- 分配策略比较简单:DNS负载均衡支持的算法少;不能区分服务器的差异(不能根据系统与服务的状态来判断负载);也无法感知后端服务器的状态。
硬件负载均衡
硬件负载均衡是通过单独的硬件设备来实现负载均衡功能,例如F5和A10
优点
- 功能强大:全面支持各层级的负载均衡,支持全面的负载均衡算法,支持全局负载均衡。
- 性能强大:对比一下,软件负载均衡支持到10万级并发已经很厉害了,硬件负载均衡可以支持100万以上的并发。
- 稳定性高:商用硬件负载均衡,经过了良好的严格测试,经过大规模使用,稳定性高。
- 支持安全防护:硬件均衡设备除具备负载均衡功能外,还具备防火墙、防DDoS攻击等安全功能
缺点
- 价格行规
- 扩展能力差:硬件设备,可以根据业务进行配置,但无法进行扩展和定制
软件负载均衡
优点
- 简单
- 便宜
- 灵活
缺点
- 性能一般
- 功能没有硬件负载均衡一样强大
- 一般不具备防火墙、防DDos攻击等安全功能。
高性能负载均衡:算法
轮训、加权轮训、负载最低、性能最优、Hash类