极客时间已完结课程限时免费阅读

10 | 架构设计流程:识别复杂度

10 | 架构设计流程:识别复杂度-极客时间

10 | 架构设计流程:识别复杂度

讲述:黄洲君

时长10:49大小4.95M

从今天开始,我将分 4 期,结合复杂度来源和架构设计原则,通过一个模拟的设计场景“前浪微博”,和你一起看看在实践中究竟如何进行架构设计。今天先来看架构设计流程第 1 步:识别复杂度。

架构设计第 1 步:识别复杂度

我在前面讲过,架构设计的本质目的是为了解决软件系统的复杂性,所以在我们设计架构时,首先就要分析系统的复杂性。只有正确分析出了系统的复杂性,后续的架构设计方案才不会偏离方向;否则,如果对系统的复杂性判断错误,即使后续的架构设计方案再完美再先进,都是南辕北辙,做的越好,错的越多、越离谱。
例如,如果一个系统的复杂度本来是业务逻辑太复杂,功能耦合严重,架构师却设计了一个 TPS 达到 50000/ 秒的高性能架构,即使这个架构最终的性能再优秀也没有任何意义,因为架构没有解决正确的复杂性问题。
架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面,但架构师在具体判断复杂性的时候,不能生搬硬套,认为任何时候架构都必须同时满足这三方面的要求。实际上大部分场景下,复杂度只是其中的某一个,少数情况下包含其中两个,如果真的出现同时需要解决三个或者三个以上的复杂度,要么说明这个系统之前设计的有问题,要么可能就是架构师的判断出现了失误,即使真的认为要同时满足这三方面的要求,也必须要进行优先级排序。
例如,专栏前面提到过的“亿级用户平台”失败的案例,设计对标腾讯的 QQ,按照腾讯 QQ 的用户量级和功能复杂度进行设计,高性能、高可用、可扩展、安全等技术一应俱全,一开始就设计出了 40 多个子系统,然后投入大量人力开发了将近 1 年时间才跌跌撞撞地正式上线。上线后发现之前的过度设计完全是多此一举,而且带来很多问题:
系统复杂无比,运维效率低下,每次业务版本升级都需要十几个子系统同步升级,操作步骤复杂,容易出错,出错后回滚还可能带来二次问题。
每次版本开发和升级都需要十几个子系统配合,开发效率低下。
子系统数量太多,关系复杂,小问题不断,而且出问题后定位困难。
开始设计的号称 TPS 50000/ 秒的系统,实际 TPS 连 500 都不到。
由于业务没有发展,最初的设计人员陆续离开,后来接手的团队,无奈又花了 2 年时间将系统重构,合并很多子系统,将原来 40 多个子系统合并成不到 20 个子系统,整个系统才逐步稳定下来。
如果运气真的不好,接手了一个每个复杂度都存在问题的系统,那应该怎么办呢?答案是一个个来解决问题,不要幻想一次架构重构解决所有问题。例如这个“亿级用户平台”的案例,后来接手的团队其实面临几个主要的问题:系统稳定性不高,经常出各种莫名的小问题;系统子系统数量太多,系统关系复杂,开发效率低;不支持异地多活,机房级别的故障会导致业务整体不可用。如果同时要解决这些问题,就可能会面临这些困境:
要做的事情太多,反而感觉无从下手。
设计方案本身太复杂,落地时间遥遥无期。
同一个方案要解决不同的复杂性,有的设计点是互相矛盾的。例如,要提升系统可用性,就需要将数据及时存储到硬盘上,而硬盘刷盘反过来又会影响系统性能。
因此,正确的做法是将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。“亿级用户平台”这个案例,团队就优先选择将子系统的数量降下来,后来发现子系统数量降下来后,不但开发效率提升了,原来经常发生的小问题也基本消失了,于是团队再在这个基础上做了异地多活方案,也取得了非常好的效果。
对于按照复杂度优先级解决的方式,存在一个普遍的担忧:如果按照优先级来解决复杂度,可能会出现解决了优先级排在前面的复杂度后,解决后续复杂度的方案需要将已经落地的方案推倒重来。这个担忧理论上是可能的,但现实中几乎是不可能出现的,原因在于软件系统的可塑性和易变性。对于同一个复杂度问题,软件系统的方案可以有多个,总是可以挑出综合来看性价比最高的方案。
即使架构师决定要推倒重来,这个新的方案也必须能够同时解决已经被解决的复杂度问题,一般来说能够达到这种理想状态的方案基本都是依靠新技术的引入。例如,Hadoop 能够将高可用、高性能、大容量三个大数据处理的复杂度问题同时解决。
识别复杂度对架构师来说是一项挑战,因为原始的需求中并没有哪个地方会明确地说明复杂度在哪里,需要架构师在理解需求的基础上进行分析。有经验的架构师可能一看需求就知道复杂度大概在哪里;如果经验不足,那只能采取“排查法”,从不同的角度逐一进行分析。

识别复杂度实战

我们假想一个创业公司,名称叫作“前浪微博”。前浪微博的业务发展很快,系统也越来越多,系统间协作的效率很低,例如:
用户发一条微博后,微博子系统需要通知审核子系统进行审核,然后通知统计子系统进行统计,再通知广告子系统进行广告预测,接着通知消息子系统进行消息推送……一条微博有十几个通知,目前都是系统间通过接口调用的。每通知一个新系统,微博子系统就要设计接口、进行测试,效率很低,问题定位很麻烦,经常和其他子系统的技术人员产生分岐,微博子系统的开发人员不胜其烦。
用户等级达到 VIP 后,等级子系统要通知福利子系统进行奖品发放,要通知客服子系统安排专属服务人员,要通知商品子系统进行商品打折处理……等级子系统的开发人员也是不胜其烦。
新来的架构师在梳理这些问题时,结合自己的经验,敏锐地发现了这些问题背后的根源在于架构上各业务子系统强耦合,而消息队列系统正好可以完成子系统的解耦,于是提议要引入消息队列系统。经过一分析二讨论三开会四汇报五审批等一系列操作后,消息队列系统终于立项了。其他背景信息还有:
中间件团队规模不大,大约 6 人左右。
中间件团队熟悉 Java 语言,但有一个新同事 C/C++ 很牛。
开发平台是 Linux,数据库是 MySQL。
目前整个业务系统是单机房部署,没有双机房。
针对前浪微博的消息队列系统,采用“排查法”来分析复杂度,具体分析过程是:
这个消息队列是否需要高性能
我们假设前浪微博系统用户每天发送 1000 万条微博,那么微博子系统一天会产生 1000 万条消息,我们再假设平均一条消息有 10 个子系统读取,那么其他子系统读取的消息大约是 1 亿次。
1000 万和 1 亿看起来很吓人,但对于架构师来说,关注的不是一天的数据,而是 1 秒的数据,即 TPS 和 QPS。我们将数据按照秒来计算,一天内平均每秒写入消息数为 115 条,每秒读取的消息数是 1150 条;再考虑系统的读写并不是完全平均的,设计的目标应该以峰值来计算。峰值一般取平均值的 3 倍,那么消息队列系统的 TPS 是 345,QPS 是 3450,这个量级的数据意味着并不要求高性能。
虽然根据当前业务规模计算的性能要求并不高,但业务会增长,因此系统设计需要考虑一定的性能余量。由于现在的基数较低,为了预留一定的系统容量应对后续业务的发展,我们将设计目标设定为峰值的 4 倍,因此最终的性能要求是:TPS 为 1380,QPS 为 13800。TPS 为 1380 并不高,但 QPS 为 13800 已经比较高了,因此高性能读取是复杂度之一。注意,这里的设计目标设定为峰值的 4 倍是根据业务发展速度来预估的,不是固定为 4 倍,不同的业务可以是 2 倍,也可以是 8 倍,但一般不要设定在 10 倍以上,更不要一上来就按照 100 倍预估。
这个消息队列是否需要高可用性
对于微博子系统来说,如果消息丢了,导致没有审核,然后触犯了国家法律法规,则是非常严重的事情;对于等级子系统来说,如果用户达到相应等级后,系统没有给他奖品和专属服务,则 VIP 用户会很不满意,导致用户流失从而损失收入,虽然也比较关键,但没有审核子系统丢消息那么严重。
综合来看,消息队列需要高可用性,包括消息写入、消息存储、消息读取都需要保证高可用性。
这个消息队列是否需要高可扩展性
消息队列的功能很明确,基本无须扩展,因此可扩展性不是这个消息队列的复杂度关键。
为了方便理解,这里我只排查“高性能”“高可用”“扩展性”这 3 个复杂度,在实际应用中,不同的公司或者团队,可能还有一些其他方面的复杂度分析。例如,金融系统可能需要考虑安全性,有的公司会考虑成本等。
综合分析下来,消息队列的复杂性主要体现在这几个方面:高性能消息读取、高可用消息写入、高可用消息存储、高可用消息读取。
“前浪微博”的消息队列设计才刚完成第 1 步,专栏下一期会根据今天识别的复杂度设计备选方案,前面提到的场景在下一期还会用到哦。

小结

今天我为你讲了架构设计流程的第一个步骤“识别复杂度”,并且通过一个模拟的场景讲述了“排查法”的具体分析方式,希望对你有所帮助。
这就是今天的全部内容,留一道思考题给你吧。尝试用排查法分析一下你参与过或者研究过的系统的复杂度,然后与你以前的理解对比一下,看看是否有什么新发现?
欢迎你把答案写到留言区,和我一起讨论。相信经过深度思考的回答,也会让你对知识的理解更加深刻。(编辑乱入:精彩的留言有机会获得丰厚福利哦!)
分享给需要的人,Ta购买本课程,你将得20
生成海报并分享

赞 49

提建议

上一篇
09 | 架构设计原则案例
下一篇
11 | 架构设计流程:设计备选方案
unpreview
 写留言

精选留言(94)

  • pk
    2018-05-21
    文中有一句话:TPS 1780 并不高。这个结论怎么来的?作者经验丰富,见过很高的TPS。 但作为新手,如何衡量这个性能要求高还是不高呢?

    作者回复: 对于架构师来说,常见系统的性能量级需要烂熟于心,例如nginx负载均衡性能是3万左右,mc的读取性能5万左右,kafka号称百万级,zookeeper写入读取2万以上,http请求访问大概在2万左右。 具体的数值和机器配置以及测试案例有关,但大概的量级不会变化很大。 如果是业务系统,由于业务复杂度差异很大,有的每秒500请求可能就是高性能了,因此需要针对业务进行性能测试,确立性能基线,方便后续架构设计做比较。

    共 17 条评论
    356
  • 公号-技术夜未眠
    2018-05-19
    识别复杂度心得 架构设计由需求所驱动,本质目的是为了解决软件系统的复杂性;为此,我们在进行架构设计时,需要以理解需求为前提,首要进行系统复杂性的分析。具体做法是: (1)构建复杂度的来源清单——高性能、可用性、扩展性、安全、低成本、规模等。 (2)结合需求、技术、团队、资源等对上述复杂度逐一分析是否需要?是否关键? “高性能”主要从软件系统未来的TPS、响应时间、服务器资源利用率等客观指标,也可以从用户的主观感受方面去考虑。 “可用性”主要从服务不中断等质量属性,符合行业政策、国家法规等方面去考虑。 “扩展性”则主要从功能需求的未来变更幅度等方面去考虑。 (3)按照上述的分析结论,得到复杂度按照优先级的排序清单,越是排在前面的复杂度,就越关键,就越优先解决。 需要特别注意的是:随着所处的业务阶段不同、外部的技术条件和环境的不同,得到的复杂度问题的优先级排序就会有所不同。一切皆变化。
    展开
    共 7 条评论
    89
  • XP
    2018-05-19
    感觉这个专栏定位是扫盲,留言的读者都是老司机

    作者回复: 应该是兄台水平高,所以觉得定位是扫盲,实际上很多人不知道这些内容,上网搜索也搜不到的

    共 8 条评论
    83
  • 云辉
    2018-05-20
    复杂度问题,还有是方案简单,但是沟通协调成本高,跨部门了,请问华仔,你们是自己推动,还是技术PMO推动。

    作者回复: 架构师推动是主要的,架构师需要五项全能:技术,沟通,推动,管理,撕逼😃😃😃

    共 11 条评论
    74
  • 空档滑行
    2018-05-20
    说下之前改造的一个系统,当时是这个系统从其他系统同步数据,经过一整套流程后将数据拆解到本地库的各个业务表中。 原来的系统是一个单机多线程程序,到了大促的时候延时非常厉害,因为马上又要大促了,首先想到的是扩展性的问题,于是就做了无状态服务拆分,可以横向扩展。在这过程成因为要控制单个同步实体任务的并发在处理幂等性上也花很大的功夫。做完这个后,又对非关键流程做了消息解耦,提高主流程的处理速度。 系统上线后运行稳定,但是到了大促当日发现速度提升很有限,将机器扩展到10台速度只提升了2-3倍,而且数据库和应用压力都很小。 后来分析下来瓶颈竟然是在数据库中间件上。其他系统大量的慢sql导致中间件处排队严重。 现在想起来,其实还是改造前优先级没搞清楚,根据之前的经验就把问题归结到扩展性上,投入了大部分精力在扩展性和可用性上,而没有对原来单机系统的性能做完整的测试和评估。其实当时做一个单机程序的压测大概就可以判断出问题所在(改造过程中也发现老的程序确实有bug)。还有就是高性能的优先级远大于扩展性和可用性,因为这个系统重启的影响非常小。改造的时候过于理想化的,想做一个各个方面均衡完善的架构
    展开

    作者回复: 所以系统复杂度识别是非常重要的,也没那么容易

    共 3 条评论
    39
  • 三月沙@wecatch
    2018-05-29
    专栏本身的牛逼之处在于系统化,相似概念其实在日常架构中已经多有涉及,但是专栏用自己独有的方法论浅显易懂的论述了这些概念以及它们的关系,值得在缺乏经验的团队广而告之
    共 1 条评论
    31
  • herome
    2018-05-19
    最近在做一个平台化的crm系统,也就是公司各个业务线都可以接入 ,或者外面的业务线也能接入。但是我们在开发过程中,比如查看商家等级列表这个接口,以前所有的接入方,都是查看就是查看,但是有个主要对接方提出了个需求是,查看后如果不存在 就插入一个默认等级。,但是其他对接方没有这样的需求,也就说原接口不能变,如果没有其他接入方我直接修改原来的接口即可,根本不考虑兼容。类似的问题数不胜数, 我们每次要么是if else这种代码走不同的逻辑,要么是 新写个接口,现在我们的代码的维护已经很混乱了,一个简单的逻辑,如查看等级列表,我就要维护好几套接口,好几套逻辑。 有想过变成可配置化的,但是没有好的思路。华哥对这方面有好的建议吗?😂
    展开

    作者回复: 试试设计模式的策略模式或者职责链模式

    共 3 条评论
    25
  • 梅子黄时雨
    2018-05-21
    微服务架构,是解决了什么复杂性问题呢

    作者回复: 可扩展

    共 3 条评论
    23
  • 黑客悟理
    2018-05-26
    留言全是干货……
    19
  • renwotao
    2018-06-13
    公司架构日志占了百分之二十的cpu,有什么好的解决方案吗

    作者回复: 日志压缩,采样,隔离

    共 2 条评论
    15
  • joyafa
    2018-05-31
    我现在做的是交易转发网关,性能瓶颈很大一部分也受上级券商网关影响,系统无状态,无数据库操作,因为涉及到交易,对可用性要求很高,需要能快速处理客户端的请求,经过多次压测,也没有排查出自身系统问题出在哪里,对系统压测,以及测试得到的数据该怎么分析,怎么找出问题所在?

    作者回复: 网关的性能可以参考nginx的性能,如果你们的测试数据和nginx做网关差异很大,那可能是并发模型甚至记日志这些不起眼的操作给拖慢了,如果差不多,那基本就是性能极限了

    共 2 条评论
    15
  • allen.huang
    2018-12-12
    识别复杂度方面比较难,如果判断错误,容易误入歧途。像我们公司是属于创业型公司,业务迭代很快,前面两三年都在堆业务,并且所有的业务都在一个系统上,web服务器一台,数据库RDS一台,那个时候流量并不大,公司高层没有重视,不考虑优化,还是以发展业务为主。 今年业务量起来了之后才重视,流量会对现有系统有所影响。于是讨论出最终方案,重新起一套框架,来重构,原来的老系统继续使用。结果实施发现周期重新起一套开发时间上,公司等不及,开发了3个月都没有出来就胎死腹中了。 但那个时候开始老系统经常频繁出问题了,有时是web请求量比较大WEB服务器CPU 100%,WEB服务器都登录不进去。有时是数据库操作比较频繁,数据库100%。只能重启web服务器来临时应对,有一次业务高峰更尴尬,连服务器重启都没有用,一重启流量一进来又100%。 这个时候通过分析web请求日志,慢查询日志来进行分析,然后来制定出优化方案,在原有的老系统上来进行优化。 但推进这个优化的过程中,也是比较费劲,研发人员比较害怕在老的系统上来进行优化了,怕优化后用不了,这好比是在给飞行中的飞机加油。后面通过领导的支持下达,通过分析报告的结果,把老系统的服务由简单到难逐步拆分: 1. 先拆分的是静态资源放到OSS上并做成CDN化。 2. 将慢查询进行优化,能利用缓存的,用缓存,大表的联表查询,拆分成单表查询。 3. 将轮询在调用接口的迁移到其他服务器,将一些轮询的计划任务服务也迁移到其他服务器。 这样子系统算是稳定下来,但要走的路还很长。 我写了这些事故的经历,就是在互联网公司成长过程中都会经历,对于技术复杂度的判断很重要,要是一开始我们就打算先从老系统来进行优化,就会避免一些事故的发生,还有就是技术上的推动,还是需要由公司领导的大力支持,首先要说服领导,说服老板,上通下达才行。
    展开

    作者回复: 架构师必须能说得动老板

    共 3 条评论
    13
  • Sir Peng
    2018-05-24
    华仔,架构师要具备的五项全能中,"撕逼"能在哪种情况中得已体现?

    作者回复: 说服别人重构,选择方案等很多时候要撕逼😂😂

    共 2 条评论
    11
  • prader26
    2021-01-21
    做了一个很小的系统,就给几个领导看,所以写代码的时候,没注意加锁,和并发。所有的功能都在一个系统里,只求速度。。。

    作者回复: 这种算demo系统,能跑起来就可以了,关键是要把界面做的漂亮😂

    10
  • huayu00
    2018-06-23
    “http请求访问大概在2万左右” 请问这个是指什么,数字怎么得来的?
    共 1 条评论
    11
  • 彡工鸟
    2018-05-20
    个人看法,在顶层上看一个系统,确实会有高可用,高性能,可扩展等等多个复杂度的要求,而且可能还真的无法分出个优先级。这样就落到都要抓,都要硬,最终无法分出个主次,导致设计四不像的系统出来。针对这种情况,是否就应该动用子系统一说,将系统拆分到一定的粒度,可以聚焦到一个,或者至多两个复杂度上?而子系统自然有子系统的架构设计,技术选型来针对性地解决其复杂度问题

    作者回复: 这是一种思路,比较适合业务系统,中间件系统就不太适合这种方式

    11
  • 慎独明强
    2020-07-25
    如何去分析自己系统的复杂度,那么项目中的痛点应该就是自己项目复杂度所在。我之前负责订单履约系统,由于订单是交易平台通过mq推送给我们,高并发不是我们系统的复杂度所在。订单拆单与发货都是自己内部系统,高性能也不是我们系统复杂度。但是我们的高可用影响到订单发货和客服满意度,订单系统是供应链的源头,与很多部门都有交互。响应业务快速性,业务复杂度和高可用是我们系统复杂度所在。按这样排序,业务复杂度,高可用,高性能。
    展开

    作者回复: 非常好的分析👍

    6
  • MichaelJY
    2018-05-21
    现在遇到这样的系统: 1.前后端没有分离,因为业务情况需要多窗口显示,然后是通过div分隔的,在多窗口的使用下会出现id冲突或者在a窗口的操作影响到b窗口的数据 2.系统分为三个子系统,业务子系统处理具体业务,公共子系统处理类似登录,权限,审批等,定时任务负责调度,三者之间通过http交互,没有集群,现在业务子系统耦合比较严重。业务子系统大概可以分为接入层,业务处理层,结算层,现在是一整个系统,经常发现结算层的逻辑变更,会导致接入层和业务层不可用 3.因为历史原因,对于数据校验方面做的比较差,经常出现数据格式问题,当然新增代码已经处理了这些,但是历史债务比较严重,且业务迭代很快 4.整个系统是单点,所有发版升级都会停服 我觉得最急的是4 >2 >1 >3,不知道对不对
    展开

    作者回复: 优先级需要根据业务和团队综合判断,不是单纯技术角度判断。 例如,如果停服影响不大的话,那2可能优于4; 如果历史债务导致投入很大,那3可能优于2

    5
  • xiaoya
    2018-08-02
    我是个新手,听一遍就忘了。记住的不多😭不开心。是我接触的太少不太重视这些吧,这些很关键?这么多理论的东西,嗨,我心性太差了。一口老想都吃掉,结果都不好。认识自己驾驭自己,一点点

    作者回复: 我也是从新手过来的,坚持就有收获,不要求一次就全部听懂了,

    共 4 条评论
    4
  • 秋天
    2018-05-21
    有没有系统提升架构思维的资料推荐,感觉还没有打破那个灵感,请大神指教?

    作者回复: 我的专栏就是呢,架构设计目的,架构设计原则,架构设计流程……都是架构设计系统化的技能点

    4