软件架构技术1:架构复杂度来源与架构设计的原则

129 阅读24分钟

一、什么是架构


简单的理解,架构就是结构,是部分组成整体的方式。

在建筑行业中,你可能听说过剪力墙结构:用钢筋混凝土墙板来代替框架结构中的梁柱,能承担各类荷载引起的内力,并能有效控制结构的水平力。这种用钢筋混凝土墙板来承受竖向和水平力的结构称为剪力墙结构。

图片

图 剪力墙结构

在企业架构上下文中,架构是针对某种特定目标系统的具有体系性的、普遍性的问题而提供的通用的解决方案,架构往往是对复杂形态的一种共性的体系抽象。

在 ISO/IEC 42010:20072 中对架构有如下定义:

一个架构是系统的基本结构,它由多个组件以及它们彼此间的关系而组成,并且在一定环境和原则下进行设计和演变。

图片从定义中可以看出架构的几个要素:架构=组件+关系+设计和演进原则

二、架构设计的目的


架构的重要性在哪里?

图片

质量属性

在现实的系统中,在决定系统的成功或失败的因素中,满足非功能需求往往比满足功能性需求更为重要。
图片

架构设计的目的是什么?

如果没有架构设计,说明你的系统不够复杂。随着业务的增长,系统由单体应用渐进演化为分布式和微服务化。系统整体的复杂性越来越高,技术团队可能从一个团队变成多个专业化团队。假如没有架构设计,系统定会是一个无序失控的状态,带来的问题:

1、应用服务的边界不是很清晰:到底该怎么拆分没有一个明确的原则,研发人员为了所谓微服务化而拆分,而不是从当前业务考虑。导致系统无序的状态,开发效率低。

我们系统出现过类似的情况:一个简单项目拆分成 8 个子服务,问他为什么这么拆分,说微服务化是为了应对以后扩展方便。结果这个项目从 2017 年到现在都没有再修改过,接手人宁愿新开发一个项目也不愿重构。

2、应用服务层次不清晰,系统耦合严重:导致服务依赖出现网状依赖结构,牵一发动全身,后续修改和扩展困难。

3、系统应用服务跟踪问题:由于微服务化后,系统逻辑复杂,服务出现问题后,你很难快速的定位问题和修复。这是我们踩过不少坑,我们使用 dubbo 服务化,系统一旦出现问题,一推人手忙脚乱。

4、系统服务监控问题:由于研发人员基本没有服务监控意识,都是出现问题后再想办法如何添加服务监控接口。

5、技术体系失控问题:不同的开发团队使用不同的技术栈或者组件,造成公司内部的技术架构失控。甚至研发人员为追求时髦新潮技术,拿应用项目来试验新技术。

架构设计的目的是为了解决系统复杂性带来的问题,其本质就是对系统进行有序化地重构以致符合当前业务的发展,并可以快速扩展。从上面架构的定义,也知道架构设计的作用涉及四方面:

1、系统性思考的合理决策。

2、明确的系统骨架。

3、系统协作关系。

4、约束规范和指导原则。

架构的本质是管理和解决系统的复杂性,提高效率。管理复杂性:对系统进行有序化重构,不断减少系统的“熵”,使系统不断进化,改善软件质量为目的的内在结构性变化;提高效率:对系统进行有序化重构,以符合当前业务的发展,并可以快速扩展。

无论是何种变化,架构师通过理解业务,全局把控,权衡业务需求和技术实现,选择合适技术,解决关键问题、指导研发落地实施,促进业务发展,提高效率。那什么样的系统要考虑做架构设计? 技术不会平白无故的出和自驱动发展起来,而架构的发展和需求是基于业务的驱动:

  • 需求相对复杂
  • 非功能性需求在整个系统占据重要位置
  • 系统生命周期长,有扩展性需求
  • 系统基于组件或者集成的需要
  • 业务流程再造的需要 

三、架构复杂度来源


架构的本质就是解决业务和技术变化带来的复杂性。 我们来谈一下复杂性到底来自于哪里。

业务复杂性

系统首先要满足当前的业务需求,在此基础上,还要满足将来的业务需求,因此系统要能不断地扩展变化,包括调整现有功能,以及增加新功能。

而且,系统的功能变化不能影响现有业务,不要一修改,就牵一发动全身,到处出问题。因此,在架构设计上,要做到系统的柔性可扩展,能够根据业务变化做灵活的调整。

此外,市场不等人,上新业务要快,之前花了半年上了个业务,这回再上个类似的新业务,需要短时间就能落地。因此,架构设计上,还要做到系统功能的可重用,这样才能通过快速复用,实现业务敏捷和创新。

技术复杂性

要保证一个业务能正常运行,除了满足业务功能之外,还要保证这个系统稳定可用。

一个复杂系统是由很多部分组成的,如应用程序、服务器、数据库、网络、中间件等,都可能会出问题。那怎么在出问题时,能够快速恢复系统或者让备用系统顶上去呢?

还有流量问题,平时流量不大,少量机器就可以处理,但在大促的时候,大量流量进来,系统是不是能够通过简单地加机器方式就能支持呢?

此外还有低成本的问题,系统能否做到,使用廉价设备而不是高大上的IOE设备,使用免费的开源组件而不是昂贵的商业套件,使用虚拟化技术而不是物理机,并且在流量低谷和高峰的不同时期,让系统能够弹性缩容和扩容呢?

因此,一个好的架构设计既要满足****业务的可扩展、可复用 ;也要满足系统的****高可用、高性能和可伸缩 ,并尽量采用低成本的方式落地。所以,对架构设计来说,技术和业务两手都要抓,两手都要硬。下面对着几个方面进行展开分析:

1 复杂度来源:高性能

性能是软件的一个重要质量属性。衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标,也可以是用户的主观感受。

高性能可以从垂直与水平两个维度来考虑。垂直维度主要是针对单台计算机,通过升级软、硬件能力实现性能提升;水平维度则主要针对集群系统,利用合理的任务分配与任务分解实现性能的提升。

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

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

2 复杂度来源:高可用

定义可用性,可以先定义什么是不可用。需要经历若干环节,网站的页面才能呈现在最终的用户面前;而其中的任何一个环节出现了故障,都可能会导致网站的页面不可访问,也就是出现了网站不可用的情况。

我们可以利用百分比来对网站可用性进行度量:

网站不可用时间=完成故障修复的时间点 - 故障发现的时间点

网站年度可用时间=年度总时间 - 网站不可用时间

网站年度可用性=(网站年度可用时间/年度总时间) x 100%

网站高可用的主要技术手段是服务与数据的冗余备份与失效转移。同一服务组件部署在多台服务器上;数据存储在多台服务器上互相备份。通过上述技术手段,当任何一台服务器宕机或出现各种不可预期的问题时,就将相应的服务切换到其他可用的服务器上,不影响系统的整体可用性,也不会导致数据丢失。

3 复杂度来源:可扩展性

可扩展性指系统为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无须整个系统重构或者重建。设计具备良好可扩展性的系统,有两个基本条件:正确预测变化、完美封装变化

设计具备良好可扩展性的系统,有两个思考角度:

(1)在业务维度。对业务深入理解,对业务的发展方向进行预判,也就是不能完全不考虑可扩展性;但是,变化无处不在,在业务看得远一点的同时,需要注意:警惕过度设计;不能每个设计点都考虑可扩展性;所有的预测都存在不正确的可能性。

(2)在技术维度。预测变化是一回事,采取什么方案来应对变化,又是另外一个复杂的事情。即使预测很准确,如果方案不合适,则系统扩展一样很麻烦。第一种应对变化的常见方案是将“变化”封装在一个“变化层”,将不变的部分封装在一个独立的“稳定层”。第二种常见的应对变化的方案是提炼出一个“抽象层”和一个“实现层”。

在实际软件系统架构设计中,常通过以下技术手段实现良好的可扩展性:

(1)使用分布式服务(框架)构建可复用的业务平台。

(2)使用分布式消息队列降低业务模块间的耦合性。

4 复杂度来源:低成本

低成本是架构设计中需要考虑一个约束条件,但不会是首要目标。低成本本质上是与高性能和高可用冲突的,当无法设计出满足成本要求的方案,就只能协调并调整成本目标。一般通过“创新”达到低成本的目标。

(1)引入新技术。主要复杂度在于需要去熟悉新技术,并且将新技术与已有技术结合;一般中小型公司基本采用该方式达到目标。

(2)开创一个全新技术领域。主要复杂度在于需要去创造全新的理念和技术,并且与旧技术相比,需要有质的飞跃,复杂度更高;一般大公司拥有更多的资源、技术实力会采用该方式来达到低成本的目标。

5 复杂度来源:安全

安全是一个庞大而又复杂的技术领域,一旦出问题,对业务和企业形象影响非常大。从技术的角度来讲,包括

(1)功能安全。减少系统潜在的缺陷,阻止黑客破坏行为,是一个逐步完善的过程,而且往往都是在问题出现后才能有针对性的提出解决方案,与编码实现有关。

(2)架构安全。保护系统不受恶意访问和攻击,保护系统的重要数据不被窃取。由于是蓄意破坏系统,因此对影响也大得多。传统企业主要通过防火墙实现不同区域的访问控制,功能强大、性能一般,但是成本更高。互联网企业更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现。

6 复杂度来源:规模

规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。随着业务的发展,规模带来的常见复杂度有

(1)业务功能越来越多,调用逻辑越来越复杂;

(2)数据容量、类型、关联关系越来越多。规模问题需要与高性能、高可用、高扩展、高伸缩性统一考虑。常采用“分而治之,各个击破”的方法策略。

四、架构设计的原则


(一)架构设计的3个战略原则

1、合适原则

原则宣言:“合适优于业界领先。”这里主要说的是,我们在设计架构的时候,要脚踏实地,从当前的业务需求出发,设计一个符合我们当前现状的系统。比如我们做一个校园的图书管理系统,开发人员可能就两三个,数据库简单的使用MySQL就能够满足。这个时候,如果我们追求规模化、高性能、高可用,采用各种业界顶尖的架构和技术。那么其结果最终是浪费居多,而且功能还不一定能满足需求。再举个简单点的例子,我们要去一公里外的超市买东西,可能步行十分钟就到了,但是为了酷炫,采用最顶尖的飞机,那么可能完全就是一种浪费。当然,这也只是一个玩笑罢了。这里有几个经验:

(1)技术选型以需求为主,而不是人员现状

经常看到这样的情况,在做技术选型决策时,明知某种技术是最优的,但还是选择当前团队掌握的技术。这种决策可以理解,但对产品长远发展不利,极有可能在与竞品的PK中落于下风。公司在这方面已经有很多教训,比如以前某事业部曾经把PHP作为主要技术路线,理由是团队就会这个,后来发现对于大中型系统来说,脚本型的PHP的代码实在是难以维护,不得不推倒用JAVA重来。

(2)重视成本

很多架构师可能有这样一种思维,把架构设计得简单了,会显得自己很平庸,弄一个高大上的架构出来,方显本事,在领导面前述职时也有善可陈。可是,如果太超前去搞这种复杂的架构,会白白增加成本。

架构师的每一个决定都会影响到成本,包括研发成本、第三方软硬件采购成本和上线后的运营成本。不同的方案,在成本分布和最终的总体成本上会不尽相同。往往需要综合权衡,才能决策出成本最优的方案。

成本关系着企业利润,最终也会影响到个人奖金。这种因果关系的体现周期虽然较长,也不是很透明直接,但道理不会错。希望大家能树立起成本意识,每做一个决策前,先问问自己,这个方案会花费多少成本?

(3)既要有拿来主义,也不能生搬硬套

经常看到两种极端,有的人做设计,完全是拿来主义,不从自己系统的实际情况出发;而另一种人,则完全自己发挥,不去调查类似系统的设计方案。这两种情况都不可取。应该从自己系统的实际需求出发,在参考别人成熟案例的基础上,少走弯路,并考虑自己系统的特点,给出符合自身需求的设计。

(4)基于约束来考虑技术方案

方案设计之前,首先明确一些约束条件,基于这些约束去考虑,可能会少走一些弯路。比如有些系统,部署环境往往就是两三台物理机,在这种情况下,复杂的架构肯定是不适合的。经常看到有的系统,上来就搞了一大套复杂设计,好象挺高大上、与时俱进,到了临上线时才发现资源有限,大部分使用方也不太喜欢这样重量级的东西,后面不得不再搞裁剪,白白浪费精力。

2、简单原则

原则宣言:“简单优于复杂。”软件架构的目的就是为了降低软件系统的复杂度。对于一个业务软件来说,其复杂度主要来源于结构的复杂性和逻辑的复杂性。结构的复杂性要是要看组成业务系统的组件数量有多少,如果组件更多,那么复杂性则是指数般增长,同时,一个组件的问题,可能会引起大范围的连锁反应。另外一个方面,如果我们把所有功能都集中到一个组件里面,就会引起逻辑复杂度的极限上升,当对这个组件进行维护开发时,所有几十号人集中在一起,大部分时间都浪费在代码冲突、问题溯源等等上面了。所以,如果我们同时面临一个简单的架构设计方案和一个复杂的架构师设计方案,同时这两个方案都可以满足需求,那么最好选择简单的方案。

(1)适度设计

适度设计应该是架构设计的第一原则。对于不同规模的问题,解决方案有所不同,其成本可能会有巨大差距。每个解决方案也都有自己适用的范围,骑自行车到不了月球,飞机也不能把你送到小区门口买菜。

架构设计应以满足一定周期内的需求为目标,周期一般考虑一年即可,需求包括功能性的和非功能性的。在这两方面都满足,并考虑一定的前瞻性的前提下,架构应尽量简单,以降低成本,缩短实现周期,使质量更高。以下是一些常见的考虑:

◆能少一个组件就少一个组件

要有这样的意识,每增加一个组件,包括研发、测试、运维、硬件资源占用的总体成本就会上升数万元。

◆能不用微服务就不用微服务

微服务是有一些优点,但缺点也很明显:响应时间增加、综合成本上升、管理复杂度高。对于中小型系统、不需要频繁发布的系统,采用微服务架构就像是杀鸡用牛刀。

◆ 能不用分布式就不用分布式

使用分布式技术的前提是处理能力需求超出了单机的能力上限。经常看到一些解决方案在单机能力尚有较多富余时就早早引入分布式技术,白白增加了系统复杂度,引起成本上升。

(2)避免问题扩大化

解决一个问题时尽量直接解决,不要间接解决而引入新的问题。经常看到有的系统,数据库刚出了一点性能问题,就开始考虑分库分表之类。这个时候,应当首先解决导致性能问题的直接原因,比如慢查询、表设计不合理等,万不得已才考虑分库分表以及引入一些数据访问中间件。在引入数据访问中间件之前,还可以考虑在驱动级别解决问题,以避免增加进程级的组件,引起管理复杂度上升和性能下降。

3、演化原则

原则宣言:“演化优于一步到位。”软件架构设计是一个不断进化的过程。因为我们的眼界限制,我们业务规模限制,一开始的软件架构是要满足设计当下的业务需要。逐步的,软件架构不断地在实际应用过程中升级和迭代,留下优秀的设计,改正错误的设计,去掉无用的设计,让我们的架构逐渐完善。再接下来,当业务发生变化时,我们的架构要扩展、重构,架构设计的方案甚至打翻重来,但有价值的经验、教训、逻辑、设计等却可以在新架构中延续。

其实软件的变化就好比生物的进化,并不是一蹴而就的。它也有一个演变的过程。

(1)首先,设计出来的架构要满足当前的业务需求(毕竟公司盈利是首要目的,不然,哪有钱发工资或者享受公司的各种福利呢);

(2)其次,架构要不断地在实际应用过程中迭代,保留优秀的设计,修复有缺陷的设计,改正错误的设计,去掉无用的设计,使得架构逐渐完善;

(3)最后,当业务发生变化时,架构要扩展、重构,甚至重写;代码也许需要重写,但有价值的经验、教训、逻辑、设计等(类似生物的基因)却可以在新架构中延续下去;

架构师在进行架构设计时需要牢记这个原则,时刻提醒自己不要贪大求全或者盲目照抄。应该认真分析当前业务的特点,明确业务所面临的主要问题,设计合理的架构,快速落地以满足业务需要,然后再运行过程中不断完善架构,不断随着业务演化架构。

(二)架构设计的10个战术原则

1.全面解耦原则: 对业务进行抽象建模,业务数据与业务逻辑解耦,软硬件解耦,平台和产品解耦,系统各部件解耦。模块、组件高内聚,低耦合。

2.服务化/组件化原则: 以服务、数据为中心,构建服务化、组件化架构,具备灵活,按需组合的能力。

3.接口隔离及服务自治原则: 通过接口隐藏服务/组件实现细节,服务/组件只能通过接口进行交互,接口契约化,标准化,跨版本兼容;服务/组件可独立发展、独立发布、独立升级,服务自治,可视、可管、可控、可测、可维,故障自愈。

4.弹性伸缩原则: 构建全分布云化架构,或借鉴云化架构思想,每个服务具备横向扩展能力,支持按需使用,自动弹性伸缩,可动态替换、灵活部署,支撑高性能、高吞吐量、高并发、高可用业务场景。

5.安全可靠环保原则: 构建最小权限,纵深防御、最小公共化、权限分离、不轻信、开放设计、完全仲裁、失效安全、保护薄弱环节、安全机制、经济性、用户接受度以及加强隐私保护的安全体系,确保系统、网络和数据的机密性、完整性、可用性、可追溯性;以业务系统零故障为导向;按需构筑分层分级的可靠性,通过故障的预流、预防、快速故障恢复、避免故障发生;系统资源使用有效最大化,实现节能、节地、节材、环保。

6.用户体验和自动化运维原则: 面向业务获取和使用场景,构建实时、按需、在线、自助、社区化、方便易用的用户体验;支持远程、自动、智能、安全、高效地完成网规/网设、安装、部署、调测、验收、扩缩容、软件升级、打补丁、日常维护、问题处理。

7.开放生态原则: 面向生态场景,按需开放平台设施、中间件、数据、业务逻辑、UI等能力;构建开放生态、支持分层、远程、自动、自助、简单高效地完成定制、集成、第三方应用开发。

8.高效开发原则: 创建支持迭代、增量、持续交付的架构,支持部件独立开发、自动化编译构建、测试、集成验证、并易于高效修改和持续优化;支持开发组织小型化,扁平化,支持小团队独立高效并行开发。

9.柔性供应制造原则: 模块化设计,模块/物料归一化、标准化,支持自动化、数字化、智能化、随需应变的柔性制造。

10.持续演进原则: 架构并非一蹴而就,需要有效地管理架构需求;持续构建和发展架构,适应业务需求变化,适时引入业界最佳实践,及时重构,确保架构生命力和竞争力

五、常见架构误区

误区 1——架构专门由架构师来做,业务开发人员无需关注

架构的再好,最终还是需要代码来落地,并且组织越大这个落地的难度越大。不单单是系统架构,每个解决方案每个项目也由自己的架构,如分层、设计模式等。如果每一块砖瓦不够坚固,那么整个系统还是会由崩塌的风险。所谓“千里之堤,溃于蚁穴”。

误区 2——架构师确定了架构蓝图之后任务就结束了

架构不是“空中楼阁”,最终还是要落地的,但是架构师完全不去深入到第一线怎么知道“地”在哪?怎么才能落的稳稳当当。

误区 3——不做出完美的架构设计不开工

世上没有最好架构,只有最合适的架构,不要企图一步到位。我们需要的不是一下子造出一辆汽车,而是从单轮车 --> 自行车 --> 摩托车,最后再到汽车。想象一下 2 年后才能造出的产品,当初市场还存在吗?

误区 4—— 为虚无的未来埋单而过度设计

在创业公司初期,业务场景和需求边界很难把握,产品需要快速迭代和变现,需求频繁更新,这个时候需要的是快速实现。不要过多考虑未来的扩展,说不定功能做完,效果不好就无用了。如果业务模式和应用场景边界都已经比较清晰,是应该适当的考虑未来的扩展性设计。

误区 5——一味追随大公司的解决方案

由于大公司巨大成功的光环效应,再加上从大公司挖来的技术高手的影响,网站在讨论架构决策时,最有说服力的一句话就成了“淘宝就是这么搞的”或者“腾讯 就是这么搞的”。

大公司的经验和成功模式固然重要,值得学习借鉴,但如果因此而变得盲从,就失去了坚持自我的勇气,在架构演化的道路上迟早会迷路。

误区 6——为了技术而技术

技术是为业务而存在的,除此毫无意义。在技术选型和架构设计中,脱离网站业务发展的实际,一味追求时髦的新技术,可能会将技术发展引入崎岖小道,架构之路越走越难。考虑实现成本、时间、人员等各方面都要综合考虑,理想与现实需要折中。

原文摘自《软件架构技术1:架构复杂度来源与架构设计的原则