<返回更多

到底该如何从零搭建一个新系统架构?

2023-12-14  京东云开发者  
加入收藏

一、前言

架构设计按照实施过程可分为工程架构,业务架构,部署架构等多个维度,一个好的系统架构标准应该具备可扩展、可维护、可靠性、安全性和高性能等特点。尽管这些特点大家都熟知,但在实际落地时,我们更为迫切的想知道实现这些要求的关键路径,以便在架构设计中融入这些特点。只有这样,才能确保系统能够适应未来的业务增长和交付效率。本文将重点围绕如何进行工程架构设计展开探讨。

二、价值为先

在方案出现歧义时,站在产品(商业)价值的视角审视方案并作出决策,这一点非常重要。

技术容易陷入的两个误区:

以上两类误区,很容易让研发对产品价值的理解形成偏差,容易对后续的技术迭代产生颠覆性的影响。站在产品(商业)价值维度,能够让协作各方站在平等的视角看问题,不仅能够容易达成共识,也能更好地为业务演进和技术迭代做好规划。

软件也是产品,在系统设计的时候,也会围绕着市场,组织,资源几个生产要素展开。

软件开发是围绕着投入产出比(ROI)展开的生产经营活动。可扩展,可维护,可靠性,安全性,高性能都是我们产品的特性,每一项特性都需要投入相当的成本来实现。

正所谓:“将军赶路,不追小兔”,总是有所取舍。我们不追求打造一个完美的复杂系统,但可以在限定的前提下追求卓越!

三、架构设计

架构模式描述了软件系统中各个组件之间的关系、职责和交互方式,从而为软件设计提供了一种规范和约束,进而提高软件生产效率。主要体现在以下两个方面:

1.工程框架

新系统往往从搭建项目的工程基础框架开始,包括目录结构、配置文件、代码模板等工程约束,主要用来规范项目结构、职责边界和代码风格,从而提高代码质量和可维护性。具体包括以下几个方面:

下面就最常用的分层架构和DDD架构给出一些实践思路。

1)分层架构

分层架构有多种形式,例如MVC、六边形架构等,它们是随着业务和技术的发展逐步演化而来的。

在互联网初期,由于计算机硬件性能差、网络速度慢、存储成本高等因素的限制,互联网产品的形态相对单一,只能实现简单的门户网站、BBS论坛等相对简单的产品。当时的技术架构没有分层的概念,主要使用ASP、JSP、php等脚本语言,在这些脚本文件中混合着编写htmlJAVAScript、css和SQL是很常见的。随着互联网技术的发展以及更多复杂业务的线上化诉求,动态脚本语言的劣势也逐渐显现,以JSP脚本语言为例:

为了解决上述问题,出现了各种框架,如Spring、Struts等。这些框架逐渐替代了JSP脚本语言,同时也提出了分层架构的概念。其中最典型的就是MVC(模型、视图和控制器)架构模式,其主要目的是解耦应用程序的不同部分,使其更易于维护和扩展。具体实现方式如下:

在多层架构中,视图层通常会使用基于模板的框架(如Thymeleaf、Freemarker、Velocity)或前后端分离的技术栈(如Vue.js、React)。这些技术的演进能够解决更加复杂的问题,如金融保险和电子商务等场景,但同时也会带来一些新的痛点:

为了提高产品交付效率并降低技术门槛,现代研发工作通常会拆分为多个岗位,包括前端开发、后端开发、质量测试、运维保障等。这些岗位需要协同工作,共同完成产品的研发任务。为了保证多业务线和多岗位之间的有序协作,有效管控过程风险,通常还会设有项目管理岗位。

MVC架构是对整个业务实现进行了关注点分离,但在更为复杂的大型项目中,特别是多人协作,多业务并行的场景下,MVC架构往往显得力不从心。此时需要对其进行更细粒度的拆分,以达到多业务线并行,而不会存在大的任务资源冲突问题。当然,不同的业务场景会有不同的拆分模式,最常见的拆分模式是多层架构模式,如下图:

到底该如何从零搭建一个新系统架构?

通过横向的分层架构我们实现了研发分工协作,所有的经验约束在这里得以体现。上图中,将控制层进行了二次细分。也可以按照实际应用场景进行重新调整。比如web模块能否依赖RPC模块就可以在POM文件中进行限定,如此一来,大家按照既有的工程约定,实施开发工作就可以了。

简单描述一下各个模块分层的作用:

传统的软件设计往往会导致各个组件之间紧密耦合,从而导致代码难以维护和扩展。六边形架构模式是分层模式的一种变体,通过将业务逻辑与框架、库等技术细节分离,从而实现了松耦合的设计,使得代码更易于维护和扩展。同时,六边形架构模式还可以帮助开发人员更好地实现单元测试和集成测试,从而提高软件质量。这在各种技术中台性质的业务场景下,非常有用,如下图:

到底该如何从零搭建一个新系统架构?

2)DDD架构

领域驱动设计(DDD)是一种软件开发方法,它以业务领域为中心,通过深入理解业务领域的知识,将业务逻辑封装在领域模型中,以此来实现更好的代码可维护性、可扩展性和可重用性。

到底该如何从零搭建一个新系统架构?

DDD属于松散的分层架构,每层职责和作用如下:

为什么DDD常年热度不减,但在我们实际的系统开发过程中,却很少有完全落地的项目呢?或者说MVC架构风格的系统很常见,但DDD架构风格的系统却很少见到。这得回归到DDD本身:它是解决复杂业务的一种软件开发方法论

如果将普通的CRUD业务系统也按照这套模式实现,反而会增加系统的复杂度。总体来说,DDD模式适用于以下几种场景:

为了评估业务的复杂程度,我们需要从多个方面进行考虑,业务流程、产品规则、数据结构以及需求变化频率等。一般情况下,采用这种架构模式需要慎重地评估,因为实施这种开发模式会面临以下几个挑战:

到底该如何从零搭建一个新系统架构?

总之,无论是团队协作模式、个人技术能力要求、业务共识的达成,各个方面都具有很大的挑战。但这并不意味着DDD在普通业务系统中,就没有用武之地。其解决复杂问题的思想仍然能够让我们受益。常用的工具框架,如CQRS框架、事件驱动架构和微服务框架,都有DDD的设计思想的影子。

以微服务架构为例,先看以下几个问题:

微服务拆分得太细,更多的服务会提高运营和管理难度;拆得太粗,功能耦合度高,在灵活性和扩展性方面又存在不足。所以这是一个比较棘手的问题。

确定业务和应用边界,是解决微服务困境的关键。而DDD就很好解决了业务边界的问题,它提供了一种划分业务领域范围的方法论。

微服务就是将应用程序拆分成多个子域,每个子域都以微服务的方式对外开放能力。微服务将复杂的业务流程和规则限定在领域范围内,即内部实现各自的领域模型和数据存储。从应用层看,这规范并统一了领域服务的实现方式,大大简化了代码逻辑,更好地管理了业务复杂性。

2.技术选型

工程架构的搭建除了基础框架外,还有一部分重要内容,就是各类基础中间件的选择,也就是我们常说的技术选型。下面结合示例跟大家展开讲述一下,关于技术选型需要关注的要点。

1)业务需求

了解业务需求,明确系统的功能、性能、安全以及未来的扩展需求。

示例:在系统模块划分的时候,有的系统会拆分成【WEB 】+ 【JSF微服务】两组应用进行分开部署,而有的系统只会部署一个【WEB】应用。这中间的判断标准是什么?拆出来【JSF微服务】的作用是什么?

综上所述:如果你的服务没有多端复用和资源运营的需求,就没有必要拆开部署,增加调用链路和机器资源的多倍投入。反之,进行服务拆分,益处则更大。

2)技术特性

评估不同技术的特性,包括可用性、性能、安全性、可扩展性、可维护性等方面。

示例:曾经遇到过一个系统,底层的存储层用的是db4o(一款开源的面向对象数据库),这个中间件拥有很多优点:

但这里还是不建议使用它,因为我们是分布式集群服务,这个数据库文件只能存储在单机上面,即存在单点故障问题,这是最致命的。有时候为了弥补类似的缺陷,你可能需要花费更多的成本。反过来说,如果是作为嵌入式数据库,应用在某些单片机上,它的这些优势就能够显现出来了。

3)社区支持

考虑技术的社区支持程度,包括是否有活跃的社区、是否有大量的文档和教程、是否有成熟的第三方库等。

示例:分布式调度框架中tbschedule算是开源比较早的了,但是开源之后很早就没有人维护了,如果在普通的业务中轻度使用,应用层做好监控,应该问题不大。但如果是作为基础中间件大范围的使用,显然它在调度过程可观测性方面,zk重连机制方面,调度异常自动恢复等方面急需升级优化。但现实是社区早就已经停止维护了,这就是一个比较麻烦的事情。

4)团队技能

根据团队的技能水平选择合适的技术,避免使用过于复杂或陌生的技术。这一点非常重要,否则后期的维护成本和迭代效率提升将成为一个大的难题。

示例:Cobol语言是上个世纪70年代,一种被广泛应用于金融行业的编程语言。它可以处理大量的数据和复杂的计算,而且有着高度的可靠性和安全性。直到2015年,它还运行着全球43%的银行系统和95%的ATM。

但在2023年3月份,日本就宣布,计划全部银行系统Cobol转JAVA语言。原因就是精通这门古老语言的技术人员非常稀缺,Cobol生态跟不上机器学习、云集成等新的发展了,整个系统的维护成本和迭代效率远远低于现代的JAVA生态体系。

5)成本效益

评估不同技术的成本效益,包括开发成本、运维成本、许可证费用等方面。

示例:当前大多数技术中间件都需要JDK8或以上版本的支持,因此在进行技术选型时,我们需要考虑合适的JDK版本。随着Spring Boot 3的发布,其默认支持的JDK版本为17,不再支持JDK8。这对于新系统而言,选择新版本似乎更为合适。而对于存量系统,则需要考虑新版本升级对于系统的改造成本以及带来收益是否匹配,而不是想当然的追求新技术。

6)风险评估

评估不同技术的风险,包括技术成熟度、安全漏洞、依赖关系等方面。

示例:Fastjson是开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。具有执行效率高的特点,应用范围广泛。现在,在进行技术选型的时候,就需要当心了,原因就是最近两年它频繁的爆出安全漏洞,依赖的应用需要跟着频繁的升级版本,修复漏洞。这还只是表象,更为深层次的原因是显现出的安全保障方面的不足,这在技术选型时,是不得不考虑的因素。

7)小结

在选择技术方案时,没必要对最新的,最热门的技术抱有执念,综合考虑业务需求和团队技能储备等多重因素,以选择最适合的方案为宜。当然,为了适应不断变化的业务需求和技术发展趋势,也要有及时进行技术评估和更新的意识。

四、规范共识

共识的重要性在于确保团队成员之间的沟通和理解达成一致。通过制定规范和流程,可以减少重复工作和错误,避免冲突和误解,这有利于提高研发效率和质量。

1.数据分层

1)对象转换

在分层架构中,各层之间存在相互依赖和引用,数据则通过参数对象进行传递。为了确保每一层内部结构的稳定性,我们需要进行防腐设计。这是实现高内聚,低耦合的关键。

示例:模型层一张表有20个字段,那么对应的PO对象就有20个属性。但终端显示层只要显示 10 个字段,请求处理层(Web)在获取数据时,没有必要把整个 PO 对象传递回来,这时我们就可以用只有这10个属性的DTO对象来传递结果到请求处理层,这样也不会暴露服务端表结构和一些敏感数据。

数据防腐设计常用的手段就是各层定义自己的数据结构,常见的有:

在实际的开发中,为了方便起见,不一定需要为每个服务层定义自己的数据对象,可以根据实际情况来灵活处理。例如,在某些简单的业务场景中,可以跳过DO层对象,直接将PO对象转换为VO对象。

2)对象复用

在迭代了许久的系统中,很容易碰到一个问题,就是一些对象的作用域失控了,其典型特征有:

对象的作用范围失控问题会导致系统整体的稳定性和迭代效率显著下降。这个问题通常是一个缓慢的积累过程,在不知不觉中形成。其弊端,往往在大的系统调整时集中爆发。

解决此类问题,可以从以下几个方面入手:

2.异常管理

1)捕获异常

异常捕获也容易走两种极端,一种是每个方法都try-catch,一个方法里有多组。另一种是整个链路都没有一个try-catch,处于裸奔的状态。那么到底该如何进行异常捕获呢?先看一下捕获异常的目的:

基于异常处理的目的,对应的处理策略也就清晰了:

总之,异常是需要捕获的,但是具体需要在哪里捕获,如何捕获,我们可以按照目的进行灵活处理。

2)处理异常

3.日志管理

4.监控管理

5.协作共识

1)HTTP服务请求都使用POST方式?

最近,我们的App遇到了一个问题。在某些情况下,服务调用返回了“HTTP 414 URI Too Long”的响应错误。这个问题的根本原因是Tomcat默认的get请求长度限制(包括请求行和请求头)超过了8192个字符。为了解决这个问题,有以下几种方案:

方案一,扩大Tomcat的容器限制,短期看起来可以,但是这是一个公共问题,要调整的应用容器可能需要成千上万台,而且治标不治本。

方案二,将所有GET请求方式,调整为同时支持POST请求方式,涉及到的应用又有成百上千个,工作量也不少。

方案三,精简Header请求参数,这个最为合理和稳妥,也是出现问题的本质原因,但是涉及到两个APP相互交互以及几十上百个部门协同梳理和改造,难度同样很大。

如果是你,该如何选择方案呢?

2)前端不做逻辑处理,只做数据渲染?

前端视角:由于APP发版,涉及到版本审核,用户下载更新等流程,一方面周期长,另一方用户可以拒绝升级。这就导致前端研发提出来,“前端不做业务逻辑处理,只做数据渲染”的口号。如果前端承接了业务逻辑处理,一方面,出了bug,想要修复的代价很高,如果用户不升级版本甚至无法修复。另一方面,前端承接了部分业务逻辑,将会和后端出现职责边界难以划分清楚的情况,给协作埋下了的隐患。

后端视角:一个默认背景图,一句提示文案,一个字体颜色……这些可预见的不会做出调整的数据,都需要我们来下发吗?提高了数据复杂度,增加了网络带宽。而且前端也有热更新技术,容易变化的复杂页面还可以通过H5来实现,怎么就不能做一些简单的业务逻辑了!

这又该如何进行方案选择呢?

3)小结

很多技术问题的解决方案并没有明显的偏向性,这取决于当时的环境和立场。例如,对于HTTP的GET请求参数超长问题,最合理的解决方案是精简Header参数,但这需要长期的努力,而在短期内很难实现。因此,在解决当前问题时,我们可以考虑其他两种方案。同样地,对于前端是否应该处理业务逻辑的问题,我们需要考虑到我们对APP的定位以及前后端各自基础能力的建设情况。好方案的评判标准应该是:能够低成本地解决当前问题,并且不引入新问题。

五、总结

本文详细介绍了搭建系统工程架构时需要关注的几个重要方面。基于产品的价值,做出决策,并从系统工程架构的演进、技术方案的选型、系统规范共识的达成等方面入手,对实施过程中的常见问题给出了解决思路。最后,借用《楞伽经》中的“标月指”作为结束语,与读者共勉:“如愚见指月,观指不观月。记着名字者,不见我真实。”

作者丨刘慧卿

来源丨公众号:京东云开发者(ID:JDT_Developers)

关键词:架构      点击(13)
声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多架构相关>>>