架构设计复杂度

识别复杂度

大家好,我是易安!

如前所述,架构设计的核心目的是解决软件系统的复杂性。因此,在设计架构时,首先要分析系统的复杂性。只有正确分析出系统的复杂性,才能制定正确的架构设计方案,否则即使设计方案再完美先进,也会偏离正确的方向,越做越错。

例如,如果一个系统的复杂度主要来源于业务逻辑复杂、功能耦合严重,架构师却设计了一个TPS达到10000/秒的高性能架构,那么即使这个架构的性能再优秀,也无法解决系统的真正复杂性问题。

架构的复杂度主要包括“高性能”、“高可用”和“可扩展”等几个方面。但是,在具体判断复杂性时,架构师不能生搬硬套,认为在任何情况下架构都必须同时满足这三个方面的要求。实际上,大部分场景下,复杂度只包含其中某一个方面,少数情况下包含其中两个方面。如果真的需要解决三个或三个以上的复杂度,要么说明系统之前的设计存在问题,要么可能是架构师判断失误。即使真的认为需要同时满足这三个方面的要求,也必须根据优先级进行排序。

如果一个系统上来就因为过度设计和错误的复杂性判断,按照腾讯QQ的用户量级和功能复杂度进行设计,高性能、高可用、可扩展、安全等技术一应俱全,一开始就设计出了40多个子系统,但实际上这些子系统是多余的,而且带来很多问题,如系统复杂无比、运维效率低下、开发效率低下等等。

后来接手的团队花费了两年时间将系统重构,合并许多子系统,将原来40多个子系统合并成不到20个子系统,整个系统才逐步稳定下来。如果接手了一个每个复杂度都存在问题的系统,正确的做法是将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。例如,“亿级用户平台”团队选择了优先降低子系统数量,这不仅提高了开发效率,而且消除了很多小问题。接着,团队在这个基础上开发了异地多活方案,取得了非常好的效果。

在解决复杂度问题时,要注意避免以下困境:要做的事情太多、设计方案过于复杂、同一个方案需要解决不同的复杂性等。因此,将主要的复杂度问题列出来,按优先级顺序进行解决是非常重要的。

对于按照复杂度优先级解决的方式,存在一个普遍的担忧:如果按照优先级来解决复杂度,可能会出现解决了优先级排在前面的复杂度后,解决后续复杂度的方案需要将已经落地的方案推倒重来。这个担忧理论上是可能的,但现实中几乎是不可能出现的,原因在于软件系统的可塑性和易变性。对于同一个复杂度问题,软件系统的方案可以有多个,总是可以挑出综合来看性价比最高的方案。

即使架构师决定要推倒重来,这个新的方案也必须能够同时解决已经被解决的复杂度问题,一般来说能够达到这种理想状态的方案基本都是依靠新技术的引入。例如,Hadoop能够将高可用、高性能、大容量三个大数据处理的复杂度问题同时解决。

识别复杂度对架构师来说是一项挑战,因为原始的需求中并没有哪个地方会明确地说明复杂度在哪里,需要架构师在理解需求的基础上进行分析。有经验的架构师可能一看需求就知道复杂度大概在哪里;如果经验不足,那只能采取“排查法”,从不同的角度逐一进行分析。

案例实战

假设一个创业公司,名为xx微博。该公司业务快速发展,系统数量不断增加,但系统间协作效率很低。例如,当用户发一条微博时,微博子系统需要通知审核、统计、广告和消息子系统进行相应操作。这意味着一条微博需要通知十几个不同的子系统,且这些通知都是通过接口调用完成的。每当引入一个新系统,微博子系统都必须设计接口、进行测试,并经常会和其他子系统的技术人员产生分歧,导致问题定位麻烦,微博子系统的开发人员备感压力。

另外,当用户等级达到VIP后,等级子系统需要通知福利、客服和商品子系统,以进行相应的操作。等级子系统的开发人员同样面临困扰。

新来的架构师结合自己的经验梳理这些问题后,敏锐地发现这些问题的根源在于架构上各业务子系统强耦合,而引入消息队列系统可以解决这个问题。经过分析、讨论、会议、汇报和审批等一系列操作,消息队列系统最终得以立项。

其他背景信息包括:

  • 中间件团队规模不大,大约6人左右。
  • 中间件团队熟悉Java语言,但有一位新同事擅长C/C++。
  • 开发平台为Linux,数据库为MySQL。
  • 目前整个业务系统是单机房部署,没有双机房。

为针对微博的消息队列系统,采用“排查法”来分析复杂度。具体分析过程如下:

  • 这个消息队列是否需要高性能?

假设微博系统用户每天发送1000万条微博,那么微博子系统一天会产生1000万条消息。如果平均每条消息被10个子系统读取,那么其他子系统读取的消息大约为1亿次。

然而,对于架构师来说,关注的并不是一天的数据,而是1秒钟的数据(即TPS和QPS)。按秒来计算,每天内平均每秒写入消息数为115条,每秒读取的消息数为1150条。由于读写操作并不完全平均,因此设计目标应以峰值为基础,通常取平均值的3倍。因此,消息队列系统的TPS为345,QPS为3450。虽然这个数据量级相对较高,但新来的架构师发现,微博系统中存在强耦合的业务子系统,导致系统间协作效率低下。例如,用户发一条微博后,微博子系统需要通知审核、统计、广告、消息等多个子系统进行处理,每通知一个新系统都需要进行接口设计和测试,问题定位也非常麻烦。同样的情况也出现在等级子系统中。针对这些问题,架构师提出了引入消息队列系统的建议,并经过一系列操作,该系统终于立项。

对于微博的消息队列系统,架构师采用了“排查法”来分析复杂度。首先,他通过计算每天微博产生的消息数量,估算出消息队列需要的TPS和QPS。尽管当前业务规模下,系统对性能的要求不是很高,但为了预留一定的容量以应对未来的业务增长,设计目标被设定为峰值的4倍。因此,系统需要具备高性能读取的能力。另外,考虑到消息丢失可能导致的严重后果,消息队列系统也需要具备高可用性,包括消息写入、存储和读取。但由于消息队列的功能较为明确,不需要进行过多的扩展,因此可扩展性并不是复杂度的关键。

在实际应用中,不同的公司或团队可能需要考虑其他方面的复杂度,例如安全性、成本等。针对微博的消息队列系统,综合分析其复杂性主要体现在高性能消息读取、高可用消息写入、高可用消息存储和高可用消息读取等方面。针对这些复杂度问题,架构师应根据业务、技术和团队等因素进行优先级排序,并逐个解决。在这个案例中,架构师将高性能读取和高可用消息写入作为主要解决的问题,并选用了消息队列系统来实现。同时,由于中间件团队规模较小,熟悉Java语言但有一名新同事很擅长C/C++,开发平台是Linux且数据库为MySQL,业务系统当前是单机房部署,没有双机房,架构师在选型时需要考虑到这些因素。最终,他选择了RabbitMQ作为消息队列系统,并采用C/C++语言进行客户端开发,以保证高性能的同时也考虑到团队成员的技术背景。

在设计和实现消息队列系统时,架构师还需要考虑到以下几个方面:

  • 消息队列系统的架构应该具备高可用性,包括节点故障、网络故障等情况下仍能保证消息的可靠传输和存储。
  • 需要进行消息的持久化存储,以防止数据丢失。
  • 消息队列的读写操作需要保证高性能和低延迟,特别是在高峰期的消息处理时,不能出现阻塞等问题。
  • 消息队列系统的安全性也需要考虑,特别是在涉及敏感数据时。
  • 需要进行消息的监控和报警,及时发现和解决问题。

在实际实现过程中,架构师还需要进行一些技术上的优化,如采用分布式架构、多线程技术、缓存技术等,以提高系统的性能和稳定性。

总之,对于复杂系统的设计和实现,架构师需要全面考虑各个方面的复杂度,并根据实际情况进行优先级排序,逐一解决。在解决复杂度问题的过程中,架构师还需要考虑到团队成员的技术背景、业务需求、安全性等因素,并进行合理的选型和技术方案设计,以实现高性能、高可用、可扩展和安全的系统。

针对这些复杂度,我将在后面文章为你分析

小结

今天我聊了架构设计的第一个步骤“识别复杂度”,并且通过一个模拟的场景讲述了“排查法”的具体分析方式,欢迎给我留下宝贵意见

如果本文对你有帮助的话,欢迎点赞分享,这对我继续分享,创作优质文章非常重要。感谢 !