如何识别架构设计复杂度
架构设计:识别复杂度
我在前面讲过,架构设计的本质目的是为了解决软件系统的复杂性,所以在我们设计架构时,首先就要分析系统的复杂性。只有正确分析出了系统的复杂性,后续的架构设计方案才不会偏离方向;否则,如果对系统的复杂性判断错误,即使后续的架构设计方案再完美再先进,都是南辕北辙,做的越好,错的越多、越离谱。
例如,如果一个系统的复杂度本来是业务逻辑太复杂,功能耦合严重,架构师却设计了一个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亿次。
尽管这些数据看起来十分庞大,但对于架构师来说,关注的并非一天的数据,而是1秒钟的数据(即TPS和QPS)。按秒来计算,每天内平均每秒写入消息数为115条,每秒读取的消息数为1150条。考虑到读写操作并不完全平均,因此设计目标应以峰值为基础。峰值通常取平均值的3倍。因此,消息队列系统的TPS为345,QPS为3450。尽管这个数据量级相对较高,但新来的架构师发现,“微讯微博”系统中存在强耦合的业务子系统,导致系统间协作效率低下。例如,用户发一条微博后,微博子系统需要通知审核、统计、广告、消息等多个子系统进行处理,而每通知一个新系统都需要进行接口设计和测试,问题定位也非常麻烦。同样的情况也出现在等级子系统中。针对这些问题,架构师提出了引入消息队列系统的建议,并经过一系列操作,该系统终于立项。其他相关背景信息包括中间件团队规模不大、熟悉Java语言但有一名新同事很擅长C/C++、开发平台是Linux且数据库为MySQL,业务系统当前是单机房部署,没有双机房。
针对“微讯微博”的消息队列系统,架构师采用了“排查法”来分析复杂度。首先,他通过计算每天微博产生的消息数量,估算出消息队列需要的TPS和QPS。虽然当前业务规模下,系统对性能的要求不是很高,但为了预留一定的容量以应对未来的业务增长,设计目标被设定为峰值的4倍。因此,系统需要具备高性能读取的能力。另外,考虑到消息丢失可能导致的严重后果,消息队列系统也需要具备高可用性,包括消息写入、存储和读取。不过,由于消息队列的功能较为明确,不需要进行过多的扩展,因此可扩展性并不是复杂度的关键。
在实际应用中,不同的公司或团队可能需要考虑其他方面的复杂度,例如安全性、成本等。针对“微讯微博”的消息队列系统,综合分析其复杂性主要体现在高性能消息读取、高可用消息写入、高可用消息存储和高可用消息读取等方面。
针对这些复杂度,我将在后面文章为你分析
小结
今天我聊了架构设计的第一个步骤“识别复杂度”,并且通过一个模拟的场景讲述了“排查法”的具体分析方式,欢迎给我留下宝贵意见
如果本文对你有帮助的话,欢迎点赞分享,这对我继续分享&创作优质文章非常重要。感谢
本文由mdnice多平台发布
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net