写在前面
最近遇到个技术面试,面试官多次在架构设计
中强调系统qps
、在线用户数量
、接口响应时间
、页面渲染时间
、用户体验度
,在我看来这还没到系统架构设计
的门槛中。于是我想归纳整理个人多年来的系统架构设计
思想和实践的经验,作为技术阶段里程碑的一个标志。
一、何为架构设计
系统架构设计
细分起来有很多,比如物理架构
、逻辑架构
、开发架构
、运行架构
、业务架构
等等,我们通常说的架构实际上是逻辑架构
或业务架构
。
大致描述起来就是:根据一个或多个业务主程(业务线),提炼出基本的业务场景,用经验预估技术瓶颈和难点。围绕思想为驱、技术落地
为目标做一个针对业务场景贴合且对技术实现宽泛的方案。
不要觉得根据业务线出发就是在做业务架构
,系统的存在有个基本的IO
属性,它是个抽象概念,意思是系统本身必然有内需或者外需,其次才能形成一个系统。这与微服务设计思想
是不谋而合的。所以本身业务架构
是可以同时表达其他架构意思的,只不过表达的比较隐晦。所以在大部分时候都需要在不同视角下进行多视角架构设计,让其他参与者能够理解架构意图的全面信息。
系统架构设计
不是一个ppt
方案就完事了,它是一个系统开发过程指南,要保证执行团队根据指南能落地,符合预期要求。它是一个实际落地的事情,不是靠嘴和文档输出就可以的。
劝诫指南
- 如果只会一种开发语言,不要碰
架构设计
,做解决方案
就好了。掌握多种开发语言意味着接触了多种生态下的思想和技术实现,具备了多角度考虑问题的思维,在设计的时候不容易进入思维死胡同。捉襟见肘的设计只是徒增笑料。注意我要表达的并不是技术不行,而是思维问题,不够开放的思维容易陷进去。 - 如果不会运维,更不要碰
架构设计
,写代码就好了。不明白自己做的架构设计
和代码在什么情况下运行的,这就像厨子只管做菜不管好不好吃。这样的厨子谁遇到都会骂的。
1、没有最佳的架构设计
,只有不断优化完善的架构设计
架构设计
本身是根据现有掌握的信息进行设计的,尽管考虑了一些可能的情况,但是随着系统运行的数据量增加、业务扩展(二开)、系统内部优化缺失、部署环境变更等问题,逐渐会形成负面结果。这就是设计中必然会出现的问题。好消息是当下的互联网快餐
模式,还没等系统依靠时间累积出这些问题就已经被马放南山了。
不要想着一套高大上的方案通吃某些业务场景,更加不要有心里认为最ok
的设计方案。什么设计都扛不住时间的沉淀。
看看大多数sass
系统做法,它是提炼业务线后高度抽象,做成多租户且数据隔离形成一个系统,这种模式对sass
系统来说是好的,对sass
租户来说未必就是有效的了,因为sass
只解决了租户的主要问题,很多无用功能或缺失功能确实不尽人意的,这就是大锅饭模式。可以说大多数sass
系统是一个好的业务抽象
(本来sass
就是业务名词),但是绝不是一个好的设计。
当然我说的sass
系统问题在很多系统中已经不存在了。根据sass
业务主流程,做一个sass
微内核,其他所有功能做成热插拔组件
进行系统集成
即可,但是这样带来了新的问题,那就是增加了系统的复杂度
,出bug
的几率变高了。这就引出了架构设计
中最常见的一个二八定律
,即实际要做20%
的事情,但是却要额外做80%
的事情来保证前面的20%
。
除此之外,在架构设计
时最多人在乎的是系统性能
,这就是我说面试遇到的那个面试官在意的东西。这些指标我统称为并发压力测试相关指标
。
针对系统性能
我有个截然不同的做法(具体请参考第二节二、基本的架构设计过程
):
- 第一阶段,基础实现:根据基本指标(
系统io
、并发数
、数据库io
、硬件配置
)结合业务主流程做一个基本的架构设计
落地 - 第二阶段,系统优化:根据第一阶段的产物进行标定的
并发压力测试相关指标
测试,寻找系统瓶颈来优化
有人会问了,为什么不直接根据并发压力测试相关指标
整一个符合指标的架构设计
呢?我可以武断的说,有这种想法的大部分都是没做过架构的。如果你经历了非常多类似的系统设计
,比如你经常做电商系统设计
,非常熟悉业务场景和技术栈了,确实可以一次性到位整一个符合指标的架构设计
,因为那只是方案的粘贴复制,非常简单了。但是如果你没有吃透(可能你觉得吃透了)某个行业或者业务场景,来进行这种一次性到位的设计,十有八九是要踩坑反工的,原因很简单。你在盲目自信,并且拿着公司的项目当小白鼠实验。我亲身经历很多次系统设计
已经完成了,到编码实现的过程中还在一直与产品或者客户确认需求、更改主流程的。
关于系统性能
,这里要提到cap定律
,即一个分布式系统
最多只能同时满足一致性(Consistency)
、可用性(Availability)
和分区容错性(Partition tolerance)
这三项中的两项。当我们对架构设计
做了n
次考虑之后,最后一定要套一下cap定律
。如果发现设计并不遵循它,那么恭喜你,加班返工吧。
具备灵性的墨菲定律
我不想提及,有这个意识的关注下就好,我很看重第一次的整体印象产生的直觉,墨菲定律
已经快被我具象化了。
综述:需要认识到架构设计
并不是一蹴而就的,更加没有一劳永逸的解法。对于提炼业务转化成设计,需要强大的内功。更应该谨记二八定律
和cap定律
。
2、需要架构设计
的根本目的就是要确定一个大方向和范围,所以架构设计
并不是一个IT
专属名词,它是一个通用性词语
我做架构设计
时使用最频繁的设计思想
是DDD
,先说明:DDD
并不是最佳的架构设计思想
,但是它是一件思维利器,能够让你快速抽象
理解业务并与技术和团队进行拆分贴合。我有幸从2016
开始接触并感受了它的魅力,深受其影响,并坚持实践DDD
多年。可能有人不知道DDD
是什么,DDD
全称是Domain-Driven Design领域驱动设计
,它是一套综合软件系统分析和设计的面向对象建模方法。这种方法论对开发、架构都有非常大的帮助,甚至对你的逻辑能力都有一定提升。(后面我将花大篇幅讲DDD
,它是我做架构的本命法宝)
在软件开发中,架构设计
不是必须的,应该说大部分时候的软件开发都不需要架构设计
。无架构设计
时,可以像写shell
或python
脚本那样(注意:我并不是要表达shell
或python
无法架构设计
),专注过程,一撸到尾。好处是开发快,坏处是代码没有抽象分离,导致维护和扩展变得困难,并且这种方式也不是适合团队协同,无法有效利用团队资源。
在架构设计
时,要避免过度设计
,不要去额外考虑过多的问题,当触发了二八定律
时一定要警醒,全盘审视是否触发了过度设计
,过度设计
的代价是系统复杂度
上升,会导致研发、维护、运维部署
成本上升,综合体现就是前期开发周期
变长了,不可控的bug
变多了,代码复杂起来了,维护变得麻烦了,需要更多服务器资源了,需要写更多运维脚本和策略来保障系统了。
3、架构设计时需要的思维方向(根据重要程度)在此列举
- 遵从的设计思想,例如
DDD
- 确认部署环境和使用环境/场景
- 确认系统
io
流转,是否涉及外部系统,或者外部方式交互。尝试考虑解耦
、外部风险隔离
- 是否对系统整体表现有预估参考数值,例如
并发压力测试相关指标
等 - 是否存在业务贴合必要的技术方案(可能导致
系统设计
会向其有一定的考虑倾斜) - 根据经验预估系统瓶颈和注意点,需要用一些前瞻性的眼光预估系统的整体情况,比如
1年后
、3年后
、5年后
等。若当前技术无法有效支撑未来的情况,应提前制定未来可能出现的应对方案,避免进入死胡同 - 技术选型的范围固定,根据经验考虑此设计的技术落地使用哪些技术方向,同时考虑当前技术团队的落地执行是否能承接(技术掌握、开发周期等)
- 是否存在开源、收费、授权等相关的技术使用风险或额外成本
- 是否有阶段性计划,可以分阶段进行设计,提高
系统设计
的专注程度,有利于现阶段的设计,同时保留后续的扩展能力
二、基本的架构设计过程
1、技术选型
- 选定开发语言,可以是多种开发语言,根据当前系统或业务的必要性、便捷性考虑,从社区生态活跃度、技术热度、
IT
市场人员掌握范围确定(避免了万一不好招人,架构师得亲自上,自己挖的坑自己填,哈哈哈) - 确定开发语言在系统中负责的部分,确保不会有无效的技术重叠
- 确定使用哪些
lib
或者开发框架
来作为基本脚手架,也需要关注其最新的社区生态或官网发布信息,确保用好、避坑 - 确定使用哪些
中间件
,按重要顺序,考虑必要性
、稳定性
、扩展性
、可维护性
。同时要注意它是否会成为限制系统性能的瓶颈。 - 要考虑
系统重量
,尽量不要为系统增重
或增加实现复杂度
- 从技术视角审视系统的
技术衔接
,确定技术能够有效支撑
。技术搭配很重要,考验的是技术积累的广度和深度,以及经验 - 根据部署和使用环境,优先考虑热度高的技术,当然核心目标是降低复杂度和成本。大部分的生产事故来自于后期的运维方案(并不是运维的人有问题,而是前期的运维方案有问题,随着系统的长时间运行,没有考虑周全的问题被爆出来了)
2、demo
预演准备
对于系统设计
中的技术选型
结合部分解决方案
进行实际的demo
实现,并测试是否符合设计预期。排除设计和选型上的大风险。在这个阶段根据demo
结果可能需要对系统设计
或技术选型
进行微调。比如需要做性能测试时,可以使用此demo
做一部分,起到一些参考作用。
后面可以基于此demo
作为开发脚手架和参考案例,对技术团队的开发和测试起到一定的支撑作用
3、技术团队培训/管理
做好的架构设计
即将要在技术团队
中执行了,这时候就需要换个角度了,需要用管理角度看待接下来的事情。
并且在不清楚团队情况之前,不要秀技术水平。最终期望的结果是让团队成员能够协同工作,并且能培养几个贯彻这个架构设计
的人,他们会影响其他人。
团队分为2
种,能打仗的和不能打仗的。不要慌,进入团队看两眼,马上这个分类就会清晰起来。
先说不能打仗的团队特征:
- 整体技术水平落后,技术好的都跑路了
- 正在开发的项目使用的技术旧(可能是3年之前或更早的技术)
- 不愿意学习新技术
- 无效加班多/卷
- 团队缺乏活力
我带过几个这种团队,深有感触。这实际上不是技术问题,是管理问题。
调整管理方式(轻量化管理加激励制度)能解决大部分问题。技术落后需要进行技术改革(阵仗大,动作慢。别把现有系统搞崩了反应不过来),主打一个恩威并施。
遇到能打仗的团队也不着急烧高香,这种团队通常有刺头,除了自己爸妈谁都不服的那种,导致要引入新技术或者管理方式会形成直接阻碍。
具体团队特征:
- 缺少技术扛大旗的岗位
- 项目技术用的比较新,但是用法可能有些偏颇
- 缺乏完整的团队管理/协同
- 有刺头
- 卷不卷随意(没人管的着),可能到点就跑,也可能半夜还在公司
- 项目立项到研发过度很快,有可能是需求对接研发
我也带过几个这种团队,同样深有感触。这实际也不是技术问题,是管理问题。这种状况更加麻烦,处理的大方针是想办法收服刺头,不然啥也干不了。团队存在这种人,但是又没在这个岗位上。细品就懂了。所以他就是管理团队、推广技术最好的大将。他要的就是公司重视他,尊重他,甚至给他搞点小福利更好。一句话就是,给予超过他岗位的尊重和重视就行,慢慢收。
以上事情完成之后,团队基本上已经达到了指哪打哪的表象。这很重要,不然提出个东西老有人出来跟杠,工作无法展开了。
注意:上述事情都是管理方面,与技术无关。我说这些的目的仅仅是为了让团队能够配合执行接下来的架构设计
培训事项
- 设计目标,一定要先说目标,很多人都是先有目标(告诉他要干什么)才能继续听下去
- 设计思想,浅浅带过即可,有兴趣的人会私下再找你问
- 技术选型,分不同岗位(后端、前端、移动端、嵌入式端、运维等等)着重讲解
- 开发规约,非常重要,接口规范、文档规范、代码规范、测试规范、运维规范必须要团队成员全部知晓
- 技术分享,如果方案中引入的技术团队中会的人不多或者完全不会,一定要进行多次技术分享。同时也能带动团队气氛
后面就是开发、测试、部署、交付。不展开说了。
4、关于DDD
设计思想
需要澄清一下,DDD
不等于微服务
。DDD
是一套方法论,是思想上的指导。微服务
是一套设计理论,也是系统设计上的一种思想。
这两者实际上没有关联,但是通常我们做微服务
设计时,会使用DDD
来做业务上的拆分。(注意:我要表达的意思是微服务
和DDD
这两种思想是可以单一存在,也可以同时存在的)
使用DDD
的好坏:
使用DDD
的好处如下:
- 不管业务如何扩展,都不会导致推倒重来
- 清晰业务边界,分工明确,有利于技术针对性和开发人员工作安排
- 良好的编码习惯,就算不写注释,只需要看
接口声明
和数据模型
就知道开发人员的实现与设计有没有偏差 - 部署直观,部署只需要一个个
run
即可,不需要考虑顺序和特殊性,更加简单。 - 不需要的服务不会
run
起来,部署资源利用率变得更高 - 显著提升整个系统的
io
能力
使用DDD
的坏处如下:
- 前期开发速度比
贫血模式
略慢一些(约慢20%
) - 团队需要培训,接纳这种思想
使用DDD
的基本要素:
DDD
设计分为以下几个阶段:
- 在业务中寻找
领域
- 在
领域
中寻找值对象
- 在业务中寻找
聚合根
看着非常简单,实际上它是一个经验积累过程,需要注意以下几点:
- 在业务中
领域
拆的过多/过少 - 在业务中
聚合根
过多/过少
当领域
过多时,需要特别注意,是否拆的过细,容易导致编码量增加,开发周期变长,开发人员投入过大。并且业务合并过于繁琐,也会给部署带来更高的复杂度。这一点往往最考验对DDD
的领悟。
当领域
过少时,要考虑拆的是否不够细,可能会因为后续的业务扩展导致当前领域
变成畸形,那时候只能继续拆分再来重构领域
了。这就是技术债。
当聚合根
过多时,意味着这个业务复杂度可能非常高,需要千万小心,一定要复盘所有的DDD
设计阶段。确认设计无误。
当聚合根
过少或者没有时,也需要复盘一下领域
,看看是否有拆得不够细的情况。通常来说聚合根
过少或者没有时表示这个系统业务非常简单。
具体的DDD
怎么做和它的名词解释,推荐去看《领域驱动设计——软件核心复杂性应对之道》这本书。
三、总结
大学时代,老师问我职业规划是什么,我说我想做架构师
,毕业工作后是一名开发,但是我不安于只做开发,于是坚持不打游戏不午睡,时间都拿来学习技术,有差不多6
年时间都是每天学习和写代码到凌晨。学到很多东西之后开始寻找创业公司去实践所学,后面发现技术是可以了,但是没人愿意用我的技术方案,于是我开始学管理,学沟通待人。很幸运在从业第四年我就达到了曾经的目标,但是当我在这个位置上时,我发现自己只是摸到了架构师
的门槛,远没有登堂入室,于是又开始了新一轮的自我强化。
我一直认为不是技术主导,思维才是主导。知道自己缺什么很重要,坚持去补足缺点更加重要。
通篇没有一个技术性名词,这是我非常在意的,我努力在表达上去技术化
,争取做到技术于内而发醒于外
。
评论区