通过业务分析,读者可以理解业务中的概念,搞清楚业务流程的现状,设想引入系统后的新流程,之后可以着手考虑待建系统的需求。整个需求主要还是由业务人员、产品人员进行分析,架构师在其中给予技术上的支撑:一方面是了解所有的功能性需求,对存在技术风险的地方进行技术实现路径初步设想、主导技术预研,以及进行技术可行性判断;另一方面是对可用性、性能和安全性等非功能性需求进行把握。
研究需求首先要分析系统上下文,简单来说就是梳理系统的周边关系,找出能够与系统发生直接作用的人和外部系统。分析系统上下文,一般需要绘制一张系统上下文图。系统上下文图示例如图2-6所示,该示例体现了待建餐饮管理系统的总体周边关系,包括所有的系统用户和要对接的外部系统。
图2-6 系统上下文图示例
绘制系统上下文图需要注意以下几点。
·待建系统在正中间,内部不要有任何东西。在进行需求分析时,系统内部结构尚未开始考虑,因此总体上只能是一个黑盒。
·所有系统用户要绘制完整,不要遗漏。
·所有直接相关的外部系统要绘制完整,不管是系统要访问的,还是要访问系统的。
·各种用户和外部系统大多来自业务对象,所以需要注意命名的延续性。
·在绘制完成以后,对于其中不太容易理解的用户、外部系统,需要进行必要的说明。
分析系统上下文,并不是“拍脑袋”决定的,而是可以在一定程度上根据前面的业务分析产物推导出来的。在所有业务流程中,找出对系统有操作的人和外部系统,就可以放到系统上下文图中。以系统上下文图为基础就可以开始分析系统需求。
基于系统上下文图可以先初步分析各个元素相关的地点,作为架构设计的前提。系统参与者地点分析示例如表2-1所示。在系统上下文图中,除了待建系统,各种用户和外部系统的地点都是已知的或确定的,待建系统后台的地点也将参考这些元素的地点来确定。
表2-1 系统参与者地点分析示例
分析功能性需求主要由产品人员、业务人员负责,架构师在这一阶段起技术上的支撑作用,以及对产品人员和业务人员的产物进行确认。功能性需求分析的结果主要是系统用例的集合,介绍的是各种用户要用系统做成什么事。
一个常见的误区是把功能和用例搞混。需求分析讲的是用户使用系统完成什么事情,在后面的设计中才考虑为了完成这件事系统需要什么功能,用例和功能是前后推导关系。很多没有经过需求工程培训的人往往跳过用例,直接分析功能,这样是不对的。用例和功能并不一定是一一对应的关系。针对一个用例的功能设计可能是多种多样的。例如,一家火锅店的点餐系统其中一个用例是“顾客选择锅底”,在功能设计上,可能有多种选择。一是将锅底与一般菜肴一视同仁;二是有一项单独的选择锅底的功能,在选择时可以可视化地看到关联的图片,是辣还是不辣一目了然,以体现火锅店的特色。在第一种情况下,并不需要独立选择锅底的功能,而是沿用了点菜的功能。如果一上来就考虑功能,就会陷入设计的细节之中,花费大量精力考虑怎样才能让顾客的体验更好,从而影响需求分析阶段的进度。开发人员有时抱怨需求多变,其实往往并非需求发生了变化,而是设计发生了变化。真正的需求往往不会变,就是“顾客选择锅底”,不管功能怎么设计,只要能解决让顾客选择锅底的问题,就算满足了需求。开发人员往往也没有分清什么是需求、什么是设计,自己是基于需求在开发还是基于设计在开发。
分析系统用例的步骤如下:一是整理出所有用例的清单,可以通过用例图或表格来呈现;二是对用例进行细化,设想用户如何与系统交互,最终办成这件事,产物是用例规约(通常采用表格形式)。下面介绍用例图、用例规约的分析要点。
1.用例图
用例图是UML中的行为图,用于表达谁要用系统做什么事。用例图是UML中比较基础的内容,关于UML的资料已经很多,此处不再详细介绍。下面仅通过一个简单的例子来讲解绘制用例图的要点。系统用例图示例如图2-7所示。
图2-7 系统用例图示例
在系统上下文图的基础上,将用户与系统边框的连线延伸到系统内部,在线的末端将要办的事绘制成一个椭圆并命名,这就是一个系统用例。外部系统也可能要通过系统做事,所以将所有用户、外部系统要通过系统办成的事绘制完整就完成了系统用例图。另外,可能还要补充一些系统要自主办的事,如定时执行一些统计分析任务。
在用例图中,信息量十分有限,读者只能通过用例的名称来理解用户要办的事,因此用例命名十分重要(命名规范是使用动词短语,且长短要适中)。比较理想的是从用户出发,读到用例后能形成清晰完整的句子,如“游客分类浏览商品”和“登录用户添加购物车”。在绘制完用例图之后,可以尝试将所有连线上的文字进行朗读,确定是否比较自然,表达的意思是否清晰,以此作为判断用例命名是否合适的标准。
系统用例都是操作层面的事情,因此数量比较多,一个小型系统可能就有数十个,中型系统可能有数百个,大型系统可能有数千个。如果都绘制成用例图,那么一张大图可能放不下;如果绘制成多张用例图,那么难以查看和维护。其实还可以采用另一种方式,就是表格。用例图的信息量其实很小,就是各种用户使用系统做什么事情。将用例图想表达的信息通过表格整理出来,虽然不如用例图直观,但意思是一样的,并且可以不受用例数量的限制,填写表格的效率也会更高,因为不用花时间调整布局。系统用例清单表示例如表2-2所示。系统用例清单表基本上表达了与用例图同样的意思。在系统用例清单表中,可以用缩进来表达用例图中的包含关系,可以在备注中说明扩展关系。
表2-2 系统用例清单表示例
2.用例规约
用例图只相当于用例清单,所以信息量十分有限。详细的需求需要将一个个用例展开来说,讲清楚用户如何与系统交互,直至办成用户要办的事,这时就需要定义用例规约。用例规约要描述的是交互的过程,不涉及具体界面,因为具体界面是设计,还没有开始做。系统用例规约示例如表2-3所示。关于用例规约,一些需求分析方面的书籍已经讲得比较清楚,此处不再详细介绍。这一部分主要由业务人员和产品人员负责,架构师更多的是理解和确认,从中识别有无技术风险,并评估技术可行性。
表2-3 系统用例规约示例
续表
决定系统架构的主要因素往往是非功能性需求,而不是功能性需求。同样的功能集,如果系统压力小、维护频率低,架构就可以很简单,甚至整个后台可以设计成单体应用;如果系统压力大、维护频率高,可能是微服务架构,整个后端就会由很多组件构成。因此,架构师需要认真确认非功能性需求。非功能性需求虽然也是需求的一部分,但业务人员和产品人员往往不擅长对此进行分析,这时就需要架构师来协助。下面就主要的非功能性需求的分析方法进行讨论。
1.可用性需求
系统最基本的要求就是可访问、能使用,这就是可用性。可用性指标通常是一个百分比数值,规定在所有可能存在对系统访问的期间内,系统能够使用的百分比。在已上线的系统中,通常是按年来考核的。要定义这个数值,需要考虑的因素有国家标准、行业标准、客户要求,以及根据业务情况所确定的系统存在访问的时间段等。描述可用性,首先要确定时间段。这是因为不同业务的访问时间分布是不同的,有的系统随时都会有访问量(如在线购物网站),有的系统只在工作时间内有访问量(如考勤系统),有的系统只在全年的几天内存在访问量(如考试报名系统),所以需要先确定访问时间段。然后确定参考的国家标准、行业标准、客户要求和实际能力等,定义在目标时间段内系统可用的百分比。这个数值通常是99.9%、99.99%和99.999%。百分比越高,要实现的代价就越大,因为更高的可用性往往是由更高的冗余度提供的,而更高的冗余度对应更多的软硬件资源投入。定义可用性的百分比不能只说一个结果,而要将确定这个数值的理由阐述清楚。
说明可用性需求,只需要说明时间段范围和系统可用的时间百分比就足够了。有的人会画蛇添足地描写一些措施,这是因为他们没有分清楚什么是需求、什么是设计。在描述需求时,只能提要求,不能考虑实现方式。
2.性能需求
这一块要求架构师具备性能建模的能力。性能问题通常是架构师要解决的一大课题,通常会占用架构师很多的精力。要解决性能问题,首先必须搞清楚性能需求是什么,然后才能进行设计、实现和验证。所谓性能需求,就是系统对业务处理速度的要求。一方面是单笔业务的处理速度,体现为响应时间;另一方面是总体上的处理能力,体现为吞吐率或并发量。业务处理速度间接的衡量因素是能支持多少个用户同时在线,因为这些在线用户的操作会以一定的频率和比例产生各种业务的访问量。一个隐含的约束是后台的资源占用不能过高,否则会引起系统稳定性问题。定义性能需求,就是把以下几个指标定义清楚。
1)响应时间
响应时间一般是根据用户的可接受程度来定义的。由于不同的业务处理速度有快有慢,因此只定义一个统一的指标,势必有些业务会不达标。所以,除了统一的指标,还可以针对个别确实耗时较长的业务单独定义合理的指标。
2)吞吐率
在单位时间内,一项业务处理完成的请求数就是吞吐率。如果是单项业务,就可以直接定义吞吐率指标。但如果是多项业务一起考虑,虽然也能定义总体吞吐率,但这种总体吞吐率意义不大,因为有的业务逻辑简单,吞吐率很高,有的业务逻辑复杂,吞吐率很低,放在一起考虑就不合适。如果是每项业务单独定义吞吐率,在单独测试时虽然每项可能都达标,但在总体测试时由于资源争用,可能有一些就无法达标了。
3)并发
严格意义上的并发是指系统同时处理的请求数,与吞吐率不是一个概念。采用并发模型的业务通常处理时间长,如下载大容量文件、语音识别等,这种业务的特点是,输入数据非一次性输入,而是在一段时间内持续输入的,所以后台无法一次性以最大能力计算,而要消耗一定的资源,以一定的节奏来处理。当采用并发指标时,通常更加在意后端资源的占用。
4)在线用户
对于复合业务场景来说,可以用在线用户数来体现系统的压力水平。实际的访问模型是,系统的各个接口在某时间段内被以一定的比率随机调用。当在线用户数达到一定数量时,各项业务被调用的比率基本确定,唯一的变量就是在线用户数。所以,可以将在线用户数作为主要的性能指标。当这个指标确定后,与性能测试中的VUSER数对应就会比较容易。
5)资源限制
当系统处理业务时,后端的各台服务器都要消耗资源。为了保证系统平衡运行,需要将资源消耗控制在一定的范围内,以免发生崩溃或服务水平下降。通常将CPU利用率、内存使用率、磁盘繁忙率、网络占用率等指标限制在80%以下。
定义性能需求需要从已知的数据出发,通过进行合理的分析和推导得出以上几个指标。最终符合性能需求的条件通常是,在预想的在线用户数规模下,平均响应时间达标,同时后端资源占用未超过限制条件。其中,吞吐率和并发隐含在在线用户数背后,因为实际的请求是由用户操作间接产生的,有了一定的用户和这些用户使用各种业务的比率,各个接口在一定时间段内的请求数也就确定了,最终体现为各种接口的吞吐率。因此,吞吐率并不需要显式要求,只要请求不出错,平均响应时间达标就可以。有的运营分析类系统的用户可能很少,只有个位数,但每次分析要处理大量数据,可能耗时较长,可达到分钟甚至小时级别,这时性能需求的关注重点是响应时间,而不是在线用户数。在这种情况下,需要对每项可能耗时较长的业务单独定义响应时间,而不是考虑并发性,并且这种大计算量任务往往会占用100%的CPU或磁盘性能,这时对后端的资源占用也可以不做要求。
3.安全性需求
安全性可以分为通用安全性和特定安全性。架构师如何考虑安全性取决于组织内有无安全专家。如果没有安全专家,那么架构师要考虑所有方面;如果有安全专家,那么由安全专家考虑通用安全性,由架构师考虑特定安全性。但实际上,由于安全领域相对比较专业,涉及的知识点很多,架构师在安全方面通常并不会达到很专业的程度。为了避免项目的安全性考虑不足,软件组织最好配备安全专家(安全专家可以同时支撑多个项目)。
特定安全性是指由于系统的业务特点所面临的特定威胁。例如,考试报名系统可能只在一年中的某几天开放,这时会有人进行DDOS攻击,让一般人无法报名,此时攻击者会开展代为报名业务,从中牟取利益。对于系统涉及的业务,架构师更了解,因此建议由架构师考虑特定安全性,前提是架构师熟悉业务,并且具备安全威胁建模能力。
分析安全性需求,要基于威胁建模的思路,考虑的是系统中有什么资产可能被其他人以什么方式攻击。需要保护的资产有系统本身、各种数据和应用程序。针对系统的攻击方式主要是拒绝服务攻击,通过大量的请求让正常的请求无法执行,实施者可能是竞争对手,或者想通过系统不可用来获得不当利益的人。针对数据的攻击形式有窃取、篡改和破坏。数据总是要保护的重点,数据出现不可恢复的损坏、机密性数据被泄露、关键数据被篡改,都是不可接受的。数据破坏有可能是因为硬件发生故障或人员误操作;数据被泄露和篡改可能是因为受到了黑客攻击。针对应用程序的攻击形式是反编译以获取代码,攻击来源可能是竞争对手,或者黑客通过了解客户端代码来分析服务端漏洞,进而发起下一步攻击。除了这些具体的威胁,还有安全体系上的要求,如整个系统要求的等级保护为几级。体系上的安全性要求往往由安全部门主导,架构师更多的还是识别特定安全性需求。
安全性需求分析框架如表2-4所示。架构师应当与安全专家配合,共同确定整个系统的安全性需求。
表2-4 安全性需求分析框架
续表
4.兼容性需求
兼容性需求需要考虑完整,主要包括以下几方面。
1)CPU
CPU以架构作为兼容的基础,不同的架构对应不同的指令集,相互之间不能兼容。目前,服务端除了常见的x86_64架构,还有AArch64、RISC-V、LoongArch等,需要根据客户的实际情况考虑要兼容的CPU架构。CPU架构主要影响非跨平台使用的语言(如C语言、C++)编写的应用程序,在更改CPU架构时,这些程序需要重新编译才能运行,并且还要依赖各种库。
2)操作系统
服务端操作系统、客户端操作系统都需要考虑。操作系统的兼容性较为重要,如果将来要切换操作系统,那么修改应用程序的代价可能比较大。
3)数据库
有些客户对数据库选择有倾向性,并不是由软件组织决定的,所以需要事先考虑支持哪些数据库。
4)中间件
与数据库类似,软件组织可能需要提前适配多种中间件,避免临时开发。
5)浏览器
不同浏览器支持的标准不尽相同,显示同一页面的效果和行为可能不同,需要事先考虑客户实际使用的是哪种。
6)分辨率
在不同分辨率下页面会有不同的表现,所以需要事先规定,避免布局出现错乱甚至脚本无法运行。
5.可扩展性需求
可扩展性经常与可伸缩性混为一谈。从严格意义上来说,可扩展性是指功能而不是性能或容量的伸缩。可扩展性常见的意义包括增加功能容易、改变系统行为容易、与未知系统集成容易等。架构师需要识别的是将来可能出现变化的方面,在可变点上进行定义。例如,现在支持使用支付宝进行支付的系统,将来可能还需要支持其他支付平台。一个支持在线办理20种业务的系统,将来可能需要支持30种。隐含的约束是,在增加新的能力时对原有系统的逻辑不能有影响。
6.可伸缩性需求
可伸缩性主要是通过硬件配置的升级,使系统能够处理更大的业务量。可伸缩性其实包括性能伸缩和容量伸缩。性能伸缩是在单位时间内处理更多的业务,容量伸缩是能承载更多的数据,有时性能和容量同时需要伸缩。
定义可伸缩性需求,需要定义具体的数据指标,明确说出当前是多少,多长时间以后要达到多少。隐含的前提是,在系统伸缩时,软件不需要修改,最多调整一些配置,主要靠硬件的调整来实现快速伸缩。可伸缩性还有一些时效上的要求,定义多长时间完成系统伸缩。
7.成本需求
这一部分没有技术因素,单纯是经济上的考虑。可用性、性能、安全性在很大程度上与投入多少有关,如果不加以限制,架构师完全可以用更多更好的硬件和安全设备来满足需求,但现实是每个项目都有一定的预算限制,不可能任意选择。在开始设计之前,架构师必须明确预算限制,在这个限制内进行选择。
8.其他约束
除了以上非功能性需求,可能还有客户的喜好或要求、机房条件、团队成员技术能力等方面的限制,这些也需要识别且定义出来,并作为架构设计的前提。