一、怎么理解架构?
假如给你一个项目开发,你会怎么开始它?对于这个问题,我想很多猿友们都应该经历过吧。很多时候,我们会直接开干,让自己快速的进入 coding 状态。
然而一旦遇上稍微有点规模,比如涉及到多个业务功能的开发,那大概率会在开发过程中经常的怀疑自己,甚至产生推倒重来的想法;又或者眼看就要交付了,只能将错就错,修修补补。最后,一个让人揪心的系统又诞生了。
说到底,还是太草率了,如果我们能提前对项目进行梳理,将涉及到的产品形态、业务功能、技术方案不断的进行提炼总结,那还会这样吗?
这也是为什么我们需要对项目进行架构设计的原因了,因为我们需要捋清楚项目中的重点、难点,让整个开发流程清晰明了。最起码,在编写代码时是有思路的。
在经历过很多项目后,我们会发现有一些经验是可以复用的,架构设计是有路子可寻的。只要我们将对应的阶段总结输出,最后重新整合成一个解决方案,那我们的架构设计也就出来了。
软件系统就像一个分散、无序的世界,而架构的核心就在于将它梳理成一个有规范、有边界、有层级的系统,让系统的复杂性是可控的,并且尽可能的简单化、流程化、自动化。
架构设计
二、该怎么做?
个人相信,很多事情都有它自己的流程步骤,只要我们对它逐步化解,总是能完成目标的。架构设计也是如此,将它拆分为几个阶段,在每个阶段进行成果输出,那么我们也能完成一次属于自己的架构设计了!
阶段一:认识业务
程序存在的意义都是为了解决某一问题,如果我们连目标都不知道,那又何来开发呢?所以,第一个阶段就是进行业务的认识。至于怎么更好的认识业务,可以从下面这个流程去着手:
- 业务是在什么场景下开始执行的?
- 当前这个场景的数据来源有哪些?
- 分支流程有哪些?
- 流程涉及到的角色是谁?
- 场景执行后输出的数据要有哪些?
例如,酒店预订系统的业务分析,梳理成如下图:
业务分析
在进行业务分析的过程中,我们肯定会产生一系列的问题,此时我们可以在上面的流程步骤里标注对应的问题集合,当问题收集完毕后,就是不断的和对应的负责人沟通确定了。
对于业务的不断确定,除了便于后面的架构展开外,还有一点重要的就是去界定当前业务的价值点。因为事情总有主次优先,我们应该将精力花在价值高的业务上。
阶段二:数据定义
业务流程的确定帮我们把想做什么给整理了出来,而在执行过程中所涉及的数据管理则有待完善。
数据管理包括了数据模型的设计和数据的存储操作。如果项目对数据的运用比较高的话,还会涉及数据的分析与安全操作。这些我们暂时先不考虑。只看最基础的,跟业务相关的数据建模。
当前经常接触到的数据建模是 ER 模型。在进行 ER 建模前,我们可以先从大的方向来看待数据定义:
- 概念定义:数据实体的基本单元,一般采用行业术语命名。
- 逻辑抽象:在概念实体上进一步延展,分析业务行为属性。
- 归纳:将数据概念进行分类或分组。
在这几面进行着手思考后,我们在心底就有一个大概的方向了。接下来就是进行具体的 ER 建模了。而这也是我们这一阶段需要输出的设计。
ER 模型通过实体-关系-属性来紧贴现实世界里的结构概念,它有属于它的一套构建过程。通常用矩形框代表实体,用连接相关实体的菱形框表示关系,用椭圆形或圆角矩形表示实体的属性,并用直线把实体其属性连接起来。
ER图
阶段三:应用划分
在这一阶段是系统架构的重要规划,我们将以上帝视角确定各个模块的定义、边界、关联,为后续的技术方案提供指导蓝图。应用划分的最终目的就在于让应用程序能以组合的方式去协调系统,确保功能隔离又能保持良好的依赖关系。
在进行应用划分时,我们往往可以借助分层的手段来简化整个过程。首先,在业务流程输出的基础上对其进行领域划分,将逻辑紧密连接的业务聚合在一起,形成一个个的子系统。子系统之间如果有关联的,需要明确定义出它们关联的上下文。
除了站在业务的角度上进行应用划分,有时我们还需要进行非业务功能的提取。比如在这些子系统之上,抽象出基础的应用服务或组件,以便可重用。
应用划分
此阶段我们需要输出的是从外到内的多层应用架构,而且是定义明确,界限分明的应用组合。
阶段四:技术落地
当把所有准备工作都了解清楚后,是时候进行具体的技术开发了。在这个阶段会对架构设计者要求比较高,主要取决于架构者的眼界和开发经验。比如技术选型、生态建设等。
项目的技术落地应该以合适、演化为原则,例如:单体 -> 分层 -> 集群 -> 分布式等,尽量避免在开发过程中使用陌生或不成熟的技术组件。
这里简单列举下当前所接触过的开发技术,并不一定适用于所有的项目,但大多数时候我们都会考虑过:
- 运维管理:Docker 或 k8s 容器化、jenkins 自动构建部署
- 负载均衡:Nginx、HAproxy
- 网关:Kong、ApiSix、Openresty
- 服务注册发现:Nacos、Consul
- 配置中心:Apollo、Disconf
- 调用链追踪:Zipkin、Jaeger
- 监控中心:prometheus
- 日志中心:elasticsearch + logstash + kafka
- 服务通信:HTTP、RPC
- 缓存:CDN、Redis、Memcached
- 消息队列:RabbitMQ、Rocketmq、NSQ
三、归纳
现在,架构设计已经一步步的解析出来了,剩下的就是 coding 了。在 coding 之前,开发人员应该根据架构蓝图把各个实施点过一遍。涉及到基础组件建设的,要先搭设好;涉及到具体业务服务的,要定义好接口。尽量分工明确,各司其职,同步进行,有效快速的推进项目实施。
架构也不是一确定了就不再改动,再牛逼的人也会有考虑不周的地方;所以好的架构肯定是演化式的,最好是简单易理解的,这样对于参与人能够迅速投入战斗状态。
架构过程中需要我们识别业务复杂度和技术复杂度。对于业务复杂度我们要不断的去确定流程,确定目标,确定边界;而技术复杂度,在于它的高性能、高可用、可拓展性、安全性、可执行程度。在设计过程中,需要清晰的辨别这些复杂情况,这样考虑的才能全面。