架构设计的本质目的是为了解决软件系统的复杂性,所以在设计架构时,首先就要分析系统的复杂性。
架构的复杂度主要来源于“高性能”“高可用”“可扩展”等几个方面,在具体判断复杂性的时候,不能生搬硬套,认为任何时候架构都必须同时满足这三方面的要求。实际上大部分场景下,复杂度只是其中的某一个,少数情况下包含其中两个,出现同时需要解决三个或者三个以上的复杂度,要么说明这个系统之前设计的有问题,要么可能就是架构师的判断出现了失误,即使真的认为要同时满足这三方面的要求,也必须要进行优先级排序。
将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。
对于同一个复杂度问题,软件系统的方案可以有多个,总是可以挑出综合来看性价比最高的方案。如果决定要推倒重来,这个新的方案也必须能够同时解决已经被解决的复杂度问题,一般来说能够达到这种理想状态的方案基本都是依靠新技术的引入。
识别复杂度对架构师来说是一项挑战,因为原始的需求中并没有哪个地方会明确地说明复杂度在哪里,需要在理解需求的基础上进行分析,如果经验不足,那只能采取“排查法”,从不同的角度逐一进行分析。
成熟的架构师需要对已经存在的技术非常熟悉,对已经经过验证的架构模式烂熟于心,然后根据自己对业务的理解,挑选合适的架构模式进行组合,再对组合后的方案进行修改和调整。
常见系统性能量级:
- Nginx负载均衡性能是3万左右
- Memcached读取性能是5万左右
- Kafka号称百万级别
- Zookeeper读写2万左右
- HTTP请求2万左右
新技术层出不穷,经过时间考验,已经被各种场景验证过的成熟技术更多。例如:
有了明确的目标后,按图索骥就能够找到可选的解决方案。只有当这种方式完全无法满足需求的时候,才会考虑进行方案的创新。
事实上方案的创新绝大部分情况下也都是基于已有的成熟技术
- NoSQL:KV存储与数据库索引是类似的,Memcache 只是把数据库的索引独立出来做成了一个缓存系统
- Hadoop 大文件存储方案,基础是集群方案 + 数据复制方案
- Docker 虚拟化,基础是 LXC(Linux Containers)
- LevelDB 的文件存储结构是 Skip List
新技术都是在现有技术的基础上发展起来的,现有技术又来源于先前的技术。
基于已有的技术或者架构模式进行组合调整,大部分情况下能得到需要的方案,并不意味着架构设计很简单。
因此,设计最终的方案,并不容易,这个阶段容易犯错:
挑选出最终的方案也是一个很大的挑战,主要原因有:
实践中采取下面几种指导思想:
最合适的做法:360度环评,列出需要关注的质量属性点,然后分别从这些质量属性的维度去评估每个方案,再综合挑选适合当时情况的最优方案。
常见的方案质量属性点有:性能、可用性、硬件成本、项目投入、复杂度、安全性、可扩展性等。
在评估这些质量属性时,需要遵循合适简单原则,避免贪大求全,基本上某个质量属性能够满足一定时期内业务发展就可以了。考虑小概率事件时,需要遵循演化原则,避免过度设计一步到位。
完成方案的 360 度环评后,基于评估结果整理出 360 度环评表,一目了然地看到各个方案的优劣点。此时不要采取错误的选择法:
正确做法是按优选择,综合当前的业务发展情况、团队人员规模和技能、业务发展预测等因素,将质量属性按照优先级排序,首先挑选满足第一优先级的,如果方案都满足,那就再看第二优先级……以此类推。
详细方案设计就是将方案涉及的关键技术细节给确定下来,有一些技术点和备选方案类似。
详细设计方案阶段可能遇到的一种极端情况就是在详细设计阶段发现备选方案不可行,一般情况下主要的原因是备选方案设计时遗漏了某个关键技术点或者关键的质量属性。这种情况可以通过下面方式有效地避免: