05 复杂度来源:高可用
高可用定义:
系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。
系统的高可用方案五花八门,但万变不离其宗,本质上都是通过“冗余”来实现高可用。通俗点来讲,就是一台机器不够就两台,两台不够就四台;一个机房可能断电,那就部署两个机房;一条通道可能故障,那就用两条,两条不够那就用三条(移动、电信、联通一起上)。高可用的“冗余”解决方案,单纯从形式上来看,和之前讲的高性能是一样的,都是通过增加更多机器来达到目的,但其实本质上是有根本区别的:高性能增加机器目的在于“扩展”处理性能;高可用增加机器目的在于“冗余”处理单元。
主要分为:计算高可用和存储高可用。
06 复杂度来源:可扩展性
可扩展性指系统为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无须整个系统重构或者重建。
剥离变化层和稳定层的方式应对变化
08 架构设计三原则
合适原则、简单原则、演化原则,架构设计时遵循这几个原则,有助于你做出最好的选择。
合适原则宣言:“合适优于业界领先”。
简单原则宣言:“简单优于复杂”。
演化原则宣言:“演化优于一步到位”。
10 架构设计流程:识别复杂度
架构设计的本质目的是为了解决软件系统的复杂性,所以在我们设计架构时,首先就要分析系统的复杂性。只有正确分析出了系统的复杂性,后续的架构设计方案才不会偏离方向。
架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面,但架构师在具体判断复杂性的时候,不能生搬硬套,认为任何时候架构都必须同时满足这三方面的要求。实际上大部分场景下,复杂度只是其中的某一个,少数情况下包含其中两个,如果真的出现同时需要解决三个或者三个以上的复杂度,要么说明这个系统之前设计的有问题,要么可能就是架构师的判断出现了失误,即使真的认为要同时满足这三方面的要求,也必须要进行优先级排序。
正确的做法是将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。
高性能架构模式
14 高性能数据库集群:读写分离
读写分离的基本原理是将数据库读写操作分散到不同的节点上,下面是其基本架构图。
读写分离的基本实现是:
(1)数据库服务器搭建主从集群,一主一从、一主多从都可以。
(2)数据库主机负责读写操作,从机只负责读操作。
(3)数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。
(4)业务服务器将写操作发给数据库主机,将读操作发给数据库从机。
读写分离的实现逻辑并不复杂,但有两个细节点将引入设计复杂度:主从复制延迟和分配机
制。
15 高性能数据库集群:分库分表
读写分离分散了数据库读写操作的压力,但没有分散存储压力,当数据量达到千万甚至上亿条的时候,单台数据库服务器的存储能力会成为系统的瓶颈,主要体现在这几个方面:
(1)数据量太大,读写的性能会下降,即使有索引,索引也会变得很大,性能同样会下降。
(2)数据文件会变得很大,数据库备份和恢复需要耗费很长时间。
(3)数据文件越大,极端情况下丢失数据的风险越高(例如,机房火灾导致数据库主备机都发生故障)。
基于上述原因,单个数据库服务器存储的数据量不能太大,需要控制在一定的范围内。为了满足业务数据存储的需求,就需要将存储分散到多台数据库服务器上。
今天我来介绍常见的分散存储的方法“分库分表”,其中包括“分库”和“分表”两大类。
业务分库
业务分库指的是按照业务模块将数据分散到不同的数据库服务器。例如,一个简单的电商网
站,包括用户、商品、订单三个业务模块,我们可以将用户数据、商品数据、订单数据分开
放到三台不同的数据库服务器上,而不是将所有数据都放在一台数据库服务器上。
分表
将不同业务数据分散存储到不同的数据库服务器,能够支撑百万甚至千万用户规模的业务,但如果业务继续发展,同一业务的单表数据也会达到单台数据库服务器的处理瓶颈。例如,淘宝的几亿用户数据,如果全部存放在一台数据库服务器的一张表中,肯定是无法满足性能要求的,此时就需要对单表数据进行拆分。
单表数据拆分有两种方式:垂直分表和水平分表。示意图如下:
为了形象地理解垂直拆分和水平拆分的区别,可以想象你手里拿着一把刀,面对一个蛋糕切一刀:
从上往下切就是垂直切分,因为刀的运行轨迹与蛋糕是垂直的,这样可以把蛋糕切成高度相等(面积可以相等也可以不相等)的两部分,对应到表的切分就是表记录数相同但包含不同的列。例如,示意图中的垂直切分,会把表切分为两个表,一个表包含 ID、name、age、sex 列,另外一个表包含 ID、nickname、description 列。
从左往右切就是水平切分,因为刀的运行轨迹与蛋糕是平行的,这样可以把蛋糕切成面积相等(高度可以相等也可以不相等)的两部分,对应到表的切分就是表的列相同但包含不同的行数据。例如,示意图中的水平切分,会把表分为两个表,两个表都包含 ID、name、age、sex、nickname、description 列,但是一个表包含的是 ID 从 1 到999999 的行数据,另一个表包含的是 ID 从 1000000 到 9999999 的行数据。
水平分表相比垂直分表,会引入更多的复杂性
16 高性能NoSQL
关系数据库存在如下缺点:
关系数据库存储的是行记录,无法存储数据结构
关系数据库的 schema 扩展很不方便
关系数据库在大数据场景下 I/O 较高
关系数据库的全文搜索功能比较弱
17 高性能缓存架构
缓存就是为了弥补存储系统在这些复杂业务场景下的不足,其基本原理是将可能重复使用的数据放到内存中,一次生成、多次使用,避免每次使用都去访问存储系统。
20 高性能负载均衡:分类及架构
单服务器无论如何优化,无论采用多好的硬件,总会有一个性能天花板,当单服务器的性能无法满足业务需求时,就需要设计高性能集群来提升系统整体的处理性能。
高性能集群的本质很简单,通过增加更多的服务器来提升系统整体的计算能力。由于计算本身存在一个特点:同样的输入数据和逻辑,无论在哪台服务器上执行,都应该得到相同的输出。因此高性能集群设计的复杂度主要体现在任务分配这部分,需要设计合理的任务分配策略,将计算任务分配到多台服务器上执行。
高性能集群的复杂性主要体现在需要增加一个任务分配器,以及为任务选择一个合适的任务分配算法。对于任务分配器,现在更流行的通用叫法是“负载均衡器”。但这个名称有一定的误导性,会让人潜意识里认为任务分配的目的是要保持各个计算单元的负载达到均衡状态。而实际上任务分配并不只是考虑计算单元的负载均衡,不同的任务分配算法目标是不一样的,有的基于负载考虑,有的基于性能(吞吐量、响应时间)考虑,有的基于业务考虑。考虑到“负载均衡”已经成为了事实上的标准术语,这里我也用“负载均衡”来代替“任务分配”,但请你时刻记住,负载均衡不只是为了计算单元的负载达到均衡状态。
负载均衡分类
常见的负载均衡系统包括 3 种:DNS 负载均衡、硬件负载均衡和软件负载均衡。