对于想要入门架构的小白来说,我们必须要了解以下问题:

  • 什么是架构
  • 架构的目的
  • 架构的复杂度来源
  • 做架构需要具备的能力

什么是架构

软件架构指软件系统的顶层结构

系统:泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。比如微信就是一个系统
顶层结构:系统可分为系统与子系统,差别在于系统可能是另外一个大系统的子系统。比如微信系统中还包含聊天、登录、支付、朋友圈等子系统。所以顶层结构更好地来将它们区分开来,避免架构层次混乱

不包括的方面:需求的详尽分析(所有功能需要在设计架构前已经分析清楚,架构师当然需要甄别需求,但软件架构需要基于清晰的需求)、系统中的实现细节(如聊天系统中使用哪种消息加密方式,这是详细设计中需要做的但不应该包含在顶层结构的设计,除非实现方式比较特殊直接影响到架构)

架构的目的

根据业务识别出软件系统复杂度来源从而解决复杂度带来的问题

架构产生的直接原因是为了实现一个系统来完成业务需求,那么必定会带来一定的系统复杂度,从而衍生出一系列问题。我们做架构,就是需要提前将这些问题预想到并给出解决方案,这样才算一个合格的架构师

举一个学生管理系统的例子,需求是登录、注册、成绩管理、课程管理。我们一拿到这个需求的时候,首先需要识别出复杂度在哪里,然后给出一些解决方案

  • 性能:一个学校的学生不多,大约1万左右,使用频率也不高,所以QPS非常低,一台主机作为Web服务器,一套MySQL数据库就可以了
  • 高可用:如果Web服务器挂了几个小时,也无关痛痒,大不了重启服务器就能恢复,但数据库里的数据没了就非常严重了,所以必须考虑MySQL主备方案
  • 扩展性:几乎不用考虑扩展性,现在的架构起码能抗住两倍于现在的流量
  • 成本:只需要几台服务器
  • 安全:由于学生的信息属于学生的隐私,所以需要对我们的入口进行控制,比如需要账号密码管理系统,密码需要加密存储,数据库需要使用复杂用户名密码以及IP白名单

所以该系统复杂度主要体现在存储的可靠性上,多使用一台服务器作为备库是最简单的解决方案,至于是否还需要另外的数据备份方式依情况而定

这个例子就是我们作为架构师的入门案例,我们通过对学生管理系统的架构进行设计,分析出了复杂度在哪里,并给与了解决方案,达到了架构的目的,但现实情况往往比较复杂,问题更多,我们需要一个更加系统的分析流程来进行架构

复杂度来源

想要对问题进行分析,那么首先需要知道问题产生的原因,现在我们来了解一下架构的复杂度来源

高性能

  • 一方面是单机复杂度,就是在单台计算机内部实现高性能

除开硬件,操作系统就是发挥出高性能的关键,进程与线程则是操作系统中性能影响最大的方面,比如我们为了追求高性能,需要考虑多线程、多进程、进程间通信、多线程并发,还需要结合实际场景选择合适的方案

  • 另一方面是集群复杂度,就是在多台计算机协作的情况下实现高性能

集群作为任务分配的使用方式:能够突破单台服务器的极限性能,通过增加更多的服务器来满足性能要求。比如一台Nginx服务器加几百台Web服务器确实可以达到一定程度的高性能服务,但不能充分发挥出服务器集群的极限性能,因为服务器之间除了分担流量,毫无配合

任务分配的意思是指每台机器都可以处理完整的业务任务,不同的任务分配到不同的机器上执行。一个任务分配器(Nginx、LVS)加上几个业务服务器就能完成这种架构,但详细来讲,任务分配器还需要进行一些配置(跟业务服务器的连接方式、动态更新配置、选择合适的分配算法)

当流量变大,一个任务分配器也是不够用的,需要一个任务分配集群,然后在任务分配集群前加上DNS轮询进行请求分配;业务服务器的数量也会大大增加,增加了管理的难度


集群作为任务分解的使用方式:由于业务变得复杂起来,一个请求可能会有很多不同的事情需要后台处理,比如消耗CPU的计算,消耗网络和磁盘IO的数据传输,所以将不同的功能对应到不同子系统中,然后针对不同业务的不同性能需求,分别进行独立的优化。这样不需要对整个系统进行修改,仅仅影响某个业务。这其实就是将单体应用拆分成若干小服务的做法,跟微服务类似,小服务也不能太多,否则会因为服务之间的消息传递大大降低性能

高可用

高可用指的是系统无中断地执行其功能的能力,代表系统的可用性程度无中断是高可用性的难点所在,冗余是做到无中断的方法,简单说就是多弄几台服务器当做备份,所以复杂度因此而生。

  • 计算高可用

计算指的是业务逻辑处理,无论在哪台服务器上计算都是一样的结果,所以这里的复杂度与【高性能】中的集群复杂度是类似的,不再赘述

  • 存储高可用

与计算高可用的区别在于,复杂度除开在集群的配置,还在平衡数据的一致性和可用性以及减少数据不一致对业务造成的影响上。分布式系统中数据的不一致很可能导致业务不可用或者用户体验极差

比如假设用户的数据存在北京机房,用户存入了 1 万块钱,然后他查询的时候被路由到了上海机房,北京机房的数据没有同步到上海机房,用户会发现他的余额并没有增加 1 万块。但最后发现是传输延迟的问题,给用户带来了不好的体验。根据CAP理论,我们只能在一致性和可用性之间做平衡,这就需要在我们做实际业务的时候进行取舍

那么如何进行取舍?一台数据库服务器肯定可以保证数据的一致性,但可用性太低,所以数据库或缓存都有主备架构、集群架构方案来提升可用性。一旦状态异常,还会延伸到高可用状态决策,比如主节点宕机,从节点应该以何种策略处理?是根据策略担任主节点?还是集群变成不可用状态?这些问题会在本系列的后续【高可用】相关文章中详细解释

扩展性

扩展性指的是系统为了应对将来需求变化而提供的一种扩展能力,当有新的需求出现时,系统不需要或者仅需要少量修改就可以支持,无须整个系统重构或者重建

设计具备良好可扩展性的系统,有以下两个基本条件,也是复杂度所在:

  • 预测变化

我们在开发的过程中,需求是永远做不完的,如果架构一开始设计的没有扩展性,日后的需求涉及到的变更会很难应用到原有的系统上,成本会很高,程序员心里也不爽(改来改去),产品经理也不爽(做得那么慢),老板也不爽(那么多人就只能干这么点事)。所以作为架构师,必须得提前预测将来可能的变化,预测也有一个度,不能过分预测导致无法落地,也不能不预测导致没有扩展性

例如,架构师准备设计一个简单的后台管理系统,当架构师考虑用 MySQL 存储数据时,是否要考虑后续需要用 Oracle 来存储?或者系统可能的访问量是多少?日后需要支持到多少?需要全球性的部署吗?作为架构师需要考虑到一段时间后的变化但不需要考虑到十年后的变化

所以扩展性的一个复杂度在于预测变化,预测哪些方面,预测到哪种程度是预测变化的复杂所在,业界也不会有一个通用的标准来约束,只能靠自己的经验做出判断

  • 应对变化

在做到预测变化的基础上,还需要找到合适的方案来应对变化

找到方案的思路大体是识别出变化层稳定层,然后设计出它们之间的接口,这也是扩展性的另一个复杂度所在

以业务逻辑连接数据库为例,业务逻辑是稳定层,因为业务逻辑应该只关注逻辑的实现,不应该操心连接哪种数据库。多种不同的数据库是变化层,因为数据库可能增加一类或者减少一类。至于它们之间的连接接口,使用连接配置文件和对应的数据库连接包就可以做到。但复杂的是,当新数据库添加进来时,要保证对所有数据库的操作都是一致的,比如SQL语句很可能在不同的数据库中无法直接执行,需要做某些数据库的语法转换

成本、安全、规模

  • 低成本

和造桥游戏Poly Bridge一样,以最低成本完成稳定的架构才能得到更高的Rank(评价),也是对自己的架构能力的进一步挑战。小项目不需要太多机器,但架构师一般负责的都不会是太小的项目,如果你的架构能省下很多机器(金钱),你的奖金就能发的更多,自己也会非常有成就感

所以,低成本的复杂度就是在成本与架构中平衡技术创新达到低成本目标。技术创新对于一般公司难度太高,但像NoSQL、Redis、Hadoop就是通过技术革新带来的低成本收益。所以通常是寻找低成本与高性能、高可用之间的平衡

  • 安全

安全非常重要,在涉及到交易相关的业务就更不用说,但安全是非常大的一个方面,大公司一般会有一个专门的安全小组对公司内部进行安全审计。安全问题一旦爆发,公司的业务影响还是小事,公众对公司的信任危机才是大事

功能安全:像SQL注入、CSRF、XSS、HTTPS、权限控制、密码管理,以及各种系统、软件的漏洞。黑客可以通过这些软件功能上的破绽拿到网站的服务器管理权限。

架构安全:传统的架构安全主要依靠防火墙,防火墙最基本的功能就是隔离网络,但由于性能问题不适用于互联网高并发场景,尤其难以防范一大堆肉鸡对你网站的DDoS攻击,导致正常业务无法访问,只能依靠运营商或者云服务商强大的带宽和流量清洗的能力,较少自己来设计和实现

  • 规模

这里的规模指的是功能数据的规模,除开高性能、高可用,当业务越来越复杂,时间越过越久,人员更替越来越多,功能和数据就会越来越丰富

功能上,即使使用的是服务拆分的思路去实现,服务也会越拆越多,若干个服务之间会存在更加复杂的调用链,从而引起质变:访问速度不可接受、调试变得困难

数据上,如果数据在MySQL中越来越多,查询速度会变慢,如果到时候才考虑到分表,根据哪个字段分?增删改查的逻辑需要大改特改;添加索引会花很久,过程中直接导致服务不可用;备份时间太长

能力的要求

以上是在技术方面需要考虑到的架构问题,但架构师并不是只需要技术就能无敌于天下的,这是100offer提供的【架构师该具备什么能力才能成为一家公司中的「灵魂人物」】的调查图

可以看出,设计能力(根据产品宗旨和目标,分析清楚产品定位以及产品业务,再整合利用现有的技术领域,找出最佳方案,实现产品概念)与技术能力(架构师必须是全栈工程师,对前后端运维都需要有所了解,对不同功能的实现多种方案有深入的理解)是架构师的核心能力,占的比重较大

本系列文章也将着重对这两方面能力进行深入,但还有很多其他能力也必不可少,因为从接收需求到实施架构的过程中会有非常多的流程,比如讨论需求、讨论方案、讲解方案、总结汇报、日程安排。沟通表达、总结、管理能力显得格外重要

这些软技能都不是一朝一夕能够学得的,需要大量的主动练习才能有所长进,同时本人推荐《软技能 代码之外的生存指南》可以作为学习指南参考

总结

以上内容可以说让我们对架构有了一个清晰的认识,也明确了我们需要努力的方向,本系列的后续文章就是将这些方向细化,分别给出一些做架构的具体处理方案,还有架构设计的一些套路。但更重要的是本系列仅仅只能作为入门,即使全部理解也无法成为架构师,还需要亲身实战,即使没有机会,也可以在 https://github.com/donnemartin/system-design-primer 上寻找锻炼机会

参考

https://time.geekbang.org/column/intro/81
https://www.zhihu.com/question/40520339

号外号外

最近在总结一些针对Java面试相关的知识点,感兴趣的朋友可以一起维护~
地址:https://github.com/xbox1994/2018-Java-Interview