从0开始架构学习总结

架构基础

架构概念

软件架构指软件系统的顶层结构。

  • 子系统:子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中一部分
  • 框架:关注的是“规范”(Framework),如Spring MVC框架
  • 架构:关注的是“结构”(Architecture)
  • 模块:逻辑的角度来拆分系统后,得到的单元就是“模块”,主要目的是职责分离
  • 组件:从物理的角度来拆分系统后,得到的单元就是“组件”,主要目的是单元复用

一句话总结:架构是顶层设计;框架是面向编程或配置的半成品;组件是从技术维度上的复用;模块是从业务维度上职责的划分;系统是相互协同可运行的实体。

architecture_1

架构设计的目的

架构设计的主要目的是为了解决软件系统复杂度带来的问题。

一句话总结:架构即(重要)决策,是在一个有约束的盒子里去求解或接近最合适的解。这个有约束的盒子是团队经验、成本、资源、进度、业务所处阶段等所编织、掺杂在一起的综合体(人,财,物,时间,事情等)。架构无优劣,但是存在恰当的架构用在合适的软件系统中,而这些就是决策的结果。

软件系统复杂度的来源

1. 高性能

单台计算机内部为了高性能带来的复杂度(垂直维度)

多台计算机集群为了高性能带来的复杂度(水平维度)

垂直维度方案比较适合业务阶段早期和成本可接受的阶段,该方案是提升性能最简单直接的方式,但是受成本与硬件能力天花板的限制。

水平维度方案所带来的好处要在业务发展的后期才能体现出来。起初,该方案会花费更多的硬件成本,另外一方面对技术团队也提出了更高的要求;但是,没有垂直方案的天花板问题。一旦达到一定的业务阶段,水平维度是技术发展的必由之路。

2. 高可用

系统无中断地执行其功能的能力

  • 计算高可用(任务分配器,分配器于业务服务器的交互,分配算法等)
  • 存储高可用(CAP定理:存储高可用不可能同时满足“一致性、可用性、分区容错性”,最多满足其中两个)

实现高可用的本质:“冗余”(高性能增加机器目的在于“扩展”处理性能;高可用增加机器目的在于“冗余”处理单元)

高可用的解决方法不是解决,而是减少或者规避,而规避某个问题的时候,一般都会引发另一个问题,只是这个问题比之前的小,高可用的设计过程其实也是一个取舍的过程。

3. 可扩展

系统为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无须整个系统重构或者重建。

设计具备良好可扩展性的系统:
1)从业务维度。对业务深入理解,对可预计的业务变化进行预测。
2)从技术维度。利用扩展性好的技术,实现对变化的封装。

4. 低成本

低成本本质上是与高性能和高可用冲突的,当无法设计出满足成本要求的方案,就只能协调并调整成本目标

一般通过创新达到低成本目标:

  • 引入新技术
  • 开创一个全新技术领域

5. 安全

功能安全(防小偷):减少系统潜在的缺陷,阻止黑客破坏行为

架构安全(防强盗):保护系统不受恶意访问和攻击,保护系统的重要数据不被窃取

6. 规模

规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化

规模问题需要与高性能、高可用、高扩展、高伸缩性统一考虑。常采用“分而治之,各个击破”的方法策略。

架构设计三原则

合适原则

合适优于业界领先

简单原则

简单优于复杂

演化原则

演化优于一步到位

架构设计流程

第一步:识别复杂度

将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。

具体做法:

  • 构建复杂度的来源清单——高性能、可用性、扩展性、安全、低成本、规模等。
  • 结合需求、技术、团队、资源等对上述复杂度逐一分析是否需要?是否关键?
  • 按照上述的分析结论,得到复杂度按照优先级的排序清单,越是排在前面的复杂度,就越关键,就越优先解决。

第二步:设计备选方案

  • 备选方案不要过于详细。备选阶段解决的是技术选型问题,而不是技术细节。
  • 备选方案的数量以 3~5个为最佳。
  • 备选方案的技术差异要明显。
  • 备选方案不要只局限于已经熟悉的技术。

第三步:评估和选择备选方案

列出我们需要关注的质量属性点,然后分别从这些质量属性的维度去评估每个方案,再综合挑选适合当时情况的最优方案。

质量属性:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等

第四步:详细方案设计

详细方案设计是将方案涉及的关键技术细节给确定下来

高性能架构模式

architecture_2

高性能数据库集群

读写分离

基本原理是将数据库读写操作分散到不同的节点上。

  • 主从:“从机”是需要提供读数据的功能的
  • 主备:一般被认为仅仅提供备份功能,不提供访问功能

主从基本实现:

  • 数据库服务器搭建主从集群,一主一从、一主多从都可以
  • 数据库主机负责读写操作,从机只负责读操作。
  • 数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。
  • 业务服务器将写操作发给数据库主机,将读操作发给数据库从机。

需解决的问题:

  • 复制延迟:数据同步延迟
    • 写操作后的读操作指定发给数据库主服务器
    • 读从机失败后再读一次主机
    • 关键业务读写操作全部指向主机,非关键业务采用读写分离
  • 分配机制:将读写区分开
    • 程序代码封装(在代码中抽象一个数据访问层,Hibernate)
    • 中间件封装(独立一套系统出来,实现读写操作分离和数据库服务器连接的管理,MySQL Router)

总结:并不是说一有性能问题就上读写分离,而是应该先优化,例如优化慢查询,调整不合理的业务逻辑,引入缓存等,只有确定系统没有优化空间后,才考虑读写分离或者集群。

分库分表

业务分库

业务分库指的是按照业务模块将数据分散到不同的数据库服务器。

需注意的问题:

  • JOIN操作问题
  • 事务问题
  • 成本问题
分表

同一业务的单表数据进行拆分

  • 垂直分表:拆分字段到不同的表
  • 水平分表:拆分记录到不同的表

水平分表的路由问题:

  • 范围路由:选取有序的数据列(例如,整形、时间戳等)作为路由的条件,不同分段分散到不同的数据库表中。
  • Hash路由:选取某个列(或者某几个列组合也可以)的值进行Hash运算,然后根据 Hash 结果分散到不同的数据库表中。
  • 配置路由:配置路由就是路由表,用一张独立的表来记录路由信息。

高性能NoSQL

常见的NoSQL方案分为4类。

  • K-V 存储:解决关系数据库无法存储数据结构的问题,以Redis为代表
    • Redis 的 Value 是具体的数据结构,包括string、hash、list、set、sorted set、bitmap 和 hyperloglog,常被称为数据结构服务器
    • Redis 的事务只能保证隔离性和一致性(I 和 C),无法保证原子性和持久性(A 和 D)
  • 文档数据库:解决关系数据库强schema约束的问题,以MongoDB为代表
    • 新增字段简单,历史数据不回出错
    • 很容易存储复杂数据
    • 代价是不支持事物、无法实现关系数据库的 join 操作
  • 列式数据库:解决关系数据库大数据场景下的I/O问题,以HBase为代表
    • 读取表中某些列时,只需要把需要的列读取到内存中(节省I/O)
    • 列式存储还具备更高的存储压缩比,能够节省更多的存储空间
    • 需要频繁地更新多个列时,磁盘是随机写操作,效率不高
  • 全文搜索引擎:解决关系数据库的全文搜索性能问题,以Elasticsearch为代表
    • 技术原理被称为“倒排索引”,建立单词到文档的索引
    • 全文搜索引擎的索引对象是单词和文档,而关系数据库的索引对象是键和行

高性能缓存

缓存就是为了弥补存储系统在复杂业务场景(经过复杂运算过的数据、读多写少等)下的不足,其基本原理是将可能重复使用的数据放到内存中,一次生成、多次使用,避免每次使用都去访问存储系统。

缓存架构的设计要点

缓存穿透

缓存没有发挥作用,业务系统虽然去缓存查询数据,但缓存中没有数据,业务系统需要再次去存储系统查询数据。

缓存雪崩

当缓存失效(过期)后引起系统性能急剧下降的情况。由于旧的缓存已经被清除,新的缓存还未生成,并且处理这些请求的线程都不知道另外有一个线程正在生成缓存,因此所有的请求都会去重新生成缓存,都会去访问存储系统,从而对存储系统造成巨大的性能压力。这些压力又会拖慢整个系统。

解放方法:

  • 更新锁:对缓存更新操作进行加锁保护,保证只有一个线程能够进行缓存更新,未能获取更新锁的线程要么等待锁释放后重新读取缓存,要么就返回空值或默认值。
  • 后台更新:后台线程来更新缓存,而不是由业务线程来更新缓存,缓存本身的有效期设置为永久,后台线程定时更新缓存。
缓存热点

如果大部分甚至所有的业务请求都命中同一份缓存数据,则这份数据所在的缓存服务器的压力也很大。

解决方法:复制多份缓存副本,将请求分散到多个缓存服务器上,减轻缓存热点导致的单台缓存服务器压力。(不同的缓存副本不要设置统一的过期时间,否则就会出现所有缓存副本同时生成同时失效的情况,从而引发缓存雪崩)

高性能服务器

  • 尽量提升单服务器的性能,将单服务器的性能发挥到极致。
  • 如果单服务器无法支撑性能,设计服务器集群方案。

单服务器的高性能

单服务器高性能的关键之一就是设计服务器采取的 “并发模型”

  • 服务器如何处理连接:I/O 模型:阻塞、非阻塞、同步、异步
  • 服务器如何处理请求:进程模型:单进程、多进程、多线程

单服务器高性能模式(PPC 和 TPC 模式):

  • PPC(Process Per Connection):指每次有新的连接就新建一个 “进程” 去专门处理这个连接的请求
  • prefork:系统在启动的时候就预先创建好进程,然后才开始接受用户的请求,省去fork进程操作
  • TPC(Thread Per Connection):指每次有新的连接就新建一个 “线程” 去专门处理这个连接的请求
  • prethread:预先创建线程,然后才开始接受用户的请求,当有新的连接进来的时候,就可以省去创建线程的操作

单服务器高性能模式(Reactor 和 Proactor 模式):

资源复用,即不再单独为每个连接创建进程,而是创建一个进程池,将连接分配给进程,一个进程可以处理多个连接的业务.

IO操作分两个阶段【去饭店点餐排队】:

    1. 等待数据准备好(读到内核缓存) 【准备菜品】
    1. 将数据从内核缓存读到用户空间(进程空间) 【端走吃到肚里】

一般来说1花费的时间远远大于2。

  • 同步阻塞IO:1上阻塞2上也阻塞【付完钱在收银台等着,菜好之后取走离开】
  • 同步非阻塞IO:1上非阻塞2上阻塞(Reactor模型)【付完钱领号,等待叫号,自己来取】
  • 异步非阻塞IO:1上非阻塞2上非阻塞是(Proactor模型)【付完钱领号,回到座位干别的,菜好后服务员把菜端来】

服务器集群的高性能

高性能集群的复杂性:需要一个任务分配器(负载均衡),以及任务分配算法

负载均衡

负载均衡的分类:

  • DNS负载均衡:实现地理级别的均衡(简单、成本低)
  • 硬件负载均衡:用于负载均衡的基础网络设备(价格昂贵、扩展能力差)
  • 软件负载均衡:常见的Nginx(网络7层负载均衡)和 LVS(4层负载均衡)

DNS 负载均衡用于实现地理级别的负载均衡;硬件负载均衡用于实现集群级别的负载均衡;软件负载均衡用于实现机器级别的负载均衡。

任务分配算法
  • 轮询:按照顺序轮流分配到服务器上
  • 加权轮询:根据服务器权重进行任务分配
  • 负载最低优先:将任务分配给当前负载最低的服务器(站在服务器的角度)
  • 性能最优类:优先将任务分配给处理速度最快的服务器(站在客户端的角度)
  • Hash类:根据任务中的某些关键信息进行 Hash 运算,将相同 Hash 值的请求分配到同一台服务器上

高可用架构模式

architecture_3

分布式系统架构CAP定理

在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。

  • 一致性(C):对某个指定的客户端来说,读操作保证能够返回最新的写操作结果
  • 可用性(A):非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)
  • 分区容错型(P):当出现网络分区后,系统能够继续“履行职责”。

设计分布式系统架构时必须选择 P(分区容忍),因为网络本身无法做到 100%可靠,有可能出故障,所以分区是一个必然的现象。

  • CP:发生分区现象后,有问题的节点不能同步数据,为了保证一致性(C),请求数据时只能返回Error,就不能满足可用性(A)
  • AP:发生分区现象后,有问题的节点不能同步数据,为了保证可用性(A),请求数据时只能返回旧数据,就不能满足一致性(C)

注意:

  • CAP 关注的粒度是数据,而不是整个系统。
  • CAP 是忽略网络延迟的(数据能够瞬间复制到所有节点)
  • 既要考虑分区发生时选择 CP 还是 AP,也要考虑分区没有发生时如何保证 CA。
  • 放弃并不等于什么都不做,需要为分区恢复后做准备。

BASE理论:即使无法做到强一致性(CAP),但应用可以采用适合的方式达到最终一致性。

  • 基本可用(Basically Available):分布式系统在出现故障时,允许损失部分可用性,即保证核心可用
  • 软状态(Soft State):允许系统存在中间状态,而该中间状态不会影响系统整体可用性
  • 最终一致性(Eventual Consistency):系统中的所有数据副本经过一定时间后,最终能够达到一致的状态

ACID:数据库管理系统为了保证 “事务” 的正确性而提出来的一个理论。

  • Atomicity(原子性):要么全部完成,要么全部不完成
  • Consistency(一致性):开始和结束后数据库完整型没有破坏
  • Isolation(隔离性):多个并发事务同时对数据进行读写和修改的能力
  • Durability(持久性):事务处理结束后,对数据的修改就是永久的

高可用存储架构

双机高可用架构(隐含的假设:主机能够存储所有数据)

  • 主备复制(备机仅仅只为备份,并没有提供读写操作,硬件成本上有浪费)
  • 主从复制(主机负责读写操作,从机只负责读操作,不负责写操作)
  • 主备/主从切换(在原有方案的基础上增加“切换”功能,即系统自动决定主机角色,并完成角色切换)
  • 主主复制(两台机器都是主机,互相将数据复制给对方,任意连接一台进行读写操作)

主备切换架构:

  • 互连式:主备机直接建立状态传递的渠道
  • 中介式:主备机之间不直接连接,而都去连接中介,并且通过中介来传递状态
  • 模拟式:主备机之间并不传递任何状态数据,而是备机模拟成一个客户端,向主机发起模拟的读写操作,根据读写操作的响应情况来判断主机的状态

集群式高可用存储架构

数据集群
  • 数据集中集群(数据都只能往主机中写,而读操作可以参考主备、主从架构进行灵活多变,如zookeeper集群-ZAB算法)
  • 数据分散集群(每台服务器都会负责存储一部分数据,每台服务器又会备份一部分数据,如Hadoop集群)
数据分区
  • 集中式:所有的分区都将数据备份到备份中心
  • 互备式:每个分区备份另外一个分区的数据
  • 独立式:每个分区自己有独立的备份中心

计算高可用

  • 主备:主机执行所有计算任务,当主机故障时,任务分配器不会自动将计算任务发送给备机
  • 主从:任务分配器需要将任务进行分类,确定哪些任务可以发送给主机执行,哪些任务可以发送给备机执行
  • 集群
    • 对称集群:负载均衡集群(集群中每个服务器的角色都是一样的,都可以执行所有任务)
    • 非对称集群:集群中的服务器分为多个不同的角色,不同的角色执行不同的任务

业务高可用

存储高可用和计算高可用都是为了解决部分服务器故障的场景下,如何保证系统能够继续提供服务。在一些极端场景下,有可能所有服务器都出现故障,此时就需要设计异地多活架构。

异地:指地理位置上不同的地方

多活:指不同地理位置上的系统都能够提供业务服务

  • 同城异区(同一个城市不同区的多个机房)
  • 跨城异地(不同城市的多个机房)
  • 跨国异地(不同国家的多个机房)

四大设计技巧:

  • 保证 “核心” 业务的异地多活
  • 保证核心数据 “最终” 一致性
  • 采用多种手段同步数据
  • 只保证绝大部分用户的异地多活

采用多种手段,保证绝大部分用户的核心业务异地多活

四步:

  • 业务分级(挑选出核心的业务,只为核心业务设计异地多活)
  • 数据分类(识别所有的数据及数据特征)
  • 数据同步
  • 异常处理

接口级的故障

接口级故障表现为:系统并没有宕机,网络也没有中断,但业务却出现问题了(业务响应缓慢、大量访问超时、大量访问出现异常)

优先保证核心业务和优先保证绝大部分用户

解决方案:

  • 降级:(应对系统自身的故障)将某些业务或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能
    • 系统后门降级
    • 独立降级系统
  • 熔断:(应对依赖的外部系统故障的情况)壮士断腕,停掉外部依赖的调用
  • 限流:(直接拒绝用户)从系统功能优先级的角度考虑如何应对故障,只允许系统能够承受的访问量进来,超出系统访问能力的请求将被丢弃
    • 基于请求限流
    • 基于资源限流
  • 排队:(让用户等待一段时间)使用 Kafka 这类消息队列来缓存用户请求

可扩展架构模式

architecture_4

可扩展的基本思想

总结为一个字:拆!

流程 > 服务 > 功能

  • 面向流程拆分:将整个业务流程拆分为几个阶段,每个阶段作为一部分(得到分层架构)
  • 面向服务拆分:将系统提供的服务拆分,每个服务作为一部分(SOA、微服务)
  • 面向功能拆分:将系统提供的功能拆分,每个功能作为一部分(微内核架构)

分层架构

本质在于隔离关注点,即每个层中的组件只会处理本层的逻辑。

  • C/S 架构、B/S 架构(划分的对象是整个业务系统,划分的维度是用户交互)
  • MVC 架构、MVP 架构(划分的对象是单个业务子系统,划分的维度是职责)
  • 逻辑分层架构(划分的对象可以是整个或单个业务子系统,划分的维度也是职责,逻辑分层架构中的层是自顶向下依赖的)

SOA架构(面向服务架构)

SOA 出现的背景是企业内部的系统重复建设且效率低下,SOA 解决了传统 IT 系统重复建设和扩展效率低的问题。

  • SOA是集成的思想,是解决服务孤岛打通链条,是无奈之举。
  • ESB集中化的管理带来了性能不佳,厚重等问题。也无法快速扩展。不适合互联网的业务特点

微服务架构

SOA 和微服务本质上是两种不同的架构设计理念,只是在“服务”这个点上有交集而已。

  • 微服务是 SOA 的实现方式(服务粒度比SOA细)
  • 微服务是去掉 ESB 后的 SOA(更为轻量级,例如HTTP RESTful)
  • 微服务是一种和 SOA 相似但本质上不同的架构理念(服务交付快,适合互联网)

微服务拆分方法(维度):

  1. 基于业务逻辑拆分(系统中的业务模块按照职责范围识别出来,每个单独的业务模块拆分为一个独立的服务)
  2. 基于可扩展拆分(将系统中的业务模块按照稳定性排序,将已经成熟和改动不大的服务拆分为稳定服务,将经常变化和迭代的服务拆分为变动服务)
  3. 基于可靠性拆分(将系统中的业务模块按照优先级排序,将可靠性要求高的核心服务和可靠性要求低的非核心服务拆分开来,然后重点保证核心服务的高可用)
  4. 基于性能拆分(将性能要求高或者性能压力大的模块拆分出来,避免性能压力大的服务影响其他服务)

微服务基础设施:

  • 自动化测试(通过自动化测试系统来完成绝大部分测试回归的工作)
  • 自动化部署(自动化部署的系统来完成大量的部署操作)
  • 配置中心(有的运行期配置需要动态修改并且所有节点即时生效,人工操作是无法做到的)
  • 接口框架(HTTP/REST 或者 RPC 方式)
  • API网关(内部的微服务之间是互联互通的,相互之间的访问都是点对点的,需要一个统一的 API 网关,负责外部系统的访问操作)
  • 服务发现
    • 自理式:每个微服务自己完成服务发现
    • 代理式:由负载均衡系统来完成微服务之间的服务发现
  • 服务路由(进行某次调用请求时,我们还需要从所有符合条件的可用微服务节点中挑选出一个具体的节点发起请求)
  • 服务容错(从整体上来看,系统中某个微服务出故障的概率会大大增加)
  • 服务监控(需要服务监控系统来完成微服务节点的监控)
  • 服务跟踪(跟踪某一个请求在微服务中的完整路径)
  • 服务安全(接入安全、数据安全、传输安全)

微内核架构(插件化架构)

两类组件:

  • 核心系统(core system):负责和具体业务功能无关的通用功能(模块加载、模块间通信等)
  • 插件模块(plug-in modules):负责实现具体的业务逻辑

互联网架构模式

architecture_5

“存储层”技术

  • SQL存储:以对业务透明的形式提供资源分配、数据备份、迁移、容灾、读写分离、分库分表等一系列服务
  • NoSQL存储:存储复杂数据、高性能
  • 小文件存储(图片等):HBase、Hadoop
  • 大文件存储(业务大数据如视频等、海量日志数据):HBase、HDFS

“开发层”技术

  • 开发框架:SSH、SpringMVC等(只是负责完成业务功能的开发)
  • Web服务器:Tomcat、Nginx等(真正能够运行起来给用户提供服务)
  • 容器:Docker等(一个虚拟化或者容器技术)

“服务层”技术

  • 配置中心:集中管理各个系统的配置
  • 服务中心:解决跨系统依赖的“配置”和“调度”问题
  • 消息队列:为了实现这种跨系统异步通知的中间件系统

“网络层”技术

  • 负载均衡(将请求均衡地分配到多个系统上)
    • DNS:实现地理级别的均衡
    • Nginx(7层)、LVS(4层)、F5(4层):用于同一地点内机器级别的负载均衡
    • CDN:将内容缓存在离用户最近的地方,用户访问的是缓存的内容(“以空间换时间”)
  • 多机房(主要目标是灾备)
    • 同城多机房
    • 跨城多机房
    • 跨国多机房
  • 多中心(以多机房为前提,要求每个中心都同时对外提供服务,且业务能够自动在多中心之间切换,故障后不需人工干预自动恢复)

“用户层”和“业务层”技术

  • 用户管理(单点登录,授权登陆)
  • 消息推送(分为短信、邮件、站内信、App推送)
  • 存储云、图片云(买云服务最快最经济)

“平台”技术

  • 运维平台:配置、部署、监控、应急
    • 标准化(制定运维标准,规范配置管理、部署流程、监控指标、应急能力等)
    • 平台化(在运维标准化的基础上,将运维的相关操作都集成到运维平台中)
    • 自动化(将重复操作固化下来,由系统自动完成)
    • 可视化(为了提升数据查看效率)
  • 测试平台:单元测试、集成测试、接口测试、性能测试
    • 用例管理(为了能够重复执行这些测试用例,测试平台需要将用例管理起来)
    • 资源管理(具体的运行环境:硬件、软件、业务系统)
    • 任务管理(将测试用例分配到具体的资源上执行,跟踪任务的执行情况)
    • 数据管理(测试完成后,记录各种相关的数据)
  • 数据平台
    • 数据管理(数据采集、数据存储、数据访问和数据安全)
    • 数据分析(数据统计、数据挖掘、机器学习、深度学习)
    • 数据应用(包括在线业务如推荐、广告等,也包括离线业务如报表等)
  • 管理平台
    • 身份认证
    • 权限管理
© 2019 GuoYL's Notes All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero