架构设计基础-软件架构设计学习第二天(非原创)

文章大纲

一、架构需求分析
二、架构愿景分析
三、架构设计原则
四、必备设计-API网关
五、参考文章

 

一、架构需求分析

1. 需求收集与分析

需求分析的前期工作是愿景描述及愿景分析, 即愿景分析就是需求的前期调研.
从软件过程来看,需求分析是一个承上启下的阶段–“上承”愿景,“下接”设计。需求分析的工作内容包含如下三方面:
1.1 需求捕获: 理解沟通
需求捕获: 从各个方面收集需求, 并理解需求.典型的需求捕获是使用“需求采集卡”:需求描述、需求提出者、需求记录者、需求类型等。

1.2 需求分析:做什么,有哪些问题
需求分析:需求捕获得到的是“原始需求”,而需求分析则对各方面收集到的需求进行分析、整理、归纳、论证形成明确的需求。比如, 产品经理说,现在系统不稳定, 需要重构架构保证系统稳定. 这只是一个愿景, 我们需要把这个需求形成一个明确的需求: 可行性99.99%, 要完成这个指标,需要做哪些工作.

1.3 系统分析:原因是什么, 怎么做
三者不是独立无关的阶段,而是相互伴随、交叉进行的。

2. 需求分类

需求可分类为三类:
(1)功能需求:更多体现各级直接目标要求,系统具体要做什么. 有哪些功能点.
(2)质量需求:运行期质量 + 设计质量+用户质量+系统质量.
(3)约束需求:业务环境因素 + 使用环境因素 + 构建环境因素 + 技术环境因素.

ADMEMS矩阵,可作为需求梳理和需求评审的工具:

 

3. 需求优先排序

架构设计的本质目的是为了解决业务,架构设计也并不是面面俱到,而是识别问题有针对性的解决, 所以要先了解系统最需要解决的是什么。

例如系统的复杂度来源于业务逻辑复杂,功能耦合度严重,架构师设计TPS达到50000/s的高性能架构没有意义。

出现问题主要为了满足“高可用”“高性能”“可扩展”三个方面,就算老板拍脑袋要求同时满足三高,也要分优先级。

比如线上运行的系统可能存在的问题:

运行效率低下,升级复杂,容易出错。

开发效率低下。

小问题不断,不好定位。

解决方法:

列出主要的复杂度问题

根据业务、技术、团队等情况进行排序

优先解决最主要的复杂度问题.

4. 需求分析总参考图

 

二、架构愿景分析

1. 架构设计流程

 

2. 愿景和目标区别

有时候我们经常把愿景和目标混为一谈,我们首先需要区别愿景和目标:
(1)愿景笼统,目标具体,。比如:架构设计做做到高可用,高性能,高可扩展,这些是笼统的概念,没有具体的指标要求。
(2)目标是即将实现,能够通过努力实现的规划,愿景是一幅前景,能够指引我们前进的理想。
(3) 愿景有助于确定发展目标,发展目标为实现愿景服务。
(4)架构愿景:是一种团队内心的愿望,是脑筋的一幅图画,是一种驱动力,愿意实践、追求,来达到某一个境界,能追求到某一种成就。是团队成员希望架构往哪个方向发展,包括具体目标、设计原则、质量要求。
(5)架构目标:架构达成某些具体的指标,比如可用性达到99.99%等。
(6)因此我这里认为架构的愿景分析是包含目标.

3. 架构愿景的层次

架构的愿景是相对于一个范围来说的,在一个特定的软件功能范围之内,谈架构愿景才有实际的意义,例如针对软件的全局或某个子系统/模块。在这个特定的范围中,订立了架构愿景之后,这个范围内的所有设计原则将不能违背架构愿景。这是非常重要的,是架构愿景的最大的用处。有了这样的保证,我们就可以保证设计的一致性和有效性。任何一项设计的加入,都能够融入到原先的架构中,使得软件更加的完善,而不是更加的危险。

我们根据架构适用范围的不同,把架构愿景分为几个类别讨论:

 

3.1 软件系统全局(架构模式)
软件全局的架构是我们所最关心的,因此也会花费最多的笔墨。
软件全局中的架构愿景一般很难具体化到代码级别,其实你会发现,就算是具体化到了代码级别,也会因为实际中存在的问题,导致代码没有太多的价值。因此,为软件全局设置的架构愿景可以以原则、或是架构模式的方式体现,并用自然语言或伪代码描述。例如,可以为一个系统规定三层架构作为其愿景,并指出三层的分类原则和具体目标。注意,我们需要指出分类原则,否则规定三层架构并没有太大的意义,因为三层架构随着实现平台的不同、开发人员的不同而有很大的差异,如果不能够规定一个可操作的规范,那么愿景是没有意义的。

3.2 子系统/模块级、或是子问题级的架构愿景
这时候的架构愿景已经是比较明确的了,因为已经存在明确的问题域。例如界面的设计、领域模型的设计、持久层的设计等。这里的愿景制定本质上和全局的愿景制定差不多,具体的例子我们也不再举了。但是要注意一点,你不能够和全局愿景所违背。在操作上,全局愿景是设计团队共同制定出来的,而子/系统模块级的架构愿景就可以分给设计子团队来负责,而其审核则还是要设计团队的共同参与。这有两个好处,一是确保各个子模块(子问题)间不至于相互冲突或出现空白地带,二是每个子设计团队可以从别人那里吸取设计经验。

在设计时,同样我们可以参考其它的资料,例如相关的模式、或规范(界面设计指南)。在一个有开发经验的团队,一般都会有开发技术的积累,这些也是可供参考的重要资料。

我们在这个层次的愿景中主要谈一谈子模块(子问题)间的耦合问题。一般来说,各个子模块间的耦合程度相对较小,例如一个MIS系统中,采购和销售模块的耦合度就比较小,而子问题间的耦合程度就比较大,例如权限设计、财务,这些功能将会被每个模块使用。那么,我们就需要为子模块(子问题)制定出合同接口(Contact Interface)。合同的意思就是说这个接口是正式的,不能够随意的修改,因为这个结构将会被其它的设计团队使用,如果修改,将会对其它的团队产生无法预计的影响。合同接口的制定、修改都需要设计团队的通过。此外,系统中的一些全局性的子问题最好是提到全局愿景中考虑,例如在源自需求模式中提到的信贷帐务的例子中,我们就把一个利息计算方式的子问题提到了全局愿景中。

3.3 代码级的愿景 (代码设计模式)
严格的说这一层次的愿景已经不是真正的愿景,而是具体设计了。但是我们为了保证对架构设计理解的完整性,还是简单的讨论一下。这一个层次的愿景一般可以使用类图、接口来表示。但在类图中,你不需要标记出具体的属性、操作,你只需要规定出类的职责以及类之间的相互关系就可以了。该层次愿景的审核需要设计子团队的通过。

而设计细分到这个粒度上,执行愿景设计的开发人员可能就只有一两个左右。但是比较重要的工作在于问题如何分解和如何归并。分解主要是从两个维度来考虑,一个是问题大小维,一个是时间长短维。也就是说,你(设计子团队负责人)需要把问题按大小和解决时间的长短分解为更细的子问题,交给不同的开发人员。然后再把开发人员提出的解决方法组合起来。

4. 架构目标

4.1 提出期望目标
期望目标也是来源于需求,主要指客户(可能是老板)或其他利益相关人提出的项目(产品)愿景。愿景表达了客户的目标以及对系统的期望。从愿景中我们可以获得许多架构分析所需要知道的知识,例如明确客户最期望达到的目标,以此可以确定场景与风险的优先级;了解客户的不同目标,可以由此识别系统客户的不同角色,明确不同的利益相关人的态度。
(1)业务响应能力:
降低系统耦合, 提升对变化的响应速度。
改善系统架构, 更好地支持业务扩展。
建立流程引擎, 更灵活地支持业务流程变化。

(2)系统质量:
合理地增加或减少系统间交互及补偿, 提升系统性能、 稳定性。

(3)开发效率:
合理划分系统, 通过系统职责的分离, 对开发组的职责进行合理分配, 同时建立更完整的公共平台、 基础框架、 基础类库, 提高开发效率。

(4)运维水平:
完善配置、 监控、 预警、 日志系统, 提升系统运维配置效率及排查问题的速度.

4.2 架构具体目标:衡量系统好坏的标准
具体目标指标如下:
(1)正确性:系统首先需要正确,运行稳定
(2)可用性: 系统必须非常可靠,一般业界更倾向用 N 个9 来量化可用性, 最常说的就是类似 “4个9(也就是99.99%)” 的可用性。
(3)开发效率: 降低开发成本和降低公司在快速巨变的行业里面的时间和机会成本。互联网目前是一个快鱼吃慢鱼的时代,已经不是大鱼吃小鱼了。因为小鱼在一夜之间就长大了,把大鱼吃掉了。
(4)伸缩性: 用户激增的时候,系统可以伸缩来支持用户的增长或流量高峰。
(5)安全性:安全也是一个商业公司的命脉,攻击、泄密、破解,前一段闹的沸沸扬扬的各种用户信息泄露,足以说明安全的重要性。
(6)扩展性:在增加新模块或者新的技术时,能比较容易的扩展。
(7)高性能:性能其实也是用户体验的一部分,尤其是用户量不断增多,性能是节省成本的重要手段。
(8)可维

 

4.3 确定架构质量要求

 

三、架构设计原则

如何设计出一个好的架构,不像数据公式或者定律,很难一概而就。很多时候是设计者(架构师)的各种设想,各种权衡折中而符合系统需求的智慧输出。但我们掌握前人总结的经验,让我们站在巨人的肩膀上高山远瞩。一些好的架构设计原则可以确保设计决策在一定程度上能够满足需求。

1. 形成架构原则的过程

形成架构原则的过程:

 

架构原则要SMART

 

2. 常见的架构设计原则

2.1 N+1设计
开发的系统在发生故障时,至少有一个冗余的实例
广泛地应用在从数据中心设计到应用服务的部署:
在发生故障时,系统至少要有一个冗余的实例。
必须确保一个为自己,一个为客户、 一个为失败

2.2 回滚设计
确保系统可以向后兼容
如果很久才能修复服务,那么就要在一定的时间范围内完成回滚。
灾难性的事故,例如损坏客户数据,往往在部署后好几天才出现。
系统最好按照预先的设计,通过发布或回滚解决问题。

2.3 禁用设计
可以关闭任何发布功能
当设计系统,特别是与其他系统或服务通讯的高风险系统时,要确保这些系统能够通过开关来禁用。这将为修复服务提供额外的时间,同时确保系统不因为错误引起诡异需求而宕机。

2.4 监控设计
在设计阶段就要考虑监控,而不是在部署完成后,通过监控发现系统的可用性问题。
(1)通过监控使系统自我诊断、自我修复成为可能。
(2)通过监控确定系统可预留空间的使用情况。
(3)通过监控掌握系统之间的交互关系,发现瓶颈
如果监控做的好,不仅能发现服务的死活,检查日志文件,还能收集系统相关的数据,评估终端用户的响应时间。如果系统和应用在设计和构建时就考虑好监控,那么即使不能自我修复,也至少可以自我诊断。

2.5 多活数据中心设计
数据是否全部集中在一个数据中心?
读写是否分离?
是否所有的客户信息都共享同一个数据结构?
服务调用是否允许延时的存在

2.6 采用成熟的技术
(1)工程师倾向于学习和实施性感时髦的新技术。因为新技术可以降低成本、减少产品上市时间、提高性能。不幸的是,新技术也往往有较高的故障率。如果把新技术应用在架构的关键部分,可能会对可用性产生显著的影响。
(2)最好争取在多数人采用该技术的时候进入,先把新技术用在对可用性要求不高的功能上,一旦证明它可以可靠地处理日常的交易,再将此技术移植到关键任务领域中去。

2.7 故障隔离
避免单一业务占用全部资源。避免业务之间的相互影响 2. 机房隔离避免单点故障。
不共享原则:理想情况是负载均衡、网络前端、应用服务器、数据库,绝不共享任何服务、硬件和软件。
不跨区原则: 不同隔离区之间无通讯,所有服务调用必须发生在同一个故障隔离区。

2.8 水平扩展
什么是水平可扩展?平台的水平扩展是指随着业务的发展,当需要扩大平台的服务能力时,不必重构软件系统,通过增加新的设备来满足业务增长的需要。

 

X轴扩展:服务器拆分。平台的服务能力可以在不改变服务的情况下,通过添加硬件设备来完成扩容。
Y轴扩展:数据库拆分。平台的服务能力通过不断地分解和部署服务来完成扩容。
Z轴扩展:功能拆分。平台的服务能力可以按照客户不断分解和部署来机器 完成容量的扩展。(比如按用户uid来分表分库等)

 

2.9 非核心则购买
工程师往往有自己研发所有系统的冲动。
系统研发要投入资源,系统维护更要长期投入。
影响核心产品到市场的速度。
如果可以形成差异化的竞争优势,那么自己做,否则外购。

2.10 使用商品化硬件
在大多数情况下,便宜的是最好的。
标准、低成本、可互换、易于商品化是商品化硬件的特征。如果架构设计得好,就可以通过购买最便宜的服务器轻松地实现水平扩展,前提是所有商品化硬件的总成本要低过高端硬件的总成本。

2.11 快速迭代
小构建:小构建的成本较低,可以确保投资可以产生价值。
小发布:发布的失败率与变更数量相关,小发布失败率较低。
快试错:可依市场反馈,快速迭代,加快TTM,优化用户体验

2.12 异步设计
同步系统中个别子系统出现故障会对整个系统带来影响。
同步系统中性能最慢的子系统成为整个系统性能的瓶颈。
同步系统中扩展性最差的子系统是整个系统扩展的瓶颈。

2.13 无状态设计
无状态的系统更利于扩展,更利于做负载均衡。
状态是系统的吞吐量、易用性、可用性、性能和可扩展性的大敌,要尽最大可能避免。

2.14 前瞻性设计
Now :目前正使用系统的架构、设计、能力、性能和扩展性。
Now+1: 下一代预研系统的架构、设计、能力、性能和扩展性。
Now+2: 下一代规划系统的架构、设计、能力、性能和扩展性

2.15 自动化
设计和构建自动化的过程。如果机器可以做,就不要依赖于人. 人常犯错误,更令人沮丧的是,他们往往会以不同的方式多次犯同样的错误。

3. 架构设计的关键原则

3.1 一个好的设计拥有以下几点
(1)解决现有需求和问题
(2)把控现实的进度和风险
(3)预测和规划未来,不要过度的设计,从迭代中演进和完善。
在开始设计之前,思考一下关键的原则,将会帮助你创建一个最小花费、高可用性和扩展性的架构。

3.2 分离关注点
将应用划分为在功能上尽可能不重复的功能点。主要的参考因素就是最小化交互,高内聚、低耦合。但是,错误的分离功能边界,可能会导致功能之间的高耦合性和复杂性

3.3 职责单一
每一个组件或者是模块应该只有一个职责或者是功能,功能要内聚。

3.4 最小知识原则
一个组件或者是对象不应该知道其他组件或者对象的内部实现细节。

3.5 不重复原则
你只需要在一个地方描述目的。例如,特殊的功能只能在一个组件中实现,在其他的组件中不应该有副本。

3.6 最小化预先设计
只设计必须的内容。在一些情况,你可能需要预先设计一些内容。另外一些情况,尤其对于敏捷开发,你可以避免设计过度。如果你的应用需求是不清晰的,最好不要做大量的预先设计。

3.7 低耦合、高内聚
防止变异(使用接口和适配器防止变异)、关注分离。

3.8 关注分离
横向分层、纵向分区
(1) 将有关事务模块化,封装到单独的构件(例如子系统)中,并且调用其服务;
(2) 使用装饰者,将所关注的事物(例如安全)置入Decrator对象中,Decorator对象包裹内部类并提取其服务,装饰者在EJB技术中被称为容器,EJB容器围绕内部对象的业务逻辑,在外部的装饰者中增添安全检查;
(3) 使用后便以和面向方面的技术(Aspect-oriented),比如AspectJ以对开发者透明的方式支持在编译之后将横切面关注织入代码。

3.9 关注点分离之道
好的架构设计必须把变化点错路有致地封装到软件系统的不同部分,为此,必须进行关注点分离。关注点相互分离,也就是说系统中的一部分发生变化,不会影响其他部分。即使需要改变,也能够清晰地识别出哪些部分需要改变。如果需要扩展架构,影响将会最小化,已经可以工作的每个部分都可以继续工作。

首先,可以通过职责划分来分离关注点。面向对象设计的关键所在,就是职责的识别和分配。每个功能的完成,都是通过一系列职责组成的协作链条完成的,当不同职责被合理分离之后,为了实现新的功能只需构建新的协作链条,而需求变更页往往只会影响到少数职责的定义和实现。

其次,可以利用软件系统各部分的通用性的不同进行关注点分离。不同的通用程度意味着变化的可能性不同,将通用性不同的部分分离有利于通用部分的重用,页便于对专用部分进行修改。

另外,还可以先考虑大粒度的子系统,而暂时忽略子系统是如何通过更小粒度的模块和类组成的。在实际中,软件架构师常常将系统划分为一组子系统,并为子系统定义明确的借口,其中的细节将随其后的开发工作慢慢展开。

根据职责分离关注点、根据通用性分离关注点、根据不同粒度级别分离关注点是三种不同维度的思维方式。

3.10 非侵入性原则
那么什么是架构的侵入性呢?所谓侵入性就是指的这个架构设计出来的部件对系统的影响范围,比如框架的侵入性就很高,因为在一个工程中引入一个框架,你的整个设计都必须围绕这个框架来进行,一旦使用了,框架的可替代性几乎为0,这样子就是搞侵入性。组件的侵入性就比较低,比如ibaties,他可以在任何java框架下使用,甚至可以和其他ORM组件共存,你仅仅需要引入,配置,然后就可以使用了,你也可以用其他的ORM替换他,所以......这个体验应该是很愉快的。
所以话说回来说到如果我们在设计一个通用架构的时候就应该注意到这个一个非常重要的地方,除非我们只是自己拿来用用,否则我们不应该假设我们的设计的用户已经具备怎么怎么样的环境或者是需要做什么特殊的设计才能够使用。
这里打个比方,假如说我们在设计一个通用权限管理什么什么的时候我们就要想好,这是一个组件,还是框架,还是一个现成系统(复用通过改改代码实现,其实个人觉得这种设计很低级,虽然有的这样子的东西功能确实丰富)。确定了目标之后我们才好开始下一步,比如确定是一个框架的话可能发挥要自由一些,因为不需要高度的内聚,不过可能因为框架要设计的方方面面太多了,所以老是觉得个人的力量不足以搞这种东西出来。如果是组件的话就需要高度的内聚来实现非侵入式,比如引入DLL的时候还需要让所有页面继承自某个基类页就不算是一个good idear。

四、必备设计-API网关

1. 网关概念介绍

API Gateway(API GW / API 网关),顾名思义,是企业 IT 在系统边界上提供给外部访问内部接口服务的统一入口。在微服务概念的流行之前,API网关的实体就已经诞生了,例如银行、证券等领域常见的前置机系统,它也是解决访问认证、报文转换、访问统计等问题的。

百度百科:API网关是一个服务器,是系统的唯一入口。从面向对象设计的角度看,它与外观模式类似。API网关封装了系统内部架构,为每个客户端提供一个定制的API。它可能还具有其它职责,如身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理。

API网关方式的核心要点是,所有的客户端和消费端都通过统一的网关接入微服务,在网关层处理所有的非业务功能。通常,网关也是提供REST/HTTP的访问API。服务端通过API-GW注册和管理服务。

2. API网关分析设计

2.1 宏观分析要素
安全性问题
企业在把服务暴露给外部使用时,首先要确保服务使用的安全,防止外部的恶意访问对公司业务的影响,特别是涉及交易方面的服务,更是要全面考虑安全性。为确保安全,需要考虑在通讯链路的建立、通讯数据的加密、数据的完整性、不可抵赖性等方面。

性能问题
作为企业API的入口,所有的请求都会经过API网关进行转发,可想而知,对API网关的访问压力是巨大的,有的网站甚至达到每分钟上千万的访问量。特别是在一些互联网企业,海量的移动终端每时每刻都需要与后端的服务进行交互,如果不能保证网关的高性能,企业在网关层需要投入大量的设备和成本。曾在一家互联网公司发生过,由于网关性能问题,网关的机器数量,需要与后台服务器的数量保持同步增长。这种情况显然是企业服务忍受的。

高可用问题
API网关作为逻辑上的单点,一旦发生问题,将造成企业服务的不可用,对企业来说可能造成的致命的影响。计算短时间的不可用,也会给企业带来直接的经济损失。所以,如何保证API网关的7*24小时的稳定运行,网关的自动伸缩、API的热更新等问题,都是企业级的网关需要考虑的。

扩展性问题
前面说到,企业网关提供了一个脚手架,一些非功能性的问题,例如日志、安全、负载均衡策略、鉴权等。这些插件会随着企业业务规模等的变化进行不断的强化与调整。这就需要网关层提供这样一种机制,使得可以灵活地进行这些调整和变化,而不用频繁对网关层进行改动,确保网关层的稳定性。

API高效运维的问题
API在上线、发布过程中,都需要涉及到网关层的配合,例如,需要网关层知道API发布的地址,API的接口形式、报文格式,也需要网关层对后台API进行封装。在API调整后,需要作出相应的修改。所以,API网关设计时,需要明确网关层与服务层的职责切分与协作模式,使得API的管理、发布更加高效。

API全生命周期的管理
API服务的全生命周期,包括服务的开发、测试、上线发布;服务使用的申请、开通;服务分类分级别的管理、服务使用情况的监控、计费等等。
一个企业可能会暴露成百上千个API,日常也会经常进行API的发布、升级、改造、下架等操作。对不同的服务,不同的访问者,需要提供不同的服务访问策略。有的商业API公司,还需要对API的使用进行付费。所以,与API网关配套的,需要一套完善的自助系统,提供给服务的提供者、管理者、使用者,来对服务的发布、使用、和运营。

2.2 具体情况分析
功能需求
1、API 生命周期管理功能:
覆盖 API 的定义、测试、发布的整个生命周期管理,便捷的日常管理、版本管理,支持热升级和快速回滚

2、开发和使用支持功能:
提供页面调试工具,自动生成 API 文档和 SDK,大大降低人力成本。

3、安全防护功能:
API 请求到达网关需要经过严格的身份认证、权限认证,才能到达后端服务。支持算法签名,支持 SSL 加密。

4、流量控制功能:
可控制单位时间内 API 允许被调用次数。用来保护企业的后端服务,实现业务分级和用户分级。 支持对 API 流控,您可以根据 API 的重要程度来配置不同流控,从而保障重要业务的稳定运行; 支持用户、应用和例外流控,您可以根据用户的重要性来配置不同流控,从而可以保证大用户的权益; 流控粒度:分钟、小时、天。

5、请求管理功能:
可根据配置进行参数类型、参数值(范围、枚举、正则、Json Schema)的校验,减少后端对非法请求、无效请求的资源消耗和处理成本。可以在 API 网关定义参数映射规则,网关通过映射规则将后端服务通过映射翻译成任何形式,以满足不同用户的不同需求,从而避免功能重复开发。

6、监控告警功能:
提供实时、可视化的 API 监控,包括:调用量、调用方式、响应时间、错误率,让您能够清楚的了解 API 的运行状况和用户的行为习惯。
支持自定义报警规则,来针对异常情况进行报警,降低故障处理时间。
提供可订阅的数据分析报表和智能分析。

高性能设计
传统的基于线程的并发模型(Thread-based concurrency),为每一个请求分配一个线程或进程。这种模型编程简单,可以将处理一个完整请求的代码编写在一个代码路径中。这种模型的弊端是,随着线程(进程)数的上升,操作系统在这些线程(进程)之间的频繁切换,将急剧降低系统的性能。

 

高可用设计
1、无状态设计原则。
网关层为保证高可以,易于伸缩,快速启动,需要设计成无状态的。用户的状态数据我们通常使用session对象来封装,网关层要设计成无状态的,也就是说,不能由网关来负责session的维护。那由谁来维护session相关的信息呢?我们是采用cookie+session服务器的方式;
a) 用户在登录页完成登录操作后,服务器会生成一个登录session信息,保存起来,设置个失效时间,并设置到用户的cookie里
b) 用户后续的每次请求里会带着这个cookie信息,服务端会对这个cookie信息进行校验,通过了就认为是合法用户,执行请求操作

2、优雅下线原则
当需要撤掉一台网关服务的时候,不是直接结束网关进程,而是先关闭监听套接字,但是继续为当前连接的客户提供服务,所有客户端的服务完成后,在把进程关闭。

3、Slow start特性
当网关监听到有一台新的服务注册上来时,考虑到有些服务启动后,刚开始会有许多初始化的工作,此时服务对请求的响应速度是比较慢的。如果一开始就给这台服务分配太多的压力,有可能导致服务瞬间被压垮。为了避免这种情况,网关层需要考虑支持Slow Start特性。即,经过一段时间,逐渐把压力增加到预设的值。

4、扩展性设计
我们知道,网关对请求的处理,可以分为三个阶段:接受请求、路由并转发请求、接受服务的返回数据并返回给请求者,除此之外,还有一种情况是处理错误。所以我们也可以在这四个地方添加扩展点。
(1)接受到请求后
(2)定位到一个服务,并准备转发之前
(3)接受到服务的返回数据,返回给客户端之前
(4)当服务调用失败后
拦截器的处理顺序,可以分为两大类:一类为网关平台自带的拦截器,例如安全校验、日志记录等;一类为网关层逻辑开发的,例如格式转换等。一般来说,网关先执行网关平台自带的拦截器,再执行为了业务逻辑编写的拦截器。当然,网关也需要提供一种机制,可以较容易地调整拦截器的执行顺序。最简单的一种方法,就是给每个拦截器定义一个优先级,网关按优先级顺序依次调用各拦截器。
对网关层来说,它接收和处理的数据都是Request对象,网关层在接收到请求后,把请求封装为Request对象,为了让后续的filter能够获得这个对象,可以考虑把Request对象保存在线程变量中。
有些拦截器,例如一些调试日志的拦截器,通常情况下都是关闭的,只有在出现问题的时候才需要打开。为了保证网关的高可用,网关层必须具备在线启用或关闭拦截器的能力。一般,网关需要提供restful接口方式,来关闭和启用一个拦截器。类似这样的命令:PUT /apigateway/v1/filters/filterName?enable=value

5、API管理与动态发布设计
对服务管理来说,分为前端服务管理与后端服务管理。前端服务指的是网关层暴露给客户端使用的服务API,后端服务指的是服务层提供的业务服务API。一个服务暴露给客户端使用,除了网关层和服务层提供服务的代码外,还需要配置前端服务与后端服务的映射关系。
网关层API调用服务层API,有多种方式。例如,可以由按照服务层API的服务契约,生成一段客户端代码,发布给网关层使用。这种方式的弊端是,网关层代码依赖于服务层代码,服务层频繁修改和调整接口时,导致网关层的代码很难维护。
可以通过配置前后端服务映射的方式,解耦网关层对服务层的依赖。当服务层的API(例如服务名、参数名等)发生变化时,只需调整映射关系,无需对网关层的代码进行调整。网关层按照映射,自动装配服务层API所需要的数据格式。这样,网关层团队与服务层团队可以相互不受干扰地开发各自的服务。

3. 优缺点介绍

3.1 优点
(1)解耦作用:它封装了应用的内部结构,客户端直接和网关通信,而不必调用特定的服务。
(2)提供给每种客户端特定优化的API。
(3)减少请求环路、简化客户端逻辑。比如说,API Gateway使得客户端用一次请求就可以从多个service处获取数据。

3.2 缺点
(1)必须被开发、部署和管理成一个高度可用的组件,也有成为开发瓶颈的危险。
(2)为了暴露出每个微服务的,开发者必须更新API网关。
(3)Partner OpenAPI:
转发路由作用:对外提供的接口服务,一般直接把请求转发到合适的service,但是此时的API GW需要增加配额、限流、令牌等一系列安全管控功能。对外提供隔离作用:请求路由,安全认证,负载均衡,限流、监控、权限控制等等。

4. 业界常用的API网关方案

通常情况下, API 网关要做很多工作,它作为一个系统的后端总入口,承载着所有服务的组合路由转换等工作,除此之外,我们一般也会把安全,限流,缓存,日志,监控,重试,熔断等放到 API 网关来做,那么可以试想在高并发的情况下,这里可能会出现一个性能瓶颈。
另外,如果没有开源项目的支撑前提下,自己来做这样一套东西,是非常大的一个工作量,而且还要做 API 网关本身的高可用等,如果一旦做不好,有可能最先挂掉的不是你的其他服务,而就是这个API网关。
4.1 基于OpenResty 的 Nginx
性能和高可用性
Nginx性能极高,Nginx先天的事件驱动型设计、全异步的网络I/O处理机制、极少的进程间切换以及许多优化设计,都使得Nginx天生善于处理高并发压力下的互联网请求。Nginx的稳定性也在各大网站得到验证。官方提供的常用模块都非常稳定,每个worker进程相对独立,master进程在1个worker进程出错时可以快速“拉起”新的worker子进程提供服务。支持热部署,可以不停机更新配置文件、更新日志文件、更新服务器程序版本。

扩展性上
Nginx的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极低的模块组成。因此,当对某一个模块修复Bug或进行升级时,可以专注于模块自身,无须在意其他

易用性上
Nginx使用最自由的BSD许可协议,允许用户在自己的项目中直接使用或修改Nginx源码,有大量的插件可以利用。但是,Nginx模块需要用C开发,而且必须符合一系列复杂的规则。虽然通过第三方模块,可以支持Nginx与Perl、Lua等脚本语言集成工作,但对使用者的要求还是很高。

4.2 Spring Cloud Zuul

 

基本功能
验证与安全保障: 识别面向各类资源的验证要求并拒绝那些与要求不符的请求。
审查与监控: 在边缘位置追踪有意义数据及统计结果,从而为我们带来准确的生产状态结论。
动态路由: 以动态方式根据需要将请求路由至不同后端集群处。
压力测试: 逐渐增加指向集群的负载流量,从而计算性能水平。
负载分配: 为每一种负载类型分配对应容量,并弃用超出限定值的请求。
静态响应处理: 在边缘位置直接建立部分响应,从而避免其流入内部集群。
Netflix公司还利用Zuul的功能通过金丝雀版本实现精确路由与压力测试。
虽然提供的功能还算丰富,但都比较弱,很难满足高要求的场景。

性能和高可用性
Zuul处理每个请求的方式是针对每个请求是用一个线程来处理。通常情况下,为了提高性能,所有请求会被放到处理队列中,从线程池中选取空闲线程来处理该请求。2016年底,Netflix将它们的网关服务Zuul进行了升级,全新的Zuul 2将HTTP请求的处理方式从同步变成了异步,以提升其处理性能。除了Netflix公司,目前Zuul在企业中用的还比较少,性能和稳定性方面还有待进一步观察。

扩展性上
从Zuul的架构图上可以看出,Zuul更像是一个过滤器框架,其自身的路由、日志、反向代理、ddos预防等功能都是通过过滤器实现的。提供了PRE、ROUTING、POST和ERROR四个扩展点,可以很容易的添加自定义的过滤器。

易用性上
Zuul的搭建非常简便,使用和配置也很简单。Zuul的开源社区比较活跃,一直在更新状态,但版本不算太稳定,在使用的过程中,还有一些坑要踩。例如重定向问题、异常处理问题,还没有解决的很好,需要自己重写一些filter。

4.3 Mashape Kong

 

Kong的一个非常诱人的地方就是提供了大量的插件来扩展应用,通过设置不同的插件可以为服务提供各种增强的功能。Kong默认插件插件包括:

身份认证
Kong提供了Basic Authentication、Key authentication、OAuth2.0 authentication、HMAC authentication、JWT、LDAP authentication认证实现。

安全
ACL(访问控制)、CORS(跨域资源共享)、动态SSL、IP限制、爬虫检测实现。

流量控制
请求限流(基于请求计数限流)、上游响应限流(根据upstream响应计数限流)、请求大小限制。限流支持本地、Redis和集群限流模式。

分析监控
Galileo(记录请求和响应数据,实现API分析)、Datadog(记录API Metric如请求次数、请求大小、响应状态和延迟,可视化API Metric)、Runscope(记录请求和响应数据,实现API性能测试和监控)。

请求转换、响应转换
Kong本身也是基于Nginx的,所以在性能和稳定性上都没有问题。Kong作为一款商业软件,在Nginx上做了很扩展工作,而且还有很多付费的商业插件。Kong本身也有付费的企业版,其中包括技术支持、使用培训服务以及 API 分析插件。
从对上面三种方案的比较中可以看到,Spring Cloud Zuul非常适合创业初期的团队,快速搭建一个“基本可用”的API网关。Nginx适合有较强研发团队,自主开发企业自己的API网关。Kong适合于没有自身研发团队,但需要拥有企业级API网关能力的公司。

五、参考文章

    1. https://mp.weixin.qq.com/s/YOxX65s-eaXTWW8eSwvaZQ
    2. https://mp.weixin.qq.com/s/LRQaFbwk1UOuOQPYwu2Ovw
    3. https://mp.weixin.qq.com/s/nbtniSjr06rfboiYaW0IsQ
    4. https://mp.weixin.qq.com/s/SUt-mFYSkNHx6QA2UkNW1w
posted @ 2019-06-04 12:35  故事爱人  阅读(987)  评论(0编辑  收藏  举报