一、前言
架构,又名软件架构,是有关软件整体结构与组件的抽象描述,用于指导大型软件系统各个方面的设计。架构描述语言(ADL)用于描述软件的体系架构。
软件架构(software architecture)是一系列相关的抽象模式,用于指导大型软件系统各个方面的设计。 软件架构是一个系统的草图。软件架构描述的对象是直接构成系统的抽象组件。各个组件之间的连接则明确和相对细致地描述组件之间的通讯。在实现阶段,这些抽象组件被细化为实际的组件,比如具体某个类或者对象。在面向对象领域中,组件之间的连接通常用接口(计算机科学)来实现。 软件体系结构是构建计算机软件实践的基础。与建筑师设定建筑项目的设计原则和目标,作为绘图员画图的基础一样,一个软件架构师或者系统架构师陈述软件构架以作为满足不同客户需求的实际系统设计方案的基础。
二、架构设计目标
在进行软件系统构架时,软件本身有其要达到的目标,软件架构设计要达到如下的 8 个目标:
- 可靠性(Reliable)。软件系统对于用户的商业经营和管理来说极为重要,因此软件系统必须非常可靠。
- 安全性(Secure)。软件系统所承担的交易的商业价值极高,系统的安全性非常重要。
- 可扩展性(Scalable)。软件必须能够在用户的使用率、用户的数目增加很快的情况下,保持合理的性能。只有这样,才能适应用户的市场扩展得可能性。
- 可定制化(Customizable)。同样的一套软件,可以根据客户群的不同和市场需求的变化进行调整。
- 可伸缩 (Extensible)。在新技术出现的时候,一个软件系统应当允许导入新技术,从而对现有系统进行功能和性能的扩展。
- 可维护性(Maintainable)。软件系统的维护包括两方面,一是排除现有的错误,二是将新的软件需求反映到现有系统中去。一个易于维护的系统可以有效地降低技术支持的花费。
- 客户体验(Customer Experience)。软件系统必须易于使用。
- 市场时机(Time to Market)。软件用户要面临同业竞争,软件提供商也要面临同业竞争。以最快的速度争夺市场先机非常重要。
三、架构分类
通常按不同的关注角度上分,可以将架构类型分为三种:
- 逻辑架构:软件中元件之间的关系,比如一个系统的架构在抽象层面,分解为表示层、业务逻辑处理层、数据元件层,如下面图所示,将各元件职责分离且划分简单抽象的单元构建的基本架构。
- 物理架构:是对软件元件怎么部署到硬件上。比如下图中所描述的物理架构图是一个终端到服务器分布式部署的物理架构,图中所有的元件都是物理设备,该架构包含WEB服务器、代理服务器、应用服务器、存储服务器。
- 系统架构:是软件系统的功能性和非功能性特征的体现,而功能性特征的原则是怎么把整个系统做拆分,将各个元件各司其职,完成某一功能为事件。非功能性特征包括可扩展性、可靠性、可用性、健壮性、灵活性、性能等。如下图中描述的是一个系统的构建和设计需要满足的要求。系统架构的设计要求架构师具备软件和硬件的功能和性能的过硬知识,这一工作无疑是架构设计工作中最为困难的工作。
四、架构边界划分
架构通常是抽象的,但其边界是可被约束的,在构建实际的系统架构中,我们可以将架构边界划分为软件元件和设计两个关键要素决定。从每一个角度上看,都可以看到架构中的这两要素,也就是元件的划分和设计。
首先,一个软件系统中的元件首先是逻辑元件。这些逻辑元件如何放到硬件上,以及这些元件如何为整个系统的可扩展性、可靠性、强壮性、灵活性、性能等做出贡献,是非常重要的信息。其次,进行软件设计需要做出的决定中,必然会包括逻辑结构、物理结构,以及它们如何影响到系统的所有非功能性特征。这些决定中会有很多是一旦做出,就很难更改的。为了讨论和分析软件架构,必须首先定义架构表示方式,即描述架构重要方面的方式。
我们决定以多种架构视图来表示软件架构,架构视图模型都有哪些将在下面进行说明。每种架构视图针对于开发流程中的涉众(例如最终用户、设计人员、管理人员、系统工程师、维护人员等)所关注的特定方面。架构视图显示了软件架构如何分解为构件,以及构件如何由连接器连接来产生有用的形式 ,由此记录主要的结构设计决策。这些设计决策必须基于需求以及功能、补充和其他方面的约束。而这些决策又会在较低层次上为需求和将来的设计决策施加进一步的约束。
五、架构视图模型有哪些
架构由许多不同的架构视图来表示,这些视图本质上是以图形方式来重点说明“在架构方面具有重要意义”的模型元素。该视图集称为“4+1 视图模型”。它包括:
- 用例视图:包括用例和场景,这些用例和场景包括在架构方面具有重要意义的行为、类或技术风险。它是用例模型的子集。
- 逻辑视图:包括最重要的设计类、从这些设计类到包和子系统的组织形式,以及从这些包和子系统到层的组织形式。它还包括一些用例实现。它是设计模型的子集。
- 实施视图:包括实施模型及其从模块到包和层的组织形式的概览。 同时还描述了将逻辑视图中的包和类向实施视图中的包和模块分配的情况。它是实施模型的子集。
- 进程视图:包括所涉及任务(进程和线程)的描述,它们的交互和配置,以及将设计对象和类向任务的分配情况。只有在系统具有很高程度的并行时,才需要该视图。在 Rational Unified Process 中,它是设计模型的子集。
- 配置视图:包括对最典型的平台配置的各种物理节点的描述以及将任务(来自进程视图)向物理节点分配的情况。只有在分布式系统中才需要该视图。它是部署模型的一个子集。
针对上面提到的几种视图模型中,我们可以构建其它视图来表达需要特别关注的不同方面,如:用户界面视图、安全视图、数据视图等。对于简单系统来说,可以省略 4+1 视图模型中的一些视图。
虽然以上视图可以表示系统的整体设计,但架构只同以下几个具体方面相关: 模型的结构,即组织模式,例如分层。
架构视图在本质上是整体设计的抽象或简化,它们通过舍弃具体细节来突出重要的特征。在考虑以下方面时,这些特征非常重要:
- 系统演进,即进入下一个开发周期。
- 在产品线环境下复用架构或架构的一部分。
- 评估补充质量,例如性能、可用性、可移植性和安全性。
- 向团队或开发商分配开发工作。
- 决定是否包括商业构件。
- 插入范围更广的系统。
六、架构设计原则
通常我们在对系统或程序做设计过程中并不是一味追求完美和为了架构而去做架构。为了解决软件架构在设计时,可根据传统软件规则约束设计出符合实际业务场景的适用性架构,并且软件架构的设计不是一成不变的,将会随着满足客户需求为意愿或其它内外部因素的影响,我们需要动态和适当的调整架构。
基本的软件架构的设计一般需要符合以下 6 个架构设计原则(简称:SOLID):
- 单一职责(SRP):是指在一个类或组件中永远只负责做独有的业务或一件事,保持职责足够单一,各司其职,不受外部因素所干扰,职责清晰,便于维护。
- 开闭原则(OCP):是指类或组件的扩展开放,修改关闭原则,实现业务之间耦合性降低和提高了可扩展性。
- 里氏替换原则(LSP):是指子类和超类或基类之间的关系,子类的实例可以替换为超类或基类任何实例,并且在此过程中程序不会受到影响,而反过来则不行,会使程序异常。
- 迪米特原则(LKP):是指类或组件中所依赖的对象(实体)降到最低,是该类的依赖最少了解,通常也被称为最少知识原则。
- 接口隔离原则(ISP):是指不需要把不必要的接口强加给用户使用,尽量保证接口和模块之间的耦合降到最低,也称为接口最少提供原则。
- 依赖倒置原则(DIP):是指类与组件之间或层与层之间的关系,顶层不应该依赖于底层,而更应该依赖于抽象层,抽象层不应该依赖于具体的实现,更应该依赖于底层,说明的是内部结构的变动并不会影响到顶层的变化,尽量避免跨层调用和强依赖关系,提高可扩展性。
软件架构设计时您还需要遵守的编程原则(规范):
- 不要重复你自己(Don’t repeat yourself - DRY)
不要让重复的代码到处都是,要让它们能够复用,所以要尽可能地组件化封装。
- 保持简单与傻瓜(Keep it simple and stupid - KISS)
不要让系统变得复杂,界面简洁,功能实用,操作方便,要让它足够的简单,足够的傻瓜。
- 高内聚与低耦合(High Cohesion and Low Coupling - HCLC)
模块内部需要做到内聚度高,模块之间需要做到耦合度低。
- 约定优于配置(Convention over Configuration - COC)
尽量让约定来减少配置,这样才能提高开发效率,尽量做到“零配置”。很多组件或框架都是这样做的。
- 命令查询分离(Command Query Separation - CQS)
在定义接口时,要做到哪些是命令,哪些是查询,要将它们分离,而不要揉到一起。
- 关注点分离(Separation of Concerns - SOC)
将一个复杂的问题分离为多个简单的问题,然后逐个解决这些简单的问题,那么这个复杂的问题就解决了。难就难在如何进行分离。
- 契约式设计(Design by Contract - DBC)
模块或系统之间的交互,都是基于契约(接口或抽象)的,而不要依赖于具体实现。该原则建议我们要面向契约编程。
- 你不需要它(You aren’t gonna need it - YAGNI)不要一开始就把系统设计得非常复杂,不要陷入“过度设计”的深渊。应该让系统足够的简单,而却又不失扩展性,这是其中的难点。
七、架构的演变过程
软件架构的设计,从最初系统的架构到不断的调整和探索的过程中,演变出一系列的架构模型。在此过程中经历了需求和业务的不断挑战和洗礼所产生的衍生架构,为了满足用户需求和实际业务场景去对架构上做出重新调整,实现新的系统架构设计上的本质提升。
由于在架构上从不同角度上看会产生不同的粗细模型,但在本质上粗略的分为如下几种架构:
- 单体架构:单体架构是传统的软件架构模型,也是最简单、最容易被人所理解的架构,比如:分层。
- 分布式架构:分布式架构是系统和组件元件的聚合,将整个系统分布式部署在服务器上,通过一种技术手段把这些系统连接上,使各系统或模块能够相互协作处理程序操作,比如:分布式集群架构、分布式缓存架构等。
- 微服务架构:微服务架构的全称是Microservice Architecture,微服务架构是现代化流行的服务化治理架构,是通过业务/组件或功能维度上去划分的架构模型,能够将大的系统分解为各个小的服务,再将这些拆分的服务联系起来,服务之间的相互协作,互不影响,提高了系统的可扩展性、可维护性和容错性。
- Serverless架构:Serverless的全称是Serverless computing无服务器运算,又被称为函数即服务(Function-as-a-Service,缩写为 FaaS),是云计算的一种模型。以平台即服务(PaaS)为基础,无服务器运算提供一个微型的架构,终端客户不需要部署、配置或管理服务器服务,代码运行所需要的服务器服务皆由云端平台来提供。 国内外比较出名的产品有Tencent Serverless、Aliyun Serverless、AWS Lambda、Microsoft Azure Functions 等。
- Service Mesh架构:Service Mesh是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。
- Istio架构:Istio扩展了Kubernetes,使用强大的Envoy服务代理建立了一个可编程的、应用程序感知的网络。与Kubernetes和传统工作负载一起工作,Istio为复杂的部署带来了标准的、通用的流量管理、遥测和安全性。
八、架构设计思想
1、对系统架构理解
由于架构是抽象的,关于系统架构目前没有一个明确的定义。有从规划、实现与步骤角度去了解,有从架构分类方面去定义。这次我提的理念是:系统架构的目标是解决利益相关者的关注点。
- 每个系统都有一个架构,架构由架构元素以及相互之间的关系构成,系统是为了满足利益相关者的需求构建的;
- 利益相关者都有自己的关注点;
- 架构由架构文档描述,并且描述了一系列的架构视角,而这些视角其实就是去解决利益相关者的关注点。
2、对系统关注点理解
系统关注点通常是从系统架构中在不同视野上分为功能性关注点和非功能性关注点,而往往我们在对系统做架构设计时忽略了最需要关注的非功能性关注点,下面就着重分析功能性和非功能性关注点所具备的基本原则和规范。
处理功能性关注点,需要注意以下 3 个原则,并且通过模型方式来进行实现。
1- 架构设计基本原则:S - O - L - I - D
SRP:单一职责原则
OCP:开闭原则
LSP:里氏替换原则
LKP:迪米特原则
ISP:接口隔离原则
DIP:依赖倒置原则
2- KISS
KEEP IT SIMPLE AND STUPID(保持简单与傻瓜)
3- 高内聚、低耦合
4- 模型的 3 个层次
第一层是代码层面:就是惯用的代码,策略是指一套API、方法等。
第二层是设计模式:主要GOF提出来的23种常用的设计模式。立足于高级抽象层面进行探讨,而非设计标注或 者编程语言,能够大大降低系统复杂度。
第三层是架构模式:它是一个通用的,可复用的解决方案。比如:分层模式、微服务模式等。
非功能性关注点,一般应用于对系统的扩展性方面做设计的。
1-高可用性
首先需要先了解一个分布式理论原则:CAP理论,在分布式系统中,一致性、可用性和分区容错性。三者不可兼得。在设计系统架构时是无法同时满足CAP这三个特性,那么我们怎么样来做权衡选择呢?选择的关键就是取决于您的业务场景。对于现在的互联网应用,特点就是机器数量庞大,部署节点分散,网络故障是常态。可用性是必须保证的,通常一般业务系统会在C和A之间做权衡,但为了保证系统的高可用性,其实本质上就放弃了C,选择AP。
保证系统的高可用方式有以下几种:
隔离:发生故障的时候,能限定它传播的范围和影响范围。就应该对其进行隔离,不会出现雪球效应。隔离 包含:进程隔离、线程隔离、集群隔离、机房隔离、读写隔离、动静隔离、爬虫隔离。
限流:限流的目的是通过对并发访问进行限速或者一个时间窗口内的请求进行限速来保护系统常见的限流算 法,有令牌桶和漏桶算法。
预案、降级:目的也是对我们的应用系统的一种保护。在不牺牲核心功能,或者牺牲一定的用户体验的情况 下,保证我们的服务还是可用的。在降级之前我们的准备工作是预案的准备。还要使用配置中心实现 开关配置。
2-高性能性
缓存:浏览器或者APP客户端缓存、CDN缓存、接入层缓存(如:Nginx缓存)、应用层缓存(堆内缓存、对外 缓存、磁盘缓存)、分布式缓存。
异步并发:当用户请求达到服务端时,比如商品详情页,它涉及到很多属性,由于目前在微服务这个大环境 下,就会存在大量的HTTP,SOA服务的调用。如果是使用同步调用来获取数据,这个线程都是 出于阻塞状态,降低了系统的吞吐量。这个时候我们就需要使用异步来进行提升吞吐量了。目前 Java这方面的开源框架有: HttpAsyncClient、gRPC、Thrift等。
扩容:业务量级越来越大,单台服务器无法处理这么大的业务流量,这就需要分而治之的思想来对待了。扩 容包括单体应用垂直扩容和水平扩容。垂直扩容:就是对硬件资源进行提升,比如CPU和内存。水平 扩容:就是增加更多的应用镜像,通过负载均衡来分摊压力。
最后涉及到高性能的比如数据层索引优化、性能测试等。
3-高伸缩性
通过很少的改动,甚至只是增加一些硬件设备,就能实现整个系统能力的线性增长,实现高吞吐量和低延迟 性能。
对于可伸缩性和纯粹的性能调优,是有区别的:可伸缩性,它主要是对高性能,低成本和可维护性等诸多因素的综合考虑和平衡。普通的性能优化,更多的只是单台机器的性能指标的优化。但是它们有个共同点,就是根据系统的特点在吞吐量和延迟之间进行一个侧重选择。
3、康威定律
康威定律是马尔文康威1967年提出的:“设计系统的架构受制于产生这些设计的组织的沟通结构。”通俗 的来说:产品必然是其(人员)组织沟通结构的缩影。
康威定律可总结为四个定律:
第一定律:组织沟通方式会通过系统设计表达出来。
第二定律:时间再多一件事情也不可能做的完美,但总有时间做完一件事情。
第三定律:线型系统和线型组织架构间有潜在的异质同态特性。
第四定律:大的系统组织总是比小系统更倾向于分解。
九、架构总结
通过阅读了本文相信你们对架构有了初步的认知和了解,但想成为架构师必须具备足够的技术和业务能力,下面我就以个人对架构的理解和总结说一下个人感触,关于架构总结我从 3 个维度去阐明,具体如下图:
架构认知:我个人对架构的认知在于万物皆架构,在生活或虚拟世界里都存在着独有的架构,好比在现实生活中的楼房、交通轨道、手机等,都离不开本身着重的架构设计,而在虚拟世界里有应用软件、通信软件和游戏等,但这些基本上都是环绕在我们脑海里对架构的初步认知,还尚未成熟,因为架构是一种思想,也是抽象的,并不被人所理解。
架构理解:通过我对架构上的认知,也触发了我本身对架构上的理解。架构的设计不在于精,而在于弹性适用性。假如我们对架构的理解是在于技术性的满足,那么就会让你陷入技术的海洋,到最后就会迷失方向,一直站在目前的方位。对于产生这样的结果,是因为没有真正的去认知和理解架构的本质。那么架构的本质是什么呢?应该怎么做才能往正确的架构方向靠近呢?无疑这些问题就成为了我们脑海里在探索答案的过程中,对于刚提到的 2 个问题我会在下面进行说明。
1、架构的本质是什么呢?
- 架构师是技术和业务之间的桥梁;
- 架构师不能只顾技术,不懂业务;
- 架构师很容易两头不讨好。
2、应该怎么做才能往正确的架构方向靠近呢?
首先,需要从架构思维上的转变,如下图:
然后,还要从实际出发点上去看,应该怎么去做,需要哪些方面的经验和方法,如下图:
架构启发:从我个人经历架构行业以来,一直对于架构上的认知、理解给予我很多启发。现在我从个人的角度出发去说明架构设计中的思想,其实,架构致力于很多方面、也以各种形式存在。在做架构设计时,我们基本上会从各方面角度去思考,比如用户需求、业务切入点、数据量级等,那么通常所说的架构设计,都是为了满足或解决实际业务问题的。我个人所理解架构总结出一句话就是:架构设计不在于完美,也不在于复杂,而在于架构足够简单并且能够适用于业务,便于能够让人去理解。
最后,若大家有想往架构这方面去提升的,我会致力于架构方面的经验持续输出,为大家输出高质量文章,麻烦大家动动小手指点个赞,收藏+关注不迷路哦~
版权归原作者 架构潜行之路 所有, 如有侵权,请联系我们删除。