聊聊架构

余梦

文章

对于开发来说,我们经常听到”架构“这个词,对其一点都不陌生。我们也经常学习业界开源系统的架构,研究大公司相关系统或者开源中间件的架构实现(例如,微信、淘宝、京东等架构)虽然“架构”这个词很常见,但如果深究一下“架构”到底指什么,大部分人也许并不一定能够准确地回答,或者说脑海里涌现出很多东西却不知道如何去说、如何用简单的词汇提炼出架构的定义。很多时候一千个人心中可能有一千个哈姆雷特。架构这个东西也是一样,其涵盖的话题比较广泛,可能也有人觉得这个话题太空泛,本文也不会去谈如何设计一个好的架构、以及介绍当前主流互联网常见架构。因本人能力及对这块的理解有限,这篇文章中陈述的观点或者举例也许会有失偏颇,不当之处欢迎指出同我交流。考虑到这个话题比较广、篇幅等问题,我准备仅从下面两个方面简单聊聊这块内容:

  • 什么是架构?
  • 架构的目的是什么?

    我们都知道Linux 有架构,MySQL 有架构,JVM 也有架构,使用 Java 开发、MySQL 存储、跑在 Linux 上的业务系统也有架构,那我们应该关注哪个架构呢?


什么是架构?

比如点我达整个软件体系有架构,点我达APP的登录系统也有架构,点我达APP的订单、调度、数据分析等等都有各自的架构,当我们说起点我达的架构时,到底是在谈什么架构?

要想准确地回答这几个问题,关键在于梳理几个有关系而又相似的概念,包括:系统与子系统、模块与组件、框架与架构。

系统与子系统

我们先来看维基百科定义的“系统”。

系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。它的意思是“总体”“整体”或“联盟”。

我来提炼一下里面的关键内容:

关联:系统是由一群有关联的个体组成的,没有关联的个体堆在一起不能成为一个系统。例如,把一个发动机和一台 PC 放在一起不能称之为一个系统,把发动机、底盘、轮胎、车架组合起来才能成为一台汽车。

规则:系统内的个体需要按照指定的规则运作,而不是单个个体各自为政。规则规定了系统内个体分工和协作的方式。比如电脑,cpu负责运算、显卡负责渲染等,硬盘负责存储,它们都有一定的设计规范和作用。

能力:系统能力与个体能力有本质的差别,系统能力不是个体能力之和,而是产生了新的能力。比如计算机的各个模块具备的独特能力整合到一起,最终使得其实际能力呈现几何级增长,最终人类已经离不开计算机。

我们再来看子系统的定义。 子系统也是由一群有关联的个体所组成的系统,多半会是更大系统中的一部分。

其实子系统的定义和系统定义是一样的,只是观察的角度有差异,一个系统可能是另外一个更大系统的子系统。

按照这个定义,系统和子系统比较容易理解。我们以点我达为例来做一个分析。

点我达软件本身是一个系统,包含登录、支付、订单、调度、风控、消息、商家等子系统。

订单这个系统又包括订单查询、存储、分析等子系统。

订单查询子系统不再包含业务意义上的子系统,而是包括各个模块或者组件,这些模块或者组件本身也是另外一个维度上的系统。例如,MySQL、ElasticSearch,但不是业务子系统。

模块与组件

模块和组件两个概念在实际工作中很容易混淆,我们经常能够听到类似这样的说法:

MySQL 模块主要负责存储数据,而 ElasticSearch 模块主要负责数据搜索。

我们有上传组件、有审核组件。

造成这种现象的主要原因是,模块与组件的定义并不好理解,也不能很好地进行区分。我们来看看这两者在维基百科上的定义。

软件模块(Module)是一套一致而互相有紧密关连的软件组织。它分别包含了程序和数据结构两部分。现代软件开发往往利用模块作为合成的单位。模块的接口表达了由该模块提供的功能和调用它时所需的元素。模块是可能分开被编写的单位。这使它们可再用和允许人员同时协作、编写及研究不同的模块。

软件组件定义为自包含的、可编程的、可重用的、与语言无关的软件单元,软件组件可以很容易被用于组装应用程序中。模块和组件都是系统的组成部分,只是从不同的角度拆分系统而已。

从逻辑的角度来拆分系统后,得到的单元就是“模块”;从物理的角度来拆分系统后,得到的单元就是“组件”。划分模块的主要目的是职责分离;划分组件的主要目的是单元复用。举个简单的例子,比如以我们点我达APP为例,其包含的登录模块、订单模块、调度模块等,而其中实现骑手图片上传功能的组件、敏感词检测等组件、骑手相关消息、服务解耦的rocketmq等组件等。

框架与架构

框架是和架构比较相似的概念,且两者有较强的关联关系,所以在实际工作中,这两个概念有时我们容易分不清楚。参考维基百科上框架与架构的定义,我来解释两者的区别。

软件框架(software framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范,也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。 框架的功能类似于基础设施,与具体的软件应用无关,但是提供并实现最为基础的软件架构和体系。软件开发者通常依据特定的框架实现更为复杂的商业运用和业务逻辑。这样的软件应用可以在支持同一种框架的软件系统中运行。 简而言之,框架就是制定一套规范或者规则(思想),大家(程序员)在该规范或者规则(思想)下工作。或者说使用别人搭好的舞台来做编剧和表演。

提炼一下其中关键部分:

框架是组件规范:例如,MVC 就是一种最常见的开发规范,类似的还有 MVP、MVVM、J2EE 等框架。

框架提供基础功能的产品:例如,Spring MVC 是 MVC 的开发框架,除了满足 MVC 的规范,Spring 提供了很多基础功能来帮助我们实现功能,包括注解(@Controller 等)、Spring Security、Spring JPA 等很多基础功能。

软件架构指软件系统的“基础结构”,创造这些基础结构的准则,以及对这些结构的描述。

单纯从定义的角度来看,框架和架构的区别还是比较明显的,框架关注的是“规范”,架构关注的是“结构”。

虽然如此,在实际工作中我们却经常碰到一些似是而非的说法。例如,“我们的系统是 MVC 架构”“我们需要将 android app 重构为 MVP 架构”“我们的系统基于 SSH 框架开发”“我们是 SSH 的架构”“XX 系统是基于 Spring MVC 框架开发,标准的 MVC 架构”……

究竟什么说法是对的,什么说法是错的呢?

其实这些说法都是对的,造成这种现象的根本原因隐藏于架构的定义中,关键就是“基础结构”这个概念并没有明确说是从什么角度来分解的。采用不同的角度或者维度,可以将系统划分为不同的结构,偏重于物理的部署拓扑架构、偏重于业务的业务架构、偏重于技术的技术架构等。

我们来总结下上面所说的东西

  • 系统与子系统

系统是有一系列有关联按特定规则组成的个体,并且产出新的能力,而系统与子系统则是观察的角度不同。

  • 模块与组件

模块是从逻辑角度去看、而组件则是从物理角度去看待,它们都可以成为系统的一部分。

  • 框架与架构

框架是规范也是约束,可以理解为封闭的话题,定义好规则和规范让别人如何去使用,而架构是一种顶成结构,是一种开放式的话题,如何去组织架构、如何让架构具有拓展新、可用性、高效性、减少沟通错误成本。架构需要明确包含哪些个体,并且要使得这些个体按照某种规则运作,需要明确个体运作、协作的规则。

说到规则和规范有序运作等,突然想起来《聊聊架构》一书中作者对架构的定义。 1. 根据要解决的问题,对系统的边界进行界定。
2. 对目标系统按照某个原则进行切分,切分的原则,要便于不同的角色对切分的部分并行或者串行的展开工作,一般并行才能减少时间,并对这些切分出来的部分建立沟通机制。
3. 根据2,实际的这些部分之间能够进行有机的联系,合并封装成一个整体,完成目标系统的所有工作。
4. 架构就是为了解决人的问题

作者通过举了一个人类社会发展的例子,衍生出为 什么会有架构这个东西。作者举例最早的人类生活中,衣食住行等都是自己搞定,效率极其低下,能力也有限,后来的群居分工协作、各司其职导致生产力的提高,人类都在权威者制定的规则内行事,每个人做自己擅长的事情,不断进化完善,推动整个人类生产力的发展,也使得整个人类抵扣环境变化的能力大大加强,使得整个人类生活有条不紊的运作着,这一套社会体系和运作机制就类似架构。


架构设计的相关背景、目的

说到架构设计的目的,这里不得不简述下软件发展史。 最早的软件开发使用的机器语言,直接使用二进制0,1来表示机器可以识别的指令和数据。一堆0,1,写起来难,改起来难,读起来也难。接着到后来的汇编语言,最早的符号语言。用一些助记符代替机器指令的操作码。用符号地址或标号代替指令或操作数的地址。这个写起来读起来相对机器语言好很多,但是依然比较偏底层,程序员需要关注与底层硬件,不同应用的操作指令可能还不同,这样程序员依然很崩溃,写个程序换到不同机器上面可能就跑不起来,软件移植性、拓展性很差(当然这些都是事后诸葛亮了,回过头来,也不得不佩服那代程序员,现在是Write once, run anywhere)。后来出现了所谓的高级语言,比如lisp到现在依然活跃在一些领域,lisp这类语言的出现,让程序员不再过于关注底层细节以及硬件等,通过编译生成适合不同系统或者cpu指令的机器语言。高级语言的出现也使得软件规模及复杂度大大的提高,最后爆发了软件历史上的第一次软件危机。其中最著名的就是那个价值1个多亿美金的bug,水手一号火箭发射事件,还有著名畅销书《人月神话》的作者布鲁克斯带领团队研发的IBMOS/360操作系统中所犯的错误和经验,没有这个系统的研发经验,也不会有人月神话这本书的存在了。这些危机的爆发、间接说明了当前的落后的软件生产方式无法满足迅速增长的计算机软件需求,从而导致软件开发与维护过程中出现一系列严重的问题象。随着后来的面向对象语言的出现,软件危机似乎减少了一些,C++,JAVA,C#等面向对象编程语言大大减低了软件编写复杂度、但是遗憾的是,依然没能阻挡住再次爆发软件危机,这次的软件危机,主要是软甲生产力跟不上硬件和业务的发展。与上一次软件危机不同的是,上次危机主要是因为软件的逻辑变得非常复杂,这次的软件危机体现在软件的拓展变得非常复杂。系统规模越来越庞大,复杂度越来越高,内部耦合度越来越高,开发效率低,牵一发而动全身,修改拓展极为不利,所以计算机界后来出现了很多关于软件架构方面的各种思想和各种技术,比如这些年比较火的微服务架构、NOSQL等。各种前端到后端再到存储的技术不断更新换代,使得软件的适应发展能力大大加强。上面简述了为什么出现软件架构这个概率的背景,接下来简要谈谈架构设计的目的。

架构设计的目的

说到架构设计的目的之前,我先说下架构设计的常见误区,因为架构很重要,所以要做架构设计?这句话是句正确的废话,架构很重要,为何架构重要?不做系统架构,系统就跑步起来,其实不然,很多创业公司当初可能就有一个好点子,一伙人撸起(可能就一个人)袖子就干,几天就搞了个APP出来,这个时候几乎没啥架构可言。做了架构能使得程序开发效率提高吗?这个也不好说,当系统很小的时候,可能搞个MVC框架甚至JSP,PHP,Ruby on rails 的搞起来可能开发效率更高,这个时候搞架构设计可能会费时间和人力,这块如果投入编码,项目可能会更早上线。良好的架构能支撑业务的发展吗?这个也不一定,你即使知道微信的架构,你也难搞出来第二微信,当然很多时候,好的架构可以推动业务的发展、业务的发展可能反过来推动架构的不断完善从而间接推动自身的发展。架构无优劣,但是存在适合的架构用在合适的软件系统中。一个好的架构决策可能会给未来减少很多麻烦。可能有些同学也会为,不是每个系统都做架构设计吗?是这样的,如果只是知道这个系统要做架构设计,而不知道为什么要这样做,也会走入架构设计的怪圈,生搬硬套其它公司或者软件的架构,为了架构设计和架构设计,最终导致架构不伦不类,水土不服。如果你会说,架构设计的目的不是为了实现应用的高性能,高可用,可拓展性么?恭喜你,你已经有了一定的架构设计经验和基础了。对于很多互联网应用来说,特别是有一定流量和用户量的应用来说,做架构设计很多时候就是为了解决上述几个问题的。通过前面讲述的软件发展史中的软件危机事件我们可以知道,现在的应用,无论是体量、规模,复杂度都大大提高了,而且再不断提供,对于架构来说,其实是在不断和这些复杂度做抗争,架构设计的目的很多时候就是为了应对软件系统复杂度而提出来的一个解决方案,为了解决软件复杂度带来的问题。(这个定义或许不一定准确,如果有更好的提炼,可以私下找我交流),其实除解决复杂度带来的问题,架构设计得目的也是为了解决利益相关者(产品、开发、用户等)的关注点或者痛点。

知道了架构设计的目的,我们就可以针对性的分析一个系统,而不是盲目套搬别人的架构。比如现在流行的docker,为了解决资源重用、动态分配、环境搭建快捷等设计的,你的应用中复杂度是否在这里?在比如流行的NOSQL,你的数据是否是结构化的或者是业务关联性很强、丢失成本极小、对事务是否敏感的等。一会追求流行的技术,只会舍本逐末。我以一个员工考勤管理系统为例,来分析下这个系统的复杂度在哪里。

性能:一个公司员工一般不会太多,员工考勤每天基本就上班、下班打卡的时候会访问系统、访问系统评率极低。性能这块并不复杂、一般用mysql存储足够。web服务器用nginx即可。 可拓展性: 考勤一般来说功能相对问题,不需要做什么额为拓展,可拓展性也不复杂。

高可用性: 对于公司来说,考勤系统宕机并不会带来多大的损失,也不用考虑做负载均衡、更不用考虑其他如异地多活的方案了。可以简单的搞个备份节点以防止服务不可用。 关于考勤数据丢失,其实来说也并不是很严重的问题,但是手动修复也比较麻烦,而且如果数据丢失,也会对员工年终工时考核等产生一些影响,这个可以考虑增加一个备份数据,主从同步即可。 安全性:考虑一般考勤系统设计薪资、员工信息等,数据还是相对较敏感,安全性这块可以考虑下。

通过如上分析,我们发现这个系统复杂性主要体现在数据存储和信息安全上面。 可能有些考勤系统有其他很多功能,这里只是举个例子,大家可以了结合自己使用过的考勤系统来分析下这个问题。

这里来做个总结: 1. 架构是为了应对软件复杂度而提出的一个解决防范。
2. 架构即(重要)决策
3. 需求驱动架构,架起分析与设计实现的桥梁。
4. 脱离业务谈架构就是耍流氓。

很多时候,架构就是一种决策和取舍,适合自身业务的架构即是非常好的架构,关键在于权衡和取舍。这其中涉及到软件的生命周期、时间、开发成本、业务发展、团队协作和管理等各个环节。最后,还是那句话,脱离了产品和业务谈架构就是耍流氓,任何架构,最终都是为人和产品服务的。

参考:

维基百科、《聊聊架构》、《人月神话》