初识架构01--概念

来源: 《从0开始学架构》(极客时间) ---李运华

架构的定义

要想准确理解架构的定义,关键在与把一下三组概念梳理清楚。

  • 系统与子系统
  • 模块与组件
  • 框架与架构

系统与子系统

系统

系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。它的意思是“总体”“整体”或“联盟”。

  • 关联
    系统是由一群有关联的个体组成的,没有关联的个体堆在一起不能成为一个系统。例如,把一个发动机和一台 PC 放在一起不能称之为一个系统,把发动机、底盘、轮胎、车架组合起来才能成为一台汽车。
  • 规则
    系统内的个体需要按照指定的规则运作,而不是单个个体各自为政。规则规定了系统内个体分工和协作的方式。例如,汽车发动机负责产生动力,然后通过变速器和传动轴,将动力输出到车轮上,从而驱动汽车前进。
  • 能力
    系统能力与个体能力有本质的差别,系统能力不是个体能力之和,而是产生了新的能力。例如,汽车能够载重前进,而发动机、变速器、传动轴、车轮本身都不具备这样的能力。

子系统

子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。

一个系统的架构,只包括顶层这一个层级的架构,而不包括下属子系统层级的架构。

模块与组件

模块和组件都是系统的组成部分,只是从不同的角度拆分系统而已。

从业务逻辑的角度来拆分系统后,得到的单元就是“模块”;从物理部署的角度来拆分系统后,得到的单元就是“组件”。划分模块的主要目的是职责分离;划分组件的主要目的是单元复用。

框架与架构

框架

软件框架(Software framework)通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。

如:

  1. 框架是组件规范:例如,MVC 就是一种最常见的开发规范,类似的还有 MVP、MVVM、J2EE 等框架。
  2. 框架提供基础功能的产品:例如,Spring MVC 是 MVC 的开发框架,除了满足 MVC 的规范,Spring 提供了很多基础功能来帮助我们实现功能,包括注解(@Controller 等)、Spring Security、Spring JPA 等很多基础功能。

架构

软件架构指软件系统的“基础结构”,创造这些基础结构的准则,以及对这些结构的描述。

单纯从定义的角度来看,框架和架构的区别还是比较明显的:框架关注的是“规范”,架构关注的是“结构”。框架是一整套开发规范,架构是某一套开发规范下的具体落地方案,包括各个模块之间的组合关系以及它们协同起来完成功能的运作规则。

重新定义架构

软件架构指软件系统的顶层(Rank)结构,它定义了系统由哪些角色(Role)组成,角色之间的关系(Relation)和运作规则(Rule)。

架构的目的

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

架构设计需要充分考虑业务设计场景,不要过度设计,需要因地制宜,没有适用一切的银弹。

结构即决策

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

架构复杂度的来源

高性能

分为单机复杂度和集群复杂度,单机复杂度主要是多进程,多线程的取舍问题。

集群复杂度

1. 任务分配

  1. 需要增加任务分配器来进行任务分配
  2. 任务分配器和业务系统的连接与交互
  3. 分配算法,是随机分配,轮询分配还是根据负载分配

随着性能要求的增加,任务分配器本身也可能成为瓶颈,这时任务分配器也需要扩展为集群的架构。

2. 任务分解
把大一统但复杂的业务系统,拆分成小而简单的需要多个系统进行配合的业务系统

  • 简单的系统容易开发,且不容易出错
  • 系统拆分后容易发现瓶颈,并针对特定系统进行扩展而不影响这个系统

高可用

高可用指系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。

硬件和软件都可能存在问题,甚至外部环境如火灾、地震等也可能导致系统不可用,一般是通过冗余来实现高可用的。

计算高可用

无论在哪台机器上进行计算,同样的算法和输入数据,产出的结果都是一样的

存储高可用

存储高可用与计算高可用有一个本质的区别:即将数据从一台机器搬到到另一台机器,需要经过线路进行传输。

存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响。

分布式领域里面有一个著名的CAP定理,从理论上论证了存储高可用的复杂度。也就是说,存储高可用不可能同时满足“一致性、可用性、分区容错性”,最多满足其中两个。

高可用状态决策

无论是计算高可用还是存储高可用,其基础都是“状态决策”,即系统需要能够判断当前的状态是正常还是异常,如果出现了异常就要采取行动来保证高可用。如果状态决策本身都是有错误或者有偏差的,那么后续的任何行动和处理无论多么完美也都没有意义和价值。但在具体实践的过程中,恰好存在一个本质的矛盾:通过冗余来实现的高可用系统,状态决策本质上就不可能做到完全正确。

独裁式

独裁式决策指的是存在一个独立的决策主体,我们姑且称它为“决策者”,负责收集信息然后进行决策。

独裁式的决策方式不会出现决策混乱的问题,因为只有一个决策者,但问题也正是在于只有一个决策者。当决策者本身故障时,整个系统就无法实现准确的状态决策。如果决策者本身又做一套状态决策,那就陷入一个递归的死循环了。

协商式

协商式决策指的是两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策就是主备决策。

民主式

民主式决策指的是多个独立的个体通过投票的方式来进行状态决策。

民主式决策和协商式决策比较类似,其基础都是独立的个体之间交换信息,每个个体做出自己的决策,然后按照“多数取胜”的规则来确定最终的状态。

民主式决策有一个固有的缺陷:脑裂。为了解决脑裂问题,民主式决策的系统一般都采用“投票节点数必须超过系统总节点数一半”规则来处理。

可扩展性

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

一个具备良好可扩展性的架构设计应当符合开闭原则:对扩展开放,对修改关闭。

预测变化

预测变化的复杂度在于:

  1. 不能每个设计点都考虑可扩展性。
  2. 不能完全不考虑可扩展性。
  3. 所有的预测都存在出错的可能性。

对于架构师来说,如何把握预测的程度和提升预测结果的准确性,是一件很复杂的事情,而且没有通用的标准可以简单套上去,更多是靠自己的经验、直觉。同时需要注意:警惕过度设计,不能每个设计点都考虑可扩展性。

2年法则

只预测 2 年内的可能变化,不要试图预测 5 年甚至 10 年后的变化。

应对变化

提炼出“变化层”和“稳定层”

将不变的部分封装在一个独立的“稳定层”,将“变化”封装在一个“变化层”。这种方案的核心思想是通过变化层来隔离变化。

提炼出“抽象层”和“实现层”

核心思想就是通过实现层来封装变化。

重构原则

如果一开始无法预测变化,则可以先不考虑复杂的可扩展性,而是等到第三次遇到类似的事情的时候再来重构,重构的时候采取隔离或者封装的方案。

低成本

当我们设计“高性能”“高可用”的架构时,通用的手段都是增加更多服务器来满足“高性能”和“高可用”的要求;而低成本正好与此相反,我们需要减少服务器的数量才能达成低成本的目标。因此,低成本本质上是与高性能和高可用冲突的,所以低成本很多时候不会是架构设计的首要目标,而是架构设计的附加约束。

低成本给架构设计带来的主要复杂度体现在,往往只有“创新”才能达到低成本目标。这里的“创新”既包括开创一个全新的技术领域(这个要求对绝大部分公司太高),也包括引入新技术,如果没有找到能够解决自己问题的新技术,那么就真的需要自己创造新技术了。

安全

安全本身是一个庞大而又复杂的技术领域,并且一旦出问题,对业务和企业形象影响非常大。

从技术的角度来讲,安全可以分为两类:一类是功能上的安全,一类是架构上的安全。

  1. 功能安全
    例如,常见的 XSS 攻击、CSRF 攻击、SQL 注入、Windows 漏洞、密码破解等,本质上是因为系统实现有漏洞,黑客有了可乘之机。黑客会利用各种漏洞潜入系统,这种行为就像小偷一样,黑客和小偷的手法都是利用系统或家中不完善的地方潜入,并进行破坏或者盗取。因此形象地说,功能安全其实就是“防小偷”。
  2. 架构安全
    如果说功能安全是“防小偷”,那么架构安全就是“防强盗”。传统的架构安全主要依靠防火墙,防火墙最基本的功能就是隔离网络,通过将网络划分成不同的区域,制定出不同区域之间的访问控制策略来控制不同信任程度区域间传送的数据流。
    防火墙的功能虽然强大,但性能一般,互联网系统的架构安全目前并没有太好的设计手段来实现,更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现。

规模

规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。常见的规模带来的复杂度有:
1. 功能越来越多,导致系统复杂度指数级上升
主要原因在于随着系统功能数量增多,功能之间的连接呈指数级增长。
2. 数据越来越多,系统复杂度发生质变
最近几年火热的“大数据”就是在这种背景下诞生的。大数据单独成为了一个热门的技术领域,主要原因就是数据太多以后,传统的数据收集、加工、存储、分析的手段和工具已经无法适应,必须应用新的技术才能解决。

架构设计三原则

相比编程来说,架构设计并没有像编程语言那样的语法来进行约束,更多的时候是面对多种可能性时进行选择。

合适原则

合适原则宣言:“合适优于业界领先”。

优秀的技术人员都有很强的技术情结,当他们做方案或者架构时,总想不断地挑战自己,想达到甚至优于业界领先水平是其中一个典型表现,因为这样才能够展现自己的优秀,然而最后却都以失败告终,原因体现在:

  1. 没那么多人,却想干那么多活。
  2. 没有那么多积累,却想一步登天。
  3. 没有那么卓越的业务场景,却幻想灵光一闪成为天才。

真正优秀的架构都是在企业当前人力、条件、业务等各种约束下设计出来的,能够合理地将资源整合在一起并发挥出最大功效,并且能够快速落地。

简单原则

简单原则宣言:“简单优于复杂”。

很多初出茅庐的架构师,会不自觉地追求架构的复杂性。然而,“复杂”在制造领域代表先进,在建筑领域代表领先,但在软件领域,却恰恰相反,代表的是“问题”。
1. 结构的复杂性
如果系统的组件数量很多,则这些组件之间的关系会很复杂。
2. 逻辑的复杂性
然而如果组件数量太少,则一个组件会承载太多的逻辑,增加单个组件的复杂性。

演化原则

演化原则宣言:“演化优于一步到位”。

对于软件来说,变化是永恒不变的主题。如果没有把握“软件架构需要根据业务发展不断变化”这个本质,在做架构设计的时候就很容易陷入一个误区:试图一步到位设计一个软件架构,期望不管业务如何变化,架构都稳如磐石。

架构设计流程

1. 识别复杂度

架构设计的本质目的是为了解决软件系统的复杂性,所以在我们设计架构时,首先就要分析系统的复杂性。只有正确分析出了系统的复杂性,后续的架构设计方案才不会偏离方向;否则,如果对系统的复杂性判断错误,即使后续的架构设计方案再完美再先进,都是南辕北辙,做的越好,错的越多、越离谱。

架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面,但架构师在具体判断复杂性的时候,不能生搬硬套,认为任何时候架构都必须同时满足这三方面的要求。实际上大部分场景下,复杂度只是其中的某一个,少数情况下包含其中两个,如果真的出现同时需要解决三个或者三个以上的复杂度,要么说明这个系统之前设计的有问题,要么可能就是架构师的判断出现了失误,即使真的认为要同时满足这三方面的要求,也必须要进行优先级排序。

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

2. 设计备选方案

虽然软件技术经过几十年的发展,新技术层出不穷,但是经过时间考验,已经被各种场景验证过的成熟技术其实更多。例如,高可用的主备方案、集群方案,高性能的负载均衡、多路复用,可扩展的分层、插件化等技术,绝大部分时候我们有了明确的目标后,按图索骥就能够找到可选的解决方案。

只有当这种方式完全无法满足需求的时候,才会考虑进行方案的创新,而事实上方案的创新绝大部分情况下也都是基于已有的成熟技术。

错误1:设计最优秀的方案。
错误2:只做一个方案。

  • 备选方案的数量以 3 ~ 5 个为最佳。
  • 备选方案的差异要比较明显。
  • 备选方案的技术不要只局限于已经熟悉的技术。

错误3:备选方案过于详细。

备选阶段关注的是技术选型,而不是技术细节,技术选型的差异要比较明显。

3. 评估和选择备选方案

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

常见的方案质量属性点有:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等。在评估这些质量属性时,需要遵循架构设计原则 1“合适原则”和原则 2“简单原则”,避免贪大求全,基本上某个质量属性能够满足一定时期内业务发展就可以了。

如果业务真的发展迅猛,也只需要遵循设计原则3“演化原则”,避免过度设计、一步到位的想法。按照原则 3 的思想,即使真的出现这种情况,那就算是重新做方案,代价也是可以接受的,因为业务如此迅猛发展,钱和人都不是问题。

在面临方案选择时,正确的做法是按优先级选择,即架构师综合当前的业务发展情况、团队人员规模和技能、业务发展预测等因素,将质量属性按照优先级排序,首先挑选满足第一优先级的,如果方案都满足,那就再看第二优先级……以此类推。那会不会出现两个或者多个方案,每个质量属性的优缺点都一样的情况呢?理论上是可能的,但实际上是不可能的。前面我提到,在做备选方案设计时,不同的备选方案之间的差异要比较明显,差异明显的备选方案不可能所有的优缺点都是一样的。

4. 详细方案设计

详细设计方案阶段可能遇到的一种极端情况就是在详细设计阶段发现备选方案不可行,一般情况下主要的原因是备选方案设计时遗漏了某个关键技术点或者关键的质量属性。幸运的是,这种情况可以通过下面方式有效地避免:

  1. 架构师不但要进行备选方案设计和选型,还需要对备选方案的关键细节有较深入的理解。
  2. 通过分步骤、分阶段、分系统等方式,尽量降低方案复杂度,方案本身的复杂度越高,某个细节推翻整个方案的可能性就越高,适当降低复杂性,可以减少这种风险。
  3. 如果方案本身就很复杂,那就采取设计团队的方式来进行设计,博采众长,汇集大家的智慧和经验,防止只有 1~2 个架构师可能出现的思维盲点或者经验盲区。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。