【摘要】个别地,架构模式大抵能够分成两类,单体架构(monolithic architecture)和分布式架构(distributed architecture)。

前言

谈到软件系统设计的方法论,在代码层面,有咱们相熟的23种设计模式(design pattern),对应到架构层面,则有所谓的架构模式(architecture pattern)。它们别离从宏观和宏观的角度领导着咱们设计出良好的软件系统,因而,作为一个软件工程师,咱们不仅要相熟设计模式,对常见的架构模式也要熟稔于心。正如看到一个设计模式的名字脑里就能浮现出大抵的结构图,当咱们看到一个架构模式的名字时,也要马上想到对应的架构图及其根本特点。比方,当谈到分层架构时,咱们就应该想起它的架构图是怎么的、有哪些杰出的架构特色(architecture characteristics)、零碎是如何部署的、数据存储的策略是哪种、等等。

个别地,架构模式大抵能够分成两类,单体架构(monolithic architecture)和分布式架构(distributed architecture)。本系列文章将会介绍以下8种罕用的架构模式:

单体架构

分层架构(Layered architecture)

管道架构(Pipeline architecture)

微内核架构(Microkernel architecture)

分布式架构

基于服务的架构(Service-based architecture)

事件驱动架构(Event-driven architecture)

基于空间的架构(Space-based architecture)

面向服务的架构(Service-oriented architecture)

微服务架构(Microservices architecture)

软件设计中的舛误

在介绍架构模式前,咱们先谈谈软件设计中的舛误(fallacy)。所谓舛误,就是在设计软件系统,特地是分布式系统时,咱们先入为主地假如它们是正确,但实际上并非如此的一些观点。这些观点都是咱们在设计软件时考虑不周的体现。

舛误1:网络是牢靠的

网络是不牢靠的

很多软件工程师经常假如网络是牢靠的,但理论并非如此。相比20年前,当初的网络会牢靠很多,然而依然具备很大的不确定性。如上图所述,Serivce B可能齐全是失常运行的,然而因为网络的问题,Service A收回的申请无奈达到Service B。一种更蹩脚的场景是,Service B能够收到Service A的申请,并解决了相干的数据,然而网络问题导致了Service A无奈收到Service B的响应,从而造成了数据不统一。网络的不牢靠也是为什么零碎中经常呈现服务通信超时、服务熔断等的起因。

总而言之,如果假如网络是牢靠的,那么咱们设计进去的软件系统将会是不牢靠的。

舛误2:时延是0

时延不为0

如上图所示,服务内组件间的函数/办法级别的调用,耗时是微秒,甚至是纳秒级别;然而服务间的近程调用(比方REST、音讯队列、RPC),耗时会是毫秒级别,甚至在异样场景会达到了秒级!在设计零碎,特地是分布式系统时,时延是一个无奈被忽视的因素,咱们必须分明零碎的均匀时延,否则设计进去的计划可能基本不可行。比方,假如零碎中服务间通信时延为100ms,如果一个申请的调用链波及到10个服务,那么该申请的时延将会是1000ms!这么高的均匀时延对于个别零碎来说是齐全无奈承受的。

进行零碎设计时,思考均匀时延还不够,更重要的是95th和99th百分点。一个零碎的均匀时延可能仅仅只有数十毫秒,然而95th百分点的时延却达到了数百毫秒,很多时候,这也恰好成为了拖垮整零碎性能的那块“短板”。

舛误3:带宽是有限的

带宽是无限的

在单体架构中,业务流程都在单服务内闭环,耗费的带宽很少甚至为0,因而带宽并不是次要关注点。一旦将零碎拆分成分布式架构,一个业务流程可能波及多个服务间的通信,带宽就成了必须思考的因素。带宽的有余,会导致网络变慢,从而影响零碎的时延(舛误2:时延是0)和可靠性(舛误1:网络是牢靠的)

如上图所示,假如在一个Web零碎中,Service A负责解决前端申请,Service B负责管理用户信息(包含姓名、性别、年龄等45个属性)。Service A每解决一个申请都须要向Service B查问用户姓名(200 bytes),而在一次申请中,Service B却返回了用户的所有信息(500 kb)。如果零碎每秒解决2000次申请,每次申请耗费500 kb带宽,那么每秒耗费的总带宽会是1 Gb!如果Service B仅仅返回必须的姓名,那么同等条件下,每秒耗费的总带宽仅仅是400 kb。

此类问题就是所谓的stampcoupling,解决办法也很多,比方在申请中增加属性抉择,应用GraphQL代替REST。相比于这些技术手段,更重要的是确定服务间通信所需的最小数据集,并在进行零碎设计时将其作为一个重点关注的因素

舛误4:网络是平安的

网络是不平安的

VPN、防火墙等的宽泛应用,使得很多工程师在设计零碎时疏忽了“网络是不平安的”这一重要准则。特地是从单体架构演进到分布式架构当前,零碎被攻打的概率将会大大增加。因而,在分布式系统中,每个服务都必须是平安的endpoint,这样能力确保任何未知或歹意的申请都被拦挡掉。当然,平安是有代价的,这也是像微服务架构这类细服务粒度的零碎,一次业务申请中调用链过长后性能极速降落的重要起因。

舛误5:网络拓扑变化无穷

网络拓扑是时常变动的

这里的网络拓扑指的是零碎运行时所波及到的网络设备,包含所有的路由器、防火墙、集线器、交换机等。很多工程师会假如网络拓扑是固定的,然而并非如此。

假如如下场景,为架构师的你在周一早上回到公司后,发现组内共事都在为零碎中所有的服务间通信都在一直呈现响应超时景象而抓狂,但奇怪的是周末并没有做服务变更。通过几个小时的攻关后,你发现周一凌晨2点时有过一次网络降级,而恰好是这次“主要”的网络降级,颠覆之前设计零碎时的时延假如,从而触发了本次事变。

因而,软件工程师也须要与网络管理员时常分割,确保在每次网络降级前都明确网络拓扑的变更点,从而做出相应的调整

舛误6:只有一个网络管理员

不只有一个网络管理员

网络管理员往往不止有一个,特地是在“云”时代,数据中心扩散在多个地区,天经地义也存在着多个局域网。运行在“云”上的零碎很有可能逾越多个数据中心,因而工程师们该当感知各个数据中心的网络管理员对网络的相干操作,提前做出应答措施,避免出现因网络拓扑变更(舛误5:网络拓扑变化无穷)而导致的服务通信超时,甚至触发服务熔断。

舛误7:通信老本为0

通信老本不为0

这里的通信老本并非指网络时延,而是指每减少一次服务间调用所导致的的花销。很多工程师在设计零碎时经常漠视掉通信老本,大家都在宣扬分布式架构绝对了单体架构的优越性,却遗记了它带来的服务器、防火墙、网关等硬件的数量减少,这些都是白花花的银子。

因而,在进行零碎设计时,咱们也应该将硬件资源和网络拓扑纳入思考因素。

舛误8:网络是同质的

网络并非同质的

很多工程师都会假如网络是同质的,也就是所有的网络设备都来自同一硬件厂商,这当然也是一个舛误。实际上,一个大的通信网络中,硬件设施往往来自于不同的厂商,这得益于网络协议规范的对立。厂商间设施的合作测试毕竟不会太充沛,在一些非凡场景下极有可能存在网络丢包,从而影响了网络的可靠性(舛误1:网络是牢靠的)、时延(舛误2:时延是0)以及带宽(舛误3:带宽是有限的)。

所有从“大泥球”开始

“大泥球”架构

大泥球”架构是驰名的反模式架构,最后在1997年由Brian Foote 和 JosephYoder提出。在“大泥球”架构里,零碎没有进行外部的模块划分,代码耦合重大,调用关系凌乱,就像一个大的泥球。如上图所示,每一个点代表一个类,红线则示意类之间的耦合关系。这样的架构对需要变更极不敌对,往往牵一发而动全身,而且在部署、可测试性、性能等方面也存在着很多问题。所有的架构师都在竭力防止“大泥球”的呈现,但很可怜的是,它依然在理论我的项目中很常见,特地是我的项目伊始,代码品质和构造还没被严格管控起来前。

有反模式的呈现,必然就有解决它的办法,这便是架构模式,从下一篇文章开始,咱们将一一介绍常见的8种架构模式。

总结

跟设计模式相似,架构模式是软件工程师们多年来在架构设计方面的经验总结。每种架构模式并没有相对的优劣之分,咱们不能说微服务架构就肯定比单体分层架构优越,它们都有着各自的利用场景。分布式架构比单体架构有着更好的可扩展性、容错性,但也带来了更高的复杂性,比方分布式事务。因而,咱们应该熟知各个架构模式的特点,这样能力在特定的业务场景应用适合的架构模式。

作者:元闰子

点击关注,第一工夫理解华为云陈腐技术~