从零开始学架构一
架构设计的目的
架构设计的真正目的是为了解决软件系统复杂度带来的问题
高性能
高性能带来的复杂度主要体现的两方面,一是单台计算机内部为了高性能带来的复杂度;二是是多台计算机集群为了高性能带来的复杂度
1 WHAT 对高性能的理解?
性能是软件的一个重要质量属性。衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标,也可以是用户的主观感受(从程序员、业务用户、终端用户/客户不同的视角,可能会得出不同的结论)。
在说性能的时候,有一个概念与之紧密相关—伸缩性,这是两个有区别的概念。性能更多的是衡量软件系统处理一个请求或执行一个任务需要耗费的时间长短;而伸缩性则更加关注软件系统在不影响用户体验的前提下,能够随着请求数量或执行任务数量的增加(减少)而相应地拥有相适应的处理能力。
但是,什么是“高”性能?这可能是一个动态概念,与当前的技术发展状况与业务所处的阶段紧密相关。比如,现在在行业/企业内部认为的高性能,站在5年后来看,未必是高性能。因此,站在架构师、设计师的角度,高性能需要和业务所处的阶段来衡量。高到什么程度才能与当前或可预见的未来业务增长相匹配。一味去追求绝对意义上的高,没有太大的实际意义。因为,伴随性能越来越高,相应的方法和系统复杂度也是越来越高,而这可能会与当前团队的人力、技术、资源等不相匹配。但是什么才合适的高性能了?这可能需要从国、内外的同行业规模相当、比自己强的竞争者、终端用户使用反馈中获取答案并不断迭代发展。
软件系统中高性能带来的复杂度主要体现在两方面,一方面是单台计算机内部为了高性能带来的复杂度;另一方面是多台计算机集群为了高性能带来的复杂度。
2 WHY 为什么需要高性能?
追求良好的用户体验;
满足业务增长的需要。
3 HOW 如何做好高性能?
可以从垂直与水平两个维度来考虑。垂直维度主要是针对单台计算机,通过升级软、硬件能力实现性能提升;水平维度则主要针对集群系统,利用合理的任务分配与任务分解实现性能的提升。
垂直维度可包括以下措施:
增大内存减少I/O操作
更换为固态硬盘(SSD)提升I/O访问速度
使用RAID增加I/O吞吐能力
置换服务器获得更多的处理器或分配更多的虚拟核
升级网络接口或增加网络接口
水平维度可包括以下措施:
功能分解:基于功能将系统分解为更小的子系统
多实例副本:同一组件重复部署到多台不同的服务器
数据分割:在每台机器上都只部署一部分数据
垂直维度方案比较适合业务阶段早期和成本可接受的阶段,该方案是提升性能最简单直接的方式,但是受成本与硬件能力天花板的限制。
水平维度方案所带来的好处要在业务发展的后期才能体现出来。起初,该方案会花费更多的硬件成本,另外一方面对技术团队也提出了更高的要求;但是,没有垂直方案的天花板问题。一旦达到一定的业务阶段,水平维度是技术发展的必由之路。因此,作为技术部门,需要提前布局 ,未雨绸缪,不要被业务抛的太远。
高可用
系统无中断地执行其功能的能力,代表系统的可用性程度,是进行系统设计时的准则之一。
计算高可用
“计算”指的是业务的逻辑处理。
储存高可用
存储高可用不可能同时满足“一致性、可用性、分区容错性”
高可用状态决策
1.独裁式
独裁式决策指的是存在一个独立的决策主体,我们姑且称它为“决策者”,负责收集信息然后进行决策;所有冗余的个体,我们姑且称它为“上报者”,都将状态信息发送给决策者。
2.协商式
协商式决策指的是两个独立的个体通过交流信息,然后根据规则进行决策,最常用的协商式决策就是主备决策。
3.民主式
民主式决策指的是多个独立的个体通过投票的方式来进行状态决策。例如,ZooKeeper集群在选举leader时就是采用这种方式。
可扩展性
1 What:什么是架构的可扩展性?
业务需求、运行环境方面的变化都会导致软件系统发生变化,而这种软件系统对上述变化的适应能力就是可扩展性。
可扩展性可以理解为是一种从功能需求方面考虑的软件属性,属性就会存在好坏之分。
按照可扩展性的定义,一个具备良好可扩展性的架构设计应当符合开闭原则:对扩展开放,对修改关闭。衡量一个软件系统具备良好可扩展性主要表现但不限于:
(1)软件自身内部方面。在软
件系统实现新增的业务功能时,对现有系统功能影响较少,即不需要对现有功能作任何改动或者很少改动。
(2)软件外部方面。软件系统本身与其他存在协同关系的外部系统之间存在松耦合关
系,软件系统的变化对其他软件系统无影响,其他软件系统和功能不需要进行改动。反之,则是一个可扩展性不好的软件系统。
2 Why:为什么要求架构具备良好的可扩展性?
伴随业务的发展、创新,运行环境的变化,对技术也就提出了更多、更高的要求。能够快速响应上述变化,并最大程度降低对现有系统的影响,是设计可扩展性好的架构的主要目的。
3 How:如何设计可扩展性好的架构?
面向对象思想、设计模式都是为了解决可扩展性的而出现的方法与技术。
设计具备良好可扩展性的系统,有两个思考角度:(1)从业务维度。对业务深入理解,对可预计的业务变化进行预测。(2)从技术维度。利用扩展性好的技术,实现对变化的封装。
(1)在业务维度。对业务深入理解,对业务的发展方向进行预判,也就是不能完全不考虑可扩展性;但是,变化无处不在,在业务看得远一点的同时,需要注意:警惕过度设计;不能每个设计点
都考虑可扩展性;所有的预测都存在不正确的可能性。
(2)在技术维度。预测变化是一回事,采取什么方案来应对变化,又是另外一个复杂的事情。即使预测很准确,如果方案不合适,则系统扩展一样很麻烦。第一种应对变化的常见方案是将“变
化”封装在一个“变化层”,将不变的部分封装在一个独立的“稳定层”。第二种常见的应对变化的方案是提炼出一个“抽象层”和一个“实现层”。
4.在实际工作场景中的解决方案
在实际软件系统架构设计中,常通过以下技术手段实现良好的可扩展性:
(1)使用分布式服务(框架)构建可复用的业务平台。
(2)使用分布式消息队列降低业务模块间的耦合性。
(1)分布式服务框架
利用分布式服务框架(如Dubbo)可以将业务逻辑实现和可复用组件服务分离开,通过接口降低子系统或模块间的耦合性。新增功能时,可以通过调用可复用的组件实现自身的业务逻辑,而对现
有系统没有任何影响。可复用组件升级变更的时候,可以提供多版本服务对应用实现透明升级,对现有应用不会造成影响。
(2) 分布式消息队列
基于生产者-消费者编程模式,利用分布式消息队列(如RabbitMQ)将用户请求、业务请求作为消息发布者将事件构造成消息发布到消息队列,消息的订阅者作为消费者从消息队列中获取消息进
行处理。通过这种方式将消息生产和消息处理分离开来,可以透明地增加新的消息生产者任务或者新的消息消费者任务。
成本、安全和规模
低成本
What:低成本是架构设计中需要考虑一个约束条件,但不会是首要目标。低成本本质上是与高性能和高可用冲突的,当无法设计出满足成本要求的方案,就只能协调并调整成本目标。
How:一般通过“创新”达到低成本的目标。(1)引入新技术。主要复杂度在于需要去熟悉新技术,并且将新技术与已有技术结合;一般中小型公司基本采用该方式达到目标。(2)开创一个全
新技术领域。主要复杂度在于需要去创造全新的理念和技术,并且与旧技术相比,需要有质的飞跃,复杂度更高;一般大公司拥有更多的资源、技术实力会采用该方式来达到低成本的目标。
安全
What:安全是一个庞大而又复杂的技术领域,一旦出问题,对业务和企业形象影响非常大。从技术的角度来讲,包括(1)功能安全-“防小偷”,减少系统潜在的缺陷,阻止黑客破坏行为;
(2)架构安全—“防强盗”,保护系统不受恶意访问和攻击,保护系统的重要数据不被窃取。由于是蓄意破坏系统,因此对影响也大得多。架构设计时需要特别关注架构安全。
How:(1)功能安全。是一个逐步完善的过程,而且往往都是在问题出现后才能有针对性的提出解决方案,与编码实现有关。(2)架构安全。传统企业主要通过防火墙实现不同区域的访问控
制,功能强大、性能一般,但是成本更高。互联网企业更多地是依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现。
规模
What:规模带来复杂度的主要原因就是“量变引起质变”,当数量超过一定的阈值后,复杂度会发生质的变化。随着业务的发展,规模带来的常见复杂度有
(1)业务功能越来越多,调用逻辑越
来越复杂;
(2)数据容量、类型、关联关系越来越多。
How:规模问题需要与高性能、高可用、高扩展、高伸缩性统一考虑。常采用“分而治之,各个击破”的方法策略。
是否还有其他复杂度原因?- 可伸缩性
当前大型互联网网站需要面对大量用户高并发访问、存储更多数据、处理更高频次的用户交互。网站系统一般通过多种分布式技术将多台服务器组成集群对外提供服务。伸缩性一般是系统可以根据需求和成本调整自身处理能力的一种能力。伸缩性常意味着系统可以通过低成本并能够快速改变自身的处理能力以满足更多用户访问、处理更多数据而不会对用户体验造成任何影响。
伸缩性度量指标包括(1)处理更高并发;(2)处理更多数据;(3)处理更高频次的用户交互。
其复杂度体现在
(1)伸——增强系统在上述三个方面的处理能力;
(2)缩——缩减系统处理能力;
(3)上述伸缩过程还必须相对低成本和快速。
架构的三个原则
架构即决策。架构需要面向业务需求,并在各种资源(人、财、物、时、事)约束条件下去做权衡、取舍。而决策就会存在不确定性。采用一些高屋建瓴的设计原则有助于去消除不确定,去逼
近解决问题的最优解。
1 合适原则
架构无优劣,但存合适性。“汝之蜜糖,吾之砒霜”;架构一定要匹配企业所在的业务阶段;不要面向简历去设计架构,高大上的架构不等于适用;削足适履与打肿充胖都不符合合适原则;所谓合适,一定要匹配业务所处阶段,能够合理地将资源整合在一起并发挥出最大功效,并能够快速落地。
2 简单原则
"我没有时间写一封短信,所以只好写一封长信"。其实,简单比复杂更加困难。面对系统结构、业务逻辑和复杂性,我们可以编写出复杂的系统,但在软件领域,复杂代表的是“问题”。架构设计时如果简单的方案和复杂的方案都可以满足需求,最好选择简单的方案。但是,事实上,当软件系统变得太复杂后,就会有人换一个思路进行重构、升级,将它重新变得简单,这也是软件开发的大趋势。 简单原则是一个朴素且伟大的原则,Google的MapReduce系统就采用了分而治之的思想,而背后就是将复杂问题转化为简单问题的典型案例。
3 演化原则
大到人类社会、自然生物,小到一个细胞,似乎都遵循这一普世原则,软件架构也不例外。业务在发展、技术在创新、外部环境在变化,这一切都是在告诫架构师不要贪大求全,或者盲目照搬大公司的做法。应该认真分析当前业务的特点,明确业务面临的主要问题,设计合理的架构,快速落地以满足业务需要,然后在运行过程中不断完善架构,不断随着业务演化架构。怀胎需要十月,早一月或晚一月都很危险。