程序员架构修炼之道:软件架构基本概念和思维

2022-09-19 15:40:05 浏览数 (1)

引子

互联网发展到今天,软件系统早就不是一个万行代码加上一台服务器这样的作坊玩具。BAT的服务器规模已经达到甚至超过百万级。传统企业向互联网的靠拢,势不可挡。

优秀的软件系统架构师就像大海航船舵手,指引着软件前进的方向,让企业在激烈的竞争中拔得头筹的同时,在企业内部尊享荣光。

只有兼具技术的深度和广度,并能克服人性弱点的资深IT从业者,才有机会成为一个优秀的架构师(高薪也是水到渠成的事情)。优秀的架构师是公不司的福音,反之就是公司的灾难。如果坏的种子已经埋下,那么"爆雷"是一定的,何时"爆"压反而不确定。

架构即人性,不切实际、追求繁杂、好大喜功的非理性的个人诉求,掺杂于甚至暗暗地主宰着整个理性的软件系统架构设计,这将置企业于危险境地!如果成为"人人喊打"的架构师, 岂不叹哉!

那么,怎么扎实地成为一名优秀的、人见人爱的架构师?

本文就先从软件架构最基本的概念和思维讲起。

软件架构:缘起

随着软件系统规模的增加,计算相关的算法和数据结构不再构成主要的设计问题;当系统由许多部分组成时,整个系统的组织,也就是所说的"软件架构",导致了一系列新的设计问题。

规模较大的软件系统会面临各种软件架构相关的问题,例如: 1、系统规模庞大,内部耦合严重,开发效率低。 2、系统耦合严重,牵一发动全身,后续修改和扩展困难。 3、系统逻辑复杂,容易出问题,出问题后很难排查和修复。

软件架构的出现有其历史必然性。

20世纪60年代第一次软件危机引出了"结构化编程",创造了"模块"概念; 20世纪80年代第二次软件危机引出了""面向对象编程",创造了"对象"概念; 到了20世纪90年代"软件架构"开始流行,创造了"组件"概念。

我们可以看到,"模块""对象""组件"本质上都是对达到一定规模的软件进行拆分,差别只是在于随着软件的复杂度不断增加,拆分的粒度越来越粗,拆分的角度越来越高。

《人月神话》中提到的IBM360大型系统,开发时间是1964年,那个时候结构化编程都还没有提出来,更不用说软件架构了。如果IBM360系统放不在20世纪90年代开发,不管是质量还是效率、成本,都会比1964年开始做要好得多,当然,这样我们可能就看不到《人月神话》了。

系统与子系统

系统泛指由一群有关联的个体组成,根据某种规则运作,能完成个别元件不能单独完成的工作的群体。 关于系统定义的关键词如下。

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

(2)规则:系统内的个体需要按照指定的规则运作,而不是单个个个体各自为政。规则规定了系统内个体分工和协作的方式。例如,汽车发动机负责产生动力,然后通过变速器和传动轴, 将动力输出到车轮上,从而驱动汽车前进。

(3)能力:系统能力与个体能力有本质的差别,系统能力不是是个体能力之和,而是产生了新的能力。例如,汽车能够载重前进,而发动机、变速器、传动轴、车轮本身都不具备这样的能力。

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

子系统也是由一群有关联的个体所组成的系统,多半是更大系统中的一部分。

模块与组件

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

【组件】 软件组件(Components)定义为自包含的、可编程的、可重用的、与语言无关的软件单元,软件组件可以很容易地被用于组装应用程序。

相信大部分人看完这两个定义还是一头雾水,看完也不知道至到底两者有什么区别。造成这种现象的根本原因是模块和组件都是系统的组成部分,只是从不同的角度拆分系统而已。

从逻辑的角度来拆分后得到的单元就是"模块";划分模块的主要目的是职责分离。

从物理的角度来拆分系统得到的单元就是"组件";划分组件的主要目的的是单元复用。

"组件"的英文单词 Component,对应中文的"零件"一词,"零件"更容易理解一些。 "零件"是一个物理的概念, 并且具备"独立且可替换"的特点。


组件化和模块化源于软件开发,现在越来越被更多地应用于UI设计当中。示意图如下。

在Angular 架构中,模块可以被认为是组件、指令、服务、管道、helpers 等的集合。 每个组件都可以使用在同一模块中声明的其他组件。要使用在其他模块中声明的组件,它们需要从该模块导出,并且该模块需要导入到我们需要该功能的模块中。 许多模块中的一个组合起来形成一个应用程序。

The module can be considered as a collection of components, directives, services, pipes, helpers, etc. Each component can use other components, which are declared in the same module. To use components declared in other modules, they need to be exported from that module and the module needs to be imported into our module where we need that functionality. One of many modules combines up to make an Application.

Arquitectura de Angular

框架与架构、结构

软件框架(Software Framework),通常指的是为了实现某个业界标准或完成特定基本任务的软件组件规范, 也指为了实现某个软件组件规范时,提供规范所要求之基础功能的软件产品。

框架定义的关键部分是:

(1)框架是组件规范。例如,MVC就是一种最常见的开发规范,类似的还有MVP、MVVM、 J2EE等框架。 (2)框架提供基础功能的产品。例如,SpringMVC是MVC的开发框架,除了满足MVC 的规范,Spring提供了很多基础功能来帮助我们实现功能,包括注解(@Controller等)、Spring Security、SpringJPA等很多基础功能。

架构的定义如下(Software Architecture) Software architecture refers to the fundamental structures of a software system, the discipline of creating such structures, and the documentation of these structures. 简单翻译一下:软件架构是指软件系统的"基础结构",创造过这些基础结构的准则,以及对 这些结构的描述。

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

框架的英文是Framework 。例如,SpringMVC 是"Web MVC Framework"。 架构的英文是Architecture。例如,Linux 操作系统的架构。

架构设计关键思维

架构设计的关键思维是判断和取舍,程序设计的关键思维是逻辑和实现。 很多程序员在转变为架构师后,很难一开始就意识到这个差异,还是按照写代码的方式去思考架构,这样会导致很多困惑。

架构设计原则

原则1: 合适原则

合适的架构优于业界领先的架构。 真正优秀的架构都是在企业当前人力、条件、业务等各种约束下设计出来的,能够合理地将资源整合在一起并发挥出最大功效,并且能够快速落地。

原则2:简单原则

简单的架构优于复杂的架构。 软件领域的复杂性体现在两方面:结构的复杂性、逻辑的复杂条性。

原则3:演化原则

架构需要随着业务的发展而不断演化。 对于建筑来说,永恒是主题;而对于软件来说,变化才是主是题。 软件架构设计类似于生物演化。

互联网软件架构模板

1、互联网标准技术架构模板

互联网软件架构模板如下图所示。

上面这张图基本上涵盖了互联网技术公司的大部分技术点,不同的公司只是在具体的技术实现上稍有差异,但不会跳出这个框架的范畴。

2、存储层

SQL:常用的有mysql,用于存储业务数据。互联网发展初期,各个业务一般都会独立运营mysql集群,但随着业务越来越多,mysql集群规模越来越大,那就有必要做成SQL平台。

NoSQL: 翻译为Not Only SQL,作为mysql的一种补充。Nosql一般本身就提供集群,且使用起来很方便,公司业务发展初期没有必要。一般Nosql集群的数量越来越多,那就有必要做成Nosql平台。

小文件:互联网中有很多小文件,比如商品图片,Facebook的图片。这类小文件具有数据小、数量巨大、访问大的特点。如果每个业务都去考虑小文件存储的话,就会出现重复造轮子现象,那就有必要做成小文件平台了。

大文件:互联网的大文件主要分为两类:一类是业务上的大数据,例如Youtube的视频、电影网站的电影;另一类是海量的日志数据,例如各种访问日志。实力雄厚的一些大公司会基于开源方案做成大数据平台。

3、开发层

开发框架:比如常见的Spring框架。 Web服务器:常见的有tomcat、jetty等。 容器:Docker可以极大降低运维成本,以及在实现动态扩容上非常方便。

4、服务层

配置中心:故名思义,配置中心就是集中管理各个系统的配置。 服务中心:解决跨系统依赖的配置和调度问题。比如有10个系统依赖A系统的x接口,此时A系统实现了一个y接口可以更好地支持x接口,那么如果直接更新10个系统依赖的配置将会很麻烦。 消息队列:支持系统解耦。

5、网络层

负载均衡:充当任务分配器的职责。 CDN:可以对一些常用文件进行就近缓存,来提高访问速度。 多机房:多机房的主要目的是备灾,当机房故障时可以快速地将业务切换到另外一个机房,这种切换操作允许一定时间的中断,比如10分钟,1个小时。 多中心:多中心的要求就更高了,要求同时对外提供服务,且业务能够自动在多中心之间切换,故障后不需人工干预或者很少的人工干预就能自动恢复。

6、用户层

用户管理:对各个系统的用户进行统一管理。 消息推送:根据不同途径分为短信、邮件、站内信、App推送。 存储云:实现是CDN 小文件存储。 图片云:实现也是CDN 小文件存储。为何不与存储云统一一套系统呢?这是因为图片业务的复杂性导致的。图片涉及的业务会更多,包括裁剪、压缩、美化、审核、水印等。

7、业务层

业务千差万别,各个互联网业务面对的主要问题是复杂度越来越高。此时就要用到拆和合的技术。拆即将一个大系统拆分为多个子系统,降低复杂度。当子系统越来越多,有可能就需要采用合的技术。

8、测试平台

测试平台的核心目的是提升测试效率。

9、运维平台

运维平台的核心职责分为四大块:配置、部署、监控、应急。

10、数据平台

数据平台的核心职责主要包含三部分:数据管理、数据分析和数据应用。

11、管理平台

管理平台的核心职责就是权限管理。

小结

  • NoSQL不是NoSQL,而是Not Only SQL,即NoSQL是SQL的衤不充。
  • NoSQL发展到一定规模后,一般都是走集群路线。
  • 在开源方案的基础上封装一个小文件存储平台并不是太难的事情。
  • 大数据存储和处理反而是最简单的,因为你别无选择,只能用这几个流行的开源方案。
  • 框架的选择,有一个总的原则:优选成熟的框架,避免盲目追逐新技术!
  • 互联网行业基本上都是"拿来主义",挑选一个流行的开源服务器即可
  • 配置中心主要为了解决系统数量增多后配置管理复杂和效率化低下的问题。
  • 服务中心目的是解决跨系统依赖的"配置"和"调度"问题。
  • 消息队列目的是为了实现跨系统异步通知。
  • DNS是最简单也是最常见的负载均衡方式,一般用来实现地理级别的均衡。
  • Nginx&LVS&F5用于同一地点内机器级别的负载均衡。
  • CDN是为了解决用户网络访问时的"最后一公里"效应,本质上是一种"以空间换时间"的加速策略。
  • 多机房设计最核心的设计因素就是如何处理时延带来的影响。
  • 多中心必须以多机房为前提,但从设计的角度来看,多中心相比多机房是本质上的飞越, 难度也高出一个等级。
  • 用户管理系统两个核心职责:单点登录和第三方授权登录。
  • 消息推送主要包含3个功能:设备管理(唯一标识、注册和注销)、连接管理和消息管理。
  • 除非BAT级别,一般不建议自己再重复造轮子了,直接买图片云和存储云服务可能是最快又最经济的方式。
  • 业务层降低复杂性最好的方式就是"拆",化整为零、分而治之,将整体复杂性分散到多个子业务或子系统里面去。
  • 运维平台核心的职责分为四大块:配置、部署、监控和应急。
  • 测试平台的核心目的是提升测试效率,从而提升产品质量,其设计关键就是自动化。
  • 数据平台的核心职责主要包括三部分:数据管理、数据分析和数据应用。
  • 管理平台的核心职责就是权限管理。

最后

技术成就梦想,坚持就能成功。

参考阅读

《从零开始学架构》

0 人点赞