0%

题目

1、预计:项目信息
2、软件维护的主要内容,提高可维护性的常见方法
3、预计:结合项目说明具体实施过程/遇到的问题及解决方案

简介

近些年,新能源汽车蓬勃发展,我司开发了一个针对新能源汽车的平台,主要包括了:媒体、社区、车型库等模块。我在该项目中担任技术经理,负责系统方案设计及技术指导工作。本文描述了该项目中维护性方面的设计与实施过程,主要包括应用端、服务端、部署运行三个部分。应用端采用 Nodejs 同构框架 NestJS,使用 Typescript 进行代码编写,提高了可阅读性、可修改性。服务端采用分层设计,并使用 REST 风格与应用端通信,并生成标准的 OpenAPI 文档,有效提高了可修改性、可阅读性。部署与运行阶段,采用 CI/CD 工具,实现了代码测试、打包、部署等功能,并使用 Serverless,提高了项目的可靠性、可移植性。

背景

2022 年,新能源汽车蓬勃发展,国家出台了相应的政策支持,此时市面上还没有专门针对新能源汽车的应用平台,用户在检索新能源车型信息的时候,无法快速准确的找到对应信息。为响应国家号召,满足用户需求,我司开发一个针对新能源汽车的一体化平台。

该项目于 2022 年 6 月开始,团队成员共 17 人,我在该项目中担任技术经理,主要负责系统方案定制及技术指导工作。该项目主要包括媒体、社区、车型库等主要模块,其中媒体模块主要为用户提供最新的新能源汽车新闻,主要功能有:简讯、文章、视频、最新车型等功能。社区模块为用户提供了讨论新能源车型的渠道,主要包括了:车友圈、热点话题、发帖、车型口碑等功能。车型库模块是该系统的核心,我们吸收传统汽车平台的经验,并在此基础上增加了一些新能源汽车特有的功能,比如三电系统、智能座舱、辅助驾驶等,并针对这些功能进行评测,建立了对应的评测系统。并由此延伸出选车、评测榜单等功能模块。

问题回应

软件的生命周期中,软件维护是提高系统寿命的一个主要手段,主要分四种维护类型,第一种是正确性维护,主要是修复系统中的 bug;适应性维护,系统状态或者系统数据变更后,系统需要进行更新或者迁移。完善性维护,当系统增加新功能或进行性能方面的优化属于该方面维护。预防性维护,适应未来的一种维护,比如专用的功能改成通用的功能。提高可维护性的常见方法有,提高可阅读性,完善的文档与规范的代码属于此类;提高可修改性,低耦合、高内聚的架构设计可以有效的提高可修改性;提高可测试性,测试是软件开发过程中不可或缺的环节,良好的系统可以更容易的进行测试;提升可靠性,一个稳定的软件,可以有效的降低维护成本。提升可移植性,应用软件的部署环境可能会发生变化,当环境变化时,如果我们采用环境无关的技术,比如 java 的虚拟机或者容器技术,可以有效的降低移植成本。

过度

一个良好的软件,应该是更容易维护的,以下就该系统的应用端、服务端、部署运行三个方面进行论述该项目的具体实施过程与解决方案。

正文

应用端

该项目是针对 C 端的汽车一体化应用平台,考虑到推广的便利性与开发成本,决定使用 B/S 架构。传统 B/S 架构中,一般会使用服务端渲染,但是这种方式,html 与后端的代码是放在一起的,可阅读性较差。这个时候,如果有功能需要进行维护,那么需要前端人员与后端人员同时在一个地方修改,因为前后端分工不同,这种方式明显降低了可修改性。所以我们决定使用前后端分离的方式,前端负责界面与功能交互,后端负责提供数据,降低耦合,提高可修改性。纯前端的应用,需要在浏览器使用 AJAX 技术去动态的获取后端数据,同时使用 Javascript 去渲染页面,最终通过拼接字符串或者模板的方式去生成 html 。这种方式因为没有 IDE 支持,可阅读性差,且修改也容易引起错误,可修改性差,且 javascript 是一种脚本语言,没有类型系统,当项目复杂后,阅读与修改都比较困难。所以我们决定使用基于 React 的全栈同构框架 NextJS,并使用微软出品的语言 Typescript 进行代码编写,并编译成 Javascript 在浏览器与 Nodejs 环境运行。这种方式可以使用服务端渲染,满足推广要求。使用 NextJS 框架 react 技术栈,有 IDE 支持,对开发人员友好,可以方便的生成 html,同时又使用 Typesctipt 语言进行类型控制,极大提高了可阅读性与可修改性。

服务端

服务端采用分层架构,共 6 层,主要包括:中间件层、守卫层、管道层、路由层、服务层、数据层,使用层次化风格的架构,可以有效的降低耦合度,提高可修改性。在与前端的通信上,我们选择 REST 风格的架构,该风格以资源为中心,使用 HTTP 协议进行构建,用不同的请求方式表示对资源的操作,主要有 GET,表示对资源的获取,POST 表示对资源的创建,PUT 表示对资源的全量更新,PATCH 表示对资源的部分更新,DELETE 表示删除资源。这种方式降低了前后端开发人员的沟通成本,同时因为资源定义明确,可以有效的提高可阅读性。我们在使用 REST 风格的时候,也生成了接口文档,在路由层使用装饰器风格的注解,标注每个资源的路由、入参、出参等详细描述,并使用 OpenAPI 标准生成了对应的文档,使用 swagger 工具在开发环境展示,有效提高了可阅读性。同时因为有了对应的标准接口文档,我们可以使用自动化接口测试工具对其进行测试,提高了可测试性。

部署与运行

该项目在设计阶段采用的是云原生架构,我们搭建了 DevOps 相关工具,代码版本管理工具使用 Git,并制定了代码的提交、质量规范,提交前进行预检,预检通过后,提交到 Gitlab 远程仓库,同时对应的负责人进行 Code Review,审核通过后合并对应分支,提升代码质量、可阅读性。当代码提交到指定分支后,自动运行代码检测工具,包括代码格式检测、单元测试等,提高了代码的可阅读性,降低了维护成本。检测通过后,使用容器化技术,将应用打包为 Docker 镜像,并提交到镜像仓库,提高了可移植性。打完完毕后,我们使用云厂商的服务,将应用镜像部署在 Serverless 上,即用即付,有效降低了运行成本,同时使用资源冗余的方式,多实例运行,自动伸缩,提高了应用的可靠性。同时在数据库层面上,我们使用的一主多从的方式进行部署,当某台数据库宕机后,可以自动切换其他节点,提高了可靠性。

结语

该项目于 2023 年 10 月上线,整体运行良好,未出现重大事故。后续我们做了一些完善性的维护,比如在服务端的数据层增加了缓存模块,由于该项目可修改性、可测试性良好,少量改动后便顺利上线。二期工程增加了移动端应用,因为采用 REST 风格架构,文档完善,可阅读性较好,后续也顺利上线。在项目的运行过程中,也遇到了一些问题,比如 Serverless 的冷启动问题,假如服务第一次启动,那么需要云厂商构建 VPC 网络,同时要下载镜像,同时启动镜像成功后,服务才会返回对应的数据,该过程耗时多达数秒,用户体验较差。 因为 serverless 其中一部分功能由云厂商控制,部分环节我们无法参与,所以我们只能对其中一部分功能做优化,比如裁剪镜像体积,降低云厂商拉取镜像的时间。根据不同时段的流量进行预留启动实例,降低冷启动概率。目前冷启动时间与概率已有所降低,镜像裁剪还有优化空间。

软件需求需要重新学一遍

论架构服务

  • B/S 架构
  • 分层架构
  • Restful 架构

云原生主题论点

系统安全架构设计

  • 访问控制
  • 内外网隔离
  • 开发环境与生产环境隔离

em

刚在想东西的时候发现。。

脑子里面空空如也

从小到大。。

我好像没有什么特别喜欢的爱好???

就特么离谱。。

计算机系统安全等级

  • 自主级保护
  • 系统审计级保护
  • 安全标记保护
  • 结构化保护
  • 访问验证保护(最高等级)

构建的组装方式

  • 顺序组装
  • 层次组装
  • 叠加组装

生命周期质量属性

  • 开发期
  • 运行期

软件复用三个阶段

  • 获取可复用的资产(没办法直接用,得先构造)
  • 管理可复用的资产
  • 使用可复用的资产

架构权衡分析方法(ATAM)四种质量属性

  • 性能
  • 安全
  • 可修改
  • 可用性(实用性)

特定领域软件体系结构基本活动

  • 领域分析,获取模型
  • 领域设计,获取DSSA
  • 领域实现,开发和组织可重用信息

系统测试的一句是 软件需求规格说明书

MIPS(每秒百万次指令数)的计算路径

一个指令为5个周期,每个周期3微秒 ,那么一个指令为 15 微秒。1秒 = 一百万微秒。一秒钟可运行 1 * 10^6 / 15 = 66666.66 次。约等于 0.067 百万次

公理

  • 自反率 Y∈X∈U 这,X->Y 成立
  • 增广率,若Z∈U且X->Y,则 ZX->ZY
  • 传递率, 若 X->Y,Y->Z,则 X->Z
  • 合并规则,如果 X->Y,X->Z,则 X->YZ
  • 伪传递规则,X->Y,WY->Z,则 XW->Z
  • 分解规则,X->Y及Z∈Y,则X->Z

常用协议

smtp : 25
pop3: 110
imap:143
ftp: 传输20 控制21

CMMI 软件能力评价,自顶向下

  • 顶层方针
  • 过程文件
  • 规程文件
  • 模板类文件

系统建模方法与基本工具

  • 结构化建模工具为数据流图
  • 信息建模方法工具是实体连续图(ERD)
  • 面向对象为UML

需求管理需要重新确认

中间件提供两种不同类型的支持

  • 交互支持
  • 提供公共服务

软件脆弱性

系统可靠性分析于设计

可靠性指标

可用性= 可用时间 / 总时间

串并联模型

alt text

串联可靠性(任意是一个失效的概率) = r1 可靠性 * r2 可靠性 * rn 可靠性
并联可靠性(同时失效的概率)= 1 - 串联可靠性

可靠性设计

alt text
alt text

  • N 版本冗余方案 (多个版本计算,交给表决器,表决出一个结果),并联
  • 恢复块方法(主块运行,验证不合格,交给后备块,直到最后一个后备块,直到通过验证通过,通过后执行,不合格异常),串联
  • 防卫式程序设计(发现错误后,能撤销错误状态,恢复到一个已知的正确状态中去)
  • 双机容错(一台出错,另外一台可用)
    • 双机热备(主系统出错后,备用系统才启用)
    • 双机互备(同时提供不同的服务,心跳出错,另外一台接管)
    • 双机双工(集群)

待复习

软件能力成熟度
设计模式
工作流参考模型
测试
UML
需求工程
ATAM
质量属性场景
ABSD
效用树
DSSA
关系代数

信息安全基础知识

五个基本要素

  • 机密性
  • 完整性
  • 可用性
  • 可控性
  • 可审查性
    alt text

信息安全范围

  • 设备安全
  • 内容安全
  • 数据安全
  • 行为安全

信息安全范围

信息存储安全

信息存储安全

数字签名

alt text

国密

国密

负载均衡技术

云原生架构

alt text

  • 服务化
  • 弹性
  • 可观测
  • 韧性
  • 自动化
  • 零信任
  • 架构持续演进

题目

论软件架构风格软件体系结构风格是描述某一特定应用领域中系统组织方式的惯用模式。体系结构风格定义一个系统家族,即一个体系结构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。体系结构风格反应了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效地组织成一个完整的系统。
请围绕“论软件架构风格”论题,依次从以下三个方面进行论述。

  1. 概要叙述你参与分析和设计的软件系统开发项目以及你所担任的主要工作。
  2. 软件系统开发中常用的软件架构风格有哪些?详细阐述每种风格的具体含义。
  3. 详细说明你所参与分析和设计的软件系统是采用什么软件架构风格的,并分析采用该架构风格设计的原因。

摘要

近些年,新能源汽车蓬勃发展,2022 年 6 月我司决定开发一个针对新能源汽车一体化平台,其中包括媒体、社区、选车等功能。我担任该项目的技术负责人,负责系统方案定制及技术指导工作。本文描述了该系统的架构分析与设计工作,其中包括三个主要部分,应用系统,该系统采用 B/S 架构,前后端分离的服务端渲染模式,满足了推广、跨平台等需求,降低了开发成本,明确了职责分工。后端服务,该部分采用层次化架构,通过划分不同的层,实现了一种明确职责,耦合性低,方便测试的应用程序。应用通讯,该部分采用 REST 架构风格,一种约定大于配置的架构,有良好的扩展性,降低了学习与开发成本。该系统于 2023 年 10 月上线运行,运行效果良好。

正文

2022 年,新能源汽车开始蓬勃发展,国家发布了相关政策进行引导规划。此时,市面上并没有针对新能源汽车的应用平台,导致用户在搜索车型时,无法快速准确的找到对应的新能源汽车信息。为响应政府号召,满足用户需求,我司决定开发一个针对新能源汽车的一体化平台。

该项目于 2022 年 6 月开始,团队成员共 17 人,我在该项目中担任技术负责人,主要负责系统方案定制及技术指导工作。该项目主要包括媒体、社区、车型库等主要功能模块,其中媒体模块用于新能源汽车的消息发布,包括了图文、视频、简报及最新车型信息等子模块,可以让用户方便的接收新能源汽车消息。社区模块主要为用户提供讨论渠道,其中包括了车型品牌圈子、车型话题讨论、热点新闻、车型打分与评价等功能。车型库模块是其中的核心,在传统汽车平台的基础上,我们增加了许多新能源汽车特有的功能,比如三电系统、辅助驾驶、智能座舱等,我们针对这些功能做了相应评测,建立了对应的评测系统,并在此基础上增加了榜单与选车等功能。

在实践中,我们使用不同的架构来满足系统的需求,架构风格是对历史工程经验的总结,可以有效的降低设计与沟通成本。传统的架构风格可以分为五大类,数据流风格、调用/返回风格、独立构件风格、虚拟机风格、仓库风格。其中数据流风格包括批处理、管道/过滤器风格。调用/返回风格包括主程序/子程序风格、数据抽象和面向对象风格、层次化结构风格。独立构件风格包括进程通讯风格、事件驱动风格。虚拟机风格包括解释器架构风格与基于规则的系统。仓库风格包括以数据库架构风格、黑板架构风格。其中常用的风格有,批处理风格,该风格的主要特征为一次性输入数据,数据经过不同的节点,每个节点处理完后进入下一个节点,直到处理完毕。层次化架构风格,该模式约定不同的层级,每个层级只做一类事情,一般只调用下一层,具有结构明确、耦合度低、维护方便等优点,同时分层过多也会带来性能降低等问题。数据库架构风格,该风格以数据为中心,进行集中存储,同时共享数据状态。除上述架构外,微服务架构也是一种比较常用的架构风格,该风格颗粒度细,独立部署运行,使用轻量级的通讯协议,如 HTTP,具有耦合度低,合作开发效率高,适合大型项目等特点。

该项目立项后进行需求分析,为了通用性,应用系统使用 B/S 架构,优先满足推广与跨平台等需求并保留未来的扩展性。服务端采用分层架构,明确责任并解耦。同时约定使用类 REST 架构风格进行通讯。

  1. 应用系统
    该系统主要采用 B/S 架构风格,传统 B/S 架构中,客户端与服务端开发人员往往是不同的人,但是要在一个项目中进行开发,会出现分工不明确,责任不清晰等问题,所以使用前后端分离的方式进行架构设计,客户端开发人员可以专注于 UI 的交互,数据通过 HTTP 协议与后端进行通讯,后端开发人员可以专注于业务流程的开发,明确责任,方便维护。一般前后端分离,前端只负责 UI 的交互,数据通过 AJAX 等技术去后端获取,展示效果通过 JavaScript 进行操作渲染,导致最终呈现在浏览器源码上的 HTML 是一个固定的结构,没有业务的相关数据,无法进行 SEO。因为该项目有推广需求,所以决定使用 SSR(服务端渲染)同构技术,客户端服务端都采用相同的 JavaScript 语言,客户端使用浏览器提供的 JS 引擎,服务端使用 NodeJS 运行时。用户或者爬虫初次访问页面的时候,NodeJS 会执行对应的 JavaScript 代码,生成对应的 HTML 与运行上下文返回给客户端,客户端拿到后,可以在客户端进行 UI 展示、路由控制等功能。按照该方案,可以做 SEO,满足推广需求,使用同构模式,同一套代码运行在两端,降低了开发成本。同时前后端分离,明确职责与分工。
  2. 后端服务
    该部分主要采用层次化架构风格,主要包括的层包括:中间件层,守卫层,管道层,控制器层,服务层,数据层。其中中间件层用来处理日志,包括用户请求信息,系统响应时间等。项目使用 Json Web Token 进行登录验证,其中主要的用户权限验证在守卫层进行处理。管道层用于输入输出数据的转换与校验,其中有输入部分可以在该层转化为标准输入,以及安全性的预防,如 XSS 攻击。输出数据的处理包括 HTTP 状态码的处理,返回体数据的格式标准化等功能。控制器层用于处理路由响应以及提供标准出入参模板,并委托给服务层处理业务。服务层为主要的业务逻辑处理空间,提供可复用的功能模块,做好封装,方便调用。数据层,该层主要用于数据的存储与交互,其中包括两个主要部分,一部分是数据的实体映射,该部分标记了数据实体与类的映射关系,简化了数据操作,增加了可维护性。另外一部分是针对数据操作的封装,包括数据库、缓存、队列等数据源的增删改查,由于已标记实体映射关系,可以做到与数据库无关,降低了耦合度。该架构风格可以提供一种职责清晰,低耦合,方便测试的应用程序。
  3. 前后端通讯
    考虑到通用性,通讯协议使用 HTTP,架构采用 REST 风格。REST 风格是一种以资源为中心的架构风格,所有的操作均是对资源的控制。REST 对应的 HTTP 控制操作有 GET、POST、PATCH、PUT、DELETE 等方法,GET 表示对资源的获取,POST 表示对资源的新增,PATCH 表示对资源的部分更新,PUT 表示对资源的整体替换,DEL 表示删除资源。REST 标准中要求使用 HTTP 状态码来表示对操作资源的响应,同时在返回体中标记该资源的状态。但是实际开发中会发现 HTTP 状态码过少,且有些复杂状态需要通过响应体里面的内容去判断如何继续交互。所以我们对 REST 做了一些改动,将请求分为是否到达业务层,如果没有达到业务层,按照标准 REST 风格进行响应。如果达到业务层那么统一状态码为 200,表示操作已经发生,在响应体里面以约定的标准格式表示本次处理的状态。项目中约定,业务状态码为 0,那么表示此次交互成功。如果业务状态码非 0,表示业务处理异常,客户端需要根据响应体里面的状态码、错误信息、参考文档链接等信息定位异常确定后续操作逻辑。这种以约定大于配置的方式降低学习和实现成本,极大简化了开发人员的心智负担。

该项目于 2023 年 10 月上线,目前已运行一年多,在此期间未出现严重生产事故。由于基于 B/S 架构风格,且前后端分离,扩展性较好,在二期工程增加移动设备支持的时候,服务端仅少量改动,便顺利上线,节约了开发成本。项目在运行过程中,遇到过数据库压力比较大的情况,我们在调用频率较高的业务上增加了缓存,并在数据库上做了读写分离、分库分表等操作后趋于稳定。

后续为了部署扩容方便,增加了 CI/CD 流程,因为服务端在设计之初是无状态的,方便横向扩展,我们将所有的应用都打包为 Docker 镜像,部署在云服务平台的 ServerLess 上,使用后才付费,极大降低了运行及维护成本。但同时也遇到了 ServerLess 的冷启动问题,当用户的请求到达云服务后,服务会判断当前的实例是否充足,如果无法满足当前的请求,服务会进入冷启动。冷启动时,服务器会去拉取镜像到本地,并启动该镜像,启动成功后,用户的请求才会被响应,该过程耗时几秒至几十秒不等,用户体验较差。由于 ServerLess的资源准备、镜像拉取和启动是云服务厂商控制,这部分环节我们无法参与,所以方案上,主要分为两部分,一是在流量高峰期提前预热服务,满足峰值流量要求,降低冷启动出现概率。二是优化容器镜像,减少镜像拉取和启动时间。目前冷启动概率已明显减少,镜像优化还有提升空间。