目录

系统架构对话(五):设计已经做完了,怎么知道它哪里会出问题?

系统架构对话第 5 篇

前四篇都是从质量目标出发找手段:要性能,就看缓冲、并发和调度;要可用性,就看检测和恢复。可真实项目里,很多决定早就做完了。这时更常见的问题是反过来的:这些已经做了的决定,对系统意味着什么,哪里可能出问题?

这就是架构评估要回答的事。这一篇仍用那套五路采集系统,素材全是前面几篇已经出现过的决定。

案例设定:一个主界面进程加五个采集进程,一路一个进程;每路输入约 26 MB/s;采集进程每秒上报一次状态,主界面进程连续 3 次收不到就判定出事并重启它;原始包直接存盘,离线后处理程序负责帧对齐和数据转换。

一个决定,几个属性

问:把五路拆成一路一个进程,哪些质量属性变好了,哪些变差了?

答:我的第一反应是“可靠性提高了,复杂度也提高了”。前半句方向对:一路崩溃不再拖垮其他四路,主界面进程还会自动重启它,更贴切的说法是可用性变好。还漏了性能,拆进程的初衷本来就是让五路不再挤在一个进程里抢线程、一起被同一次回收停住。

后半句的问题在“复杂度”。它不是质量属性,没法和变好的那几项放在一起比。评估做不下去,往往就卡在这种说法上。

问:那换个问法:拆开以后,开发或测试时哪一件具体的事更费劲了?

答:多了一套进程间通信。“连续 3 次收不到上报就重启”是跨进程的行为,得手动杀进程才测得到,这是可测试性下降;采集进程想多报一个字段,两边程序和通信约定都要改,版本还得对上,这是可修改性下降。

合起来看,拆进程这一个决定,把性能、可用性往上拉,把可测试性、可修改性往下拉。一个决定同时牵动多个质量属性、而且方向相反,这种点叫权衡点。

说代价时,别停在“复杂了”。问一句“哪件事变费劲了”,再把那件事翻译成质量属性。

一个参数,一个属性

问:回读缓冲从 64 MB 改成 8 MB,最先受影响的是什么?

答:性能。第二篇算过,缓冲区买到的是时间:落盘偶尔慢一下,数据还在按每秒约 26 MB 进来,全靠缓冲区接住。缓冲越小,能扛的停顿越短,丢帧率就上去了。

丢帧率这个目标对“缓冲区大小”这个参数很敏感,所以它是性能的一个敏感点。敏感点本身不分好坏,它提醒的是:这里不能随手改,改了要重新验证对应的目标。

问:反过来调大到 1 GB,除了性能,还有什么会变差吗?

答:要看约束。内存富余、以后也不加路,那基本只影响性能;内存总量固定、以后还要多接几路,那每路占得越多,能接的路数就越少,可伸缩性变差了。

缓冲区大小,在什么约束下牵动的质量属性它算什么
内存富余,路数不再增加基本只有性能敏感点
内存固定,以后还要多接性能变好,可伸缩性变差权衡点

同一个参数是敏感点还是权衡点,取决于系统处在什么约束下。评估时把约束一起写下来,结论才站得住。

可能落空的,可以接受的

问:数据测完以后才拷到服务器归档。在那之前,原始数据只在采集电脑上,而这台电脑上的软件没有登录,谁都能操作。这段时间可能发生什么?

答:磁盘坏了,或者有人误删。两种情况分属不同的质量属性:误删是安全性(完整性)的问题,少了授权这一步;磁盘损坏是可靠性的问题,拷走之前只有一份。

这就是风险点:一个架构决定,可能让某个高优先级的质量目标落空。这里有两件事值得留意。第一,没做的决定也算。“不做访问控制”“拷走前只存一份”都不是写出来的代码,但都是架构决定,风险恰恰出在这里。第二,风险点带着判断,而敏感点、权衡点只说“这里牵动了哪些属性”。

问:采集进程崩溃时会丢几秒数据,也没有给每一路做主动冗余。为什么认为这不是问题?

答:要用的数据可以重新采;丢几帧对整份测试报告影响很小。再加上第一篇定下的口径:丢帧率低于 1% 指正常采集期间,不含崩溃造成的中断。

这是非风险点。它的关键在于总是带着前提,可以写成这样一句:

假设崩溃后能自动重启,丢失的几秒数据可以重采或对报告影响很小,则不给每一路做主动冗余是可以接受的。

前提一变,非风险就会变成风险。比如道路测试碰上一个很难再遇到的路况,偏偏这几秒丢了,又没法重采。所以前提要和结论一起记下来。

问:评估结论交给项目经理,哪一类最需要拿去安排人和时间?

答:风险点。这也是结论要分成四类的原因:交出去以后,用法各不相同。

结论交出去以后怎么用
风险点进行动计划:改设计,或者想办法降低风险
非风险点不用花钱,但前提要记下来,前提变了要重新评估
敏感点提醒开发和运维:这个参数改了,要验证对应的目标
权衡点请相关的人一起拍板:往哪边倾斜,是业务决定

一句结论怎么认

问:“调整业务数据的编码方式,会同时影响系统的性能和安全性。”这算风险点吧?毕竟要改设计。

答:我第一次也是这么判断的,但“要改”不是风险的标志。敏感点和权衡点本来就是在说“改了这个特性,质量属性会跟着变”。这句话没说哪个目标会落空,只说编码方式同时牵动了两个属性,所以是权衡点。

与其凭字眼猜,不如按固定的顺序看:

先看是否写明前提并说可以接受,是则为非风险点;再看是否说某个目标可能落空,是则为风险点;剩下的数牵动了几个质量属性,一个是敏感点,多个是权衡点。
先找前提,再找“可能落空”,剩下的数属性个数。图可点击放大。
试着按这个顺序判断三句话

① 把心跳上报间隔从 1 秒缩短到 0.1 秒,能更快发现采集进程故障,但进程间通信的开销也会增加。② 系统的日志格式至今没有统一规范,后续可能导致故障定位困难,影响可维护性。③ 数据库连接池的大小,决定了高峰期请求的响应时间。

① 权衡点:同样带着“改动”,但它牵动可用性(发现更快)和性能(开销更大)两个属性。② 风险点:“至今没有”“可能导致”。③ 敏感点:只牵动性能。

拿场景到架构上走一遍

问:如果评审的办法是发一张检查表,请几位资深同事按经验逐项打分,最大的弱点是什么?

答:大家拿到的是同一张表,可每一项“好不好”,仍由各人凭经验判断,结论很大程度上取决于打分人。这种办法便宜,能把大家的经验用起来,但很难回答“凭什么这么判断”。

另一类做法是拿具体场景到架构上走一遍,看架构到底怎样应对。

问:场景是“某一路采集进程崩溃,要尽快恢复采集”。从崩溃那一刻起,依次会发生什么?

答:我先写的是“无法采集,系统检测到崩溃,系统主动恢复”。顺序没错,但三步都只说了“应该发生什么”,没说“靠什么发生”。这种答案,打检查表的同事也会给,评审拿它判断不了好坏。追问“哪个进程、靠什么发现”,才落到了实处:主界面进程,靠心跳。

崩溃时只停这一路;主界面进程连续 3 次收不到上报后判定出事,约 3 秒;主界面进程重启采集进程并续写文件,需要 N 秒;离线后处理丢弃不完整的帧。这一路大约缺 3 + N 秒数据。
每一步都落到构件、机制和时间上。N 是重启到重新收数据的时间,需要实测。

走完以后,场景的度量就能算出来:这一路大约缺 3 + N 秒的数据,可以直接和需求对比。更有用的是,走的过程中会顺带冒出评估结论:心跳间隔和“连续 3 次”的门限是可用性的敏感点,间隔缩短又会牵动性能;整个恢复都靠主界面进程,它自己出事、还没恢复的那段时间里,采集进程再崩溃由谁来重启?这一点还需要确认,先记为待确认的风险点。

场景走查的每一步,都要回答“哪个构件、靠什么机制、用多少时间”。只写目标,就退回了凭感觉打分。

修改场景要走完整条链路

问:刚才是运行时的场景。假设以后换一种采集卡,哪些构件要改?

答:我先想到的是“新加一个采集类,其他基本不用改”。厂家相关的知识确实集中在采集类里,这一处对。

问:可是落盘存的是原始包,带着这家采集卡自己的包头格式。离线的帧对齐和转换程序还能直接用吗?

答:不能。修改场景要沿整条链路走:在线采集、落盘格式、离线后处理,凡是被牵连到的都要算。再加上主进程里绑定采集卡的那段逻辑,换卡一共要改三处。第四篇讨论“协议差异放在哪里”时,遇到的正是这条链路。

按这种方式逐个检查修改场景,可以把场景分成两种:现有架构不用改就支持的,比如运行中动态增减一路;要改架构才支持的,比如换卡,并列出要改的构件。接着再看几个要改架构的场景,会不会撞在同一个构件上:

修改场景要改的构件
换一种采集卡采集类、主进程的绑定逻辑、离线后处理程序
改落盘格式采集进程的写入、离线后处理程序

两个场景都撞在后处理程序上,因为它既要认识厂家的包格式,又要负责格式转换。撞在一起的场景越多,说明这个构件管的事越杂,后面也越难改。把协议描述作为后处理程序的输入,作用就是把这两个场景拆开。

这一套做法就是 SAAM 的核心。它是较早成形的架构分析方法,主要用来看可修改性:开发修改场景,描述架构,逐个评估场景,再看场景之间的交互,最后作出总体评价。场景交互是它最有特色的一步。

场景太多,先走哪些

问:这个系统里性能、可用性、安全性、可修改性都要看,场景能列出几十个。评审只有半天,下面五个只能先走两个,挑哪两个?

① 某一路采集进程崩溃 ② 主界面进程崩溃 ③ 换一种采集卡 ④ 测完还没拷走的数据被人误删 ⑤ 主界面换一套配色

答:我挑了 ① 和 ②,理由是“它们影响到系统核心”。这用的是重要性,是对的标准之一,但还缺一个:让架构满足这个场景有多难。

ATAM 用效用树处理这个问题。从“效用”出发,往下分出质量属性、属性分类,叶子是具体场景。修剪掉配色这类无关紧要的场景,再给每个叶子标两个档位:重要性、实现难度,各分 H、M、L。

效用树从效用分出性能、可用性、安全性、可修改性,叶子分别是持续采集、采集进程崩溃、主界面进程崩溃、未拷走的数据被误删、换一种采集卡;前三个标为 H、M,误删标为 H、L。
档位是这次讨论给出的判断,没有标准答案,要看理由。

标完以后出现了一个反差:挑场景时我没挑 ④,可单独问它的重要性,我又给了 H。最怕丢的本来就是原始数据。只凭直觉挑,人容易盯着自己熟悉的那一两类属性;效用树把几类属性并排摆出来,漏掉的就显出来了。

(H, M)、(H, H) 这类场景重要又不好做,风险多半藏在里面,要花时间细走。④ 是 (H, L):重要,但处理起来不难,很快就能定下办法。

回头看,这一篇前面做的事,正是 ATAM 的主线:收集场景并排出优先级,把重要场景放到架构上走,从中标出敏感点和权衡点,找出风险和非风险。它和 SAAM 的区别在于不只盯一个属性,而是在多个质量属性之间权衡。完整的步骤可以读 SEI 的 ATAM 技术报告。

先花钱解决哪个

问:误删这个风险点,有两个方案都能降低它:甲,给采集电脑上的软件加登录和权限;乙,每段数据录完,自动再复制一份到另一块硬盘。按什么选?

答:我说的是“成本和复杂度,以及风险发生的概率”。成本和概率都对,“复杂度”其实也属于成本。还缺一个关键维度:收益,也就是每个方案到底能挡住多少损失。两个方案挡住的东西并不一样:

方案挡得住误删挡得住磁盘损坏牵动的其他属性
甲 登录和权限能不能易用性:采集时多一步登录
乙 自动再存一份大部分能,除非两份都被删能性能:五路合计约 130 MB/s,写入量翻倍

所以不能只看哪个便宜,要看每花一份成本,能换回多少收益。CBAM 做的就是这笔账:它接着 ATAM 的结果往下走,估算各个架构策略的成本和收益,按投资回报排序。ATAM 告诉你哪里有风险,CBAM 帮你决定先花钱解决哪个。

请谁来评

问:评审这套系统,除了开发人员,还应该请谁?

答:我列了架构师、设计人员、测试人员、需求人员。这些人都站在造系统的一方,还缺用系统和维护系统的人:

谁在这个系统里会带来什么场景
最终用户开车采数的测试人员开车时看不了屏幕,要声音告警;某段断了要能重跑
用数据的人拿数据出报告的人丢多少帧会影响结论;数据要保存多久
维护的人管采集电脑和归档服务器的人磁盘满了怎么办;谁有权删数据
设备专家熟悉采集卡的人下一代采集卡的接口会怎么变

请哪些人,决定了能收集到哪些场景。挑场景时差点漏掉 ④、列评审人员时只想到开发一方,其实是同一个盲点:只从造系统的角度看。

问一个场景重不重要之前,先问一句:它是谁会提出来的?

三种方法放在一起

SAAM 回答这次修改要动哪些构件、几个修改会不会撞在一起;ATAM 由它发展而来,回答哪些点牵动多个属性、哪里可能让重要目标落空;CBAM 用 ATAM 的结果,回答先花钱解决哪个、每份成本换回多少收益。
三种方法依次往前多走一步:从修改代价,到多属性权衡,再到成本和收益。

这一篇用的素材,全是前四篇已经做过的决定。评估并没有引入新技术,它做的是把这些决定重新摆出来,逐个问清楚:牵动了哪些属性,在什么前提下可以接受,哪里可能落空,以及先处理哪个。

试着在自己的系统里找一遍

各找一个敏感点、权衡点、风险点和非风险点,非风险点写出“假设……,则……是可以接受的”的完整句子。再挑一个重要的运行时场景,按“步骤、构件、机制、时间”走一遍,看能不能算出度量,路上又冒出了哪些点。最后列出会提出场景的人,看看有没有只站在开发一方。

下一篇会把 ATAM 用到一个完整的案例上:从一组零散的系统描述里整理出效用树,再从中找出风险、敏感点和权衡点。