欢迎点击下方👇🏻 关注 我 ,记得 星标 哟~
文末有惊喜** ~**
大家好,我是汤师爷~
今天聊聊应用架构设计。
应用架构就像整个SaaS系统的骨架,决定了系统的整体结构和各个应用之间的关系。
接下来,我们会深入探讨应用架构的三个核心要素:应用服务、应用结构和应用交互。这些要素共同构成了一个体系化的SaaS应用架构。通常,应用架构设计包括以下几个步骤:
- • 识别应用服务:根据业务架构,找出关键的应用服务。
- • 划分应用结构:设计应用结构,明确各部分的职责。
- • 设计应用交互:规划各个应用结构之间如何交互和集成。
应用服务的定义
应用服务将相关的业务对象及其操作进行封装。每个应用服务需要具有明确的边界,将相关功能组合在一起,同时隐藏内部实现细节。一般来说,应将可能同时变化的功能和数据组织在一起,而将相对独立变化的部分分开。
这种设计方法来自SOA(面向服务的架构)和微服务架构的兴起。把系统分成多个独立的服务后,整个系统就更容易维护、扩展和复用。
应用服务如何划分?
应用服务在应用架构中非常重要,它把系统的核心功能“打包”起来,提供给外部的业务流程使用,可以看作是SaaS系统对外的“门面”。用户或者其他系统通过调用应用服务提供的服务接口,来实现特定的业务功能。那么,如何设计应用服务呢?
1、对齐业务能力,划分粒度适中的应用服务,职责单一。
在划分应用服务粒度时,可以参考领域驱动设计(DDD)中的"限界上下文"概念。业务对象类似于限界上下文中的聚合根,是应用服务的核心。
通常情况下,我们会基于业务能力来划分应用服务,每个业务能力都对应一到多个独立的应用服务,每个应用服务用于支撑特定的业务能力。
将应用服务与业务能力对齐,确保系统功能紧密贴合业务需求,避免技术实现与业务逻辑脱节。
从应用服务的视角来看,可以按抽象层级划分为业务域、业务子域和应用服务,它们分别对应L1业务能力、L2业务能力和末级业务能力的粒度。
如果一个应用服务支撑了过多的业务能力,那么需要评估其内部是否关联了过多的业务对象。在这种情况下,可以考虑将多个业务对象进行分组,从而将该应用服务拆分为多个更小、更专注的服务。
2、围绕业务对象,提供具体的业务功能,避免包含不相关的功能。
从外部来看,应用服务通常有明确的业务含义,主要围绕一个或一组密切相关的业务对象进行操作。
围绕业务对象设计服务,可确保服务内部功能高度相关,提升内聚性,让服务的边界更清晰,有利于业务团队和技术团队的协作与沟通。
例如,线上商城系统的”交易服务”专注于订单确认、下单和支付等功能,不应处理用户认证、商品推荐等其他业务。
5.2.3 示例:订单履约应用服务划分
我们以订单履约能力为例,它是零售企业业务能力地图中的 L2 级别的业务能力。
订单履约能力可以细分为多个末级业务能力:ToC的履约服务、订单派单、订单管理、拣货管理、发货管理和逆向履约。
基于这些末级业务能力,我们就可以设计出对应的应用服务、服务模块和功能。
应用结构的定义
在完成应用服务的设计后,我们需要规划应用服务的内部结构。
应用结构设计是把应用服务转化为具体实现的关键步骤。它描述了应用服务内部的层次结构和组织关系,决定了系统的模块化程度,以及后续开发和维护的难度。
应用结构的抽象层次
在设计应用结构时,我们通常会把系统分成不同的层次,比如系统级、应用级、模块级和代码级。
这种分层方式有助于我们在不同层面处理复杂问题,确保系统结构清晰、易于维护。
- • **系统级:**关注各个系统的整体布局和管理方式,比如系统之间的关系,以及它们如何协同工作。
- • **应用级:**聚焦每个应用的整体架构,包括应用与其他应用的交互方式,以及它们在整个系统中的角色。
- • **模块级:**对应用内部进行更细致的划分,涉及代码的模块化设计、数据和状态的管理等。通过合理的模块划分,可以提高代码的可维护性和可重用性,减少重复工作。
- • **代码级:**关注代码本身的结构和实现方式,这一层的设计直接影响到代码的质量和实现细节。
抽象层次的存在,是为了帮我们更有效地管理系统的复杂性。
这种分层方法让开发团队能在不同层次上专注于特定的问题,更好地应对大型软件系统的挑战。具体来说有以下作用:
1、分解复杂度
如果把所有的业务细节、技术细节都混在一起,整个系统就会变得难以理解、维护和扩展。通过设置不同的抽象层次,我们可以把系统的复杂性分解到各个层次,每个层次只需关注特定的领域和职责。
例如,全局架构师主要负责把握整体系统架构和演进方向,需要重点关注系统级的设计。领域架构师则专注于特定业务领域的应用架构设计,主要关注应用级的规划。而一线开发工程师则需要深入具体实现细节,主要关注模块级的开发和代码级的编写。
这种分层处理方式让开发人员在专注于系统某一部分时,不用过多关注其他部分的细节,大大简化了系统的设计和开发过程。
2、团队协作边界清晰
在大型项目中,通常会有多个团队同时开发。如果系统没有明确的边界,各团队之间很容易产生冲突和重复劳动。通过清晰的抽象层次划分,不同团队可以专注于系统的不同层次或模块,互不干扰。
3、扩展性强
随着业务需求的变化,系统往往需要不断地进行扩展和升级。如果系统的架构设计没有合理的抽象层次,扩展和升级就会变得非常困难,甚至可能需要对系统进行全面重构。
而在有清晰的抽象层次的系统中,变更通常只需聚焦在特定的层次上进行,而不会影响整个系统。比如,一次业务改动只影响模块级别,我们就可以在不改变系统整体架构的情况下,替换或新增某个模块,满足新的业务需求即可。
应用结构如何划分?
前面我们讨论了应用结构的抽象层次,那么如何将应用服务逐步转化为实际可落地的应用结构呢?
基于应用服务的划分,我们可以进一步细化应用结构,更好地组织和管理系统功能。这个过程涉及到多个层次的设计方法:
-
- 系统和子系统的划分要和业务域、业务子域的粒度保持一致。这样,我们就能更好地把业务需求映射到技术实现上。
-
- 一个或多个相关的应用服务,可以组合成一个可独立部署的应用。
-
- 在应用内部,可以进一步分层。比如,参考领域驱动设计(DDD)的分层方法,可以分为用户接口层、应用层、领域层和基础设施层。
-
- 应用的各个层级内部,还可以细分为多个模块,每个模块又包含多个代码单元。
应用的划分原则
应用是一个可独立部署和运行的软件单元。它是将应用服务转化为实际可执行程序的载体,具有以下特点:
- • 独立部署:应用可以独立安装、启动和运行,不依赖于其他应用的部署状态。
- • 资源隔离:每个应用都有自己独立的运行环境、内存空间和计算资源。
- • 服务承载:一个应用可以承载一个或多个相关的应用服务,为这些服务提供运行环境。
- • 版本管理:应用可以独立进行版本升级和回滚,便于持续集成和部署。
那么,具体来说,我们该怎么划分应用的边界呢?可以参考以下几点原则:
1、服务划分原则
应用划分的关键是看应用服务的边界。
应用服务的核心目标是帮助企业实现业务能力,所以它们需要和业务能力保持一致。而应用是实际的物理部署单元,应用服务最终要部署在特定的应用上。
因此,一个或多个相关的应用服务,可以组合成一个可独立部署的应用。
应用服务可以单独部署,也可以多个服务合并部署。那么,如何判断何时选择独立部署,何时选择合并部署呢?这需要参考技术层面的成本和稳定性风险等因素。
2、技术划分原则
在业务初期,尽量从单体应用开始,避免过早地把应用拆得太细,这样可以减少分布式事务和数据不一致等问题,并可以降低技术部署的成本。然而,即使在单体应用内部,也需要将应用服务划分为界限分明的模块,这样能确保开发人员在正确的模块中编写和组织代码。
其次,要避免应用之间出现循环依赖或双向依赖。在应用单元内部,可以进一步分层,始终保持不同层级之间的单向依赖关系,高层级可以依赖低层级,同层级之间不应互相依赖。
只有当真正遇到技术上的痛点,比如规模、性能、安全等问题时,才考虑拆分应用。如果不拆分会严重影响业务的稳定性,那就应该拆分。但不要为了拆分而拆分,因为每次拆分都会增加系统的复杂度。
由于业务场景或技术条件的限制,系统中可能同时使用Go、Java或大数据架构等不同技术。对于这些技术异构的功能,可以考虑按照技术边界进行拆分。
3、组织规模原则
单个应用的项目团队规模,通常建议保持在10~12人左右。
因为团队成员越多,协作关系就会成倍增加,可能导致信息传递变慢或者失真。一个10到12人的团队,可以确保大家的沟通更直接、更高效,减少信息障碍。
同时,小团队通常更容易管理,项目经理或者团队领导能更好地了解每个成员的工作状态和需求,进行更有效的协调和支持。小团队有助于建立更紧密的合作关系,成员之间更容易培养出默契,提升整体工作效率和项目质量。
示例:新零售SaaS整体应用结构设计
让我们以新零售SaaS为例,探讨其整体应用结构。在深入分析之前,我们先来了解传统零售企业的IT架构现状。
1、零售企业常见的IT架构
为了有效管理团队、明确部门职责和优化协作流程,零售企业通常会引入办公自动化(OA)、人力资源管理(HRM)和企业资源规划(ERP)等系统。
企业会设立信息技术部门来负责系统改造、新系统实施,并确保系统、服务器和网络的稳定运行。中小型连锁企业一般会使用以下IT系统。
- • O2O云店系统:集成线上线下销售渠道,实现全渠道销售和场景化消费。
- • 线上商城系统:构建和运营企业电商平台,提升电商竞争力。
- • POS系统:处理门店收银、结算和财务,实现销售数据整合。
- • 促销系统:策划和执行营销活动,提高销售转化率。
- • 客户运营系统:管理会员资料和权益,开展精准营销,增强客户忠诚度。
- • 商品管理系统:统一管理商品信息和定价,优化商品运营流程。
- • 仓储管理系统:管理货物出入库和盘点,提高仓储效率。
- • 采购系统:管理供应商关系和采购流程,优化采购计划。
- • 配送系统:管理产品配送和物流,保证准时送达。
- • 客服系统:提供工单处理和智能客服等全方位服务。
- • 中央库存系统:统一管理企业库存,提供预警分析和优化建议。
- • 订单履约系统:规范订单处理流程,确保订单顺利完成。
- • 基础数据系统:整合企业核心数据,优化数据质量和运营效率。
- • 财务管理系统:处理财务核算和成本管理,提供财务分析报表。
- • 人力资源管理系统:管理招聘、考勤、绩效和培训等人事工作。
- • 数据分析系统:整合数据分析和可视化功能,支持数据驱动决策。
2、新零售SaaS整体应用结构划分
我们可以将新零售SaaS系统的核心部分归纳为:
- • 面向消费者的销售系统:包括O2O云店系统、线上商城系统、POS系统、促销系统。
- • 客户精准营销相关系统:包括客户运营系统、数据分析系统、客服系统。
- • 核心依赖系统:包括基础数据系统、商品管理系统、中央库存系统、订单履约系统等。
对于仓储管理、配送、采购、财务管理和人力资源管理等成熟的IT系统,选择直接集成市场现有的解决方案。新零售SaaS的整体应用结构设计包含以下几个层次:
- • 用户端:负责向用户提供系统的使用界面和交互体验,包括小程序、H5、移动端、PC客户端等。
- • 解决方案:通过组合一系列的SaaS产品和服务,满足客户不同的业务场景需求。
- • 业务系统:提供各个业务领域的核心系统,包括O2O云店系统、线上商城系统、POS系统、促销系统、订单履约系统、客户运营系统等。
- • 共享服务:为业务系统提供通用的领域服务,包括账户中心、商品中心、订单中心、促销中心等。
- • 技术平台:负责系统的技术实现落地,提供各类通用技术组件支撑。
- • 基础设施:为整个系统提供运行环境和支撑,包括服务器、数据库、存储、网络、容器等。
5.5.2 示例:订单履约系统的应用结构划分
上一节展示了新零售SaaS的全局应用结构划分。我们以订单履约系统为例,展示单个领域系统的应用结构划分。订单履约系统的应用结构分为以下几个层次,各层的职责为:
- • 用户接口层:直接与用户交互的层级,负责展示信息和响应用户操作。
- • 应用层:定义软件的功能,负责处理用户请求,协调领域层的能力完成任务,并返回结果。
- • 领域层:承载核心业务逻辑,负责处理业务概念、状态流转和规则,提供可复用的服务能力。
- • 基础设施层:提供技术支撑,包括数据库、缓存、消息中间件、搜索引擎、分布式通信、日志和网关等基础组件。
5.2.1 应用交互的定义
应用交互是指不同应用之间怎么“沟通”和“交流”。在一个复杂的系统中,各个应用不是孤立存在的,它们需要互相配合,才能完成更复杂的业务功能。应用交互的设计,就是为了确保这些系统和组件能够顺畅地“对话”,一起实现系统的整体目标。
应用交互的方式有很多种,包括同步调用、异步消息通信等,每种方式都有特定的应用场景和优缺点。通过合理的交互设计,系统中的各个部分能够高效协作,降低耦合度,增强系统的灵活性。
同时,好的交互设计还能显著提升系统的性能和容错能力,即使在高并发、大流量的情况下,也能保持稳定运行。
应用服务的上下游
应用服务承载了系统对外提供的核心业务功能。虽然应用服务可以独立发展和演化,但它们必须相互交互,才能实现系统整体目标。
那么,如何设计应用服务之间的交互呢?首先,我们需要了解服务的上下游概念。
1、服务上下游的概念
服务的上下游关系可以通过DDD(领域驱动设计)的建模方法来定义,主要涉及两个关键概念:"限界上下文"(bounded context)和"上下文映射"(context mapping)。限界上下文帮助我们划分不同的业务边界,而上下文映射则定义了这些边界之间如何协作。
上下游表示上下文之间的映射关系,下游需要了解上游的领域知识来实现业务,而上游不需要了解下游。换句话说,上游服务不需要关心下游服务的存在,但下游服务的实现却依赖于上游服务提供的能力。
这个概念初看可能有些抽象,确实让许多人在第一次接触时感到困惑。让我们通过线上商城的几个应用服务来具体说明:
- • 用户服务:管理用户的账户信息,包括注册、登录、认证、个人资料等,处理用户的权限和角色管理。
- • 商品服务:管理商品的基本信息,包括名称、描述、价格、图片、分类等,提供商品的查询、筛选和浏览功能。
- • 库存服务:管理商品的库存数量,处理库存的预占、扣减和回补操作。
- • 交易服务:处理订单的创建、修改、取消和查询,管理订单的状态和生命周期。
- • 支付服务:处理支付事务,支持多种支付方式,管理支付状态。
- • 履约服务:处理订单的履约,包括拣货、包装、发货等,管理物流信息和配送状态。
如图所示,为各个服务的上下游关系,这种关系的设计基于业务流程和数据流向。
在整个上下游关系中,商品服务和用户服务位于最上游。作为基础服务,它们为整个系统提供核心的业务数据支撑,其他所有服务都依赖这些基础数据来实现各自的业务功能。
同时,交易服务与库存服务之间也存在明确的依赖关系。在这个关系中,交易服务是下游,因为在整个交易流程中,特别是下单、支付环节,交易服务需要依赖库存服务进行库存预占和扣减操作。
最后,在与履约服务的交互中,交易服务扮演上游角色。它将已支付的订单信息传递给履约服务,这些订单数据驱动着后续的履约流程,包括订单分派、物流配送等环节。
2、为什么要区分上下游?
区分上下游关系的核心目标是为了解耦。"解耦"这个词相信大家都不陌生,但它的含义往往过于抽象和模糊。在这里,我们探讨一下解耦到底指什么。
耦合是指两个或多个结构之间的相互作用。在软件开发中,可以理解为不同模块、系统或团队之间的相互依赖和影响。
随着业务需求越来越复杂,单个团队很难独立实现所有功能。因此,解耦的目的并不是完全消除耦合,而是减少不必要的依赖关系。
前面提到,上游服务不需要关心下游服务的存在,但下游服务的实现却依赖上游服务提供的能力。
因此,当下游服务团队在迭代新功能时,无需评估是否影响上游服务,因为基于明确的上下游关系,可以快速判断不会影响上游服务,只需评估是否影响自己的下游服务。
比如,交易服务的功能发生变更时,只需通知履约服务团队,评估是否会影响到他们,上游服务团队则无需知晓。这种方式能大大减少影响面的评估工作,提高团队协作效率。
相反,如果上下游关系混乱,存在各种循环依赖,那么任何一个服务的改动都难以准确评估影响面。此时,就需要召集所有服务的团队,逐一评估是否有影响。
在实际项目中,如果每次会议都需要召集大量人员才能评估影响面,这样的协作效率显然太低。
3、上下游关系的核心使用场景
在软件研发过程中,上下游关系在很多关键场景中都发挥着重要作用:
- • 明确服务之间的依赖关系:上下游关系帮助开发者清晰理解服务间的依赖,防止循环依赖,减少服务故障引发连锁反应的风险。
- • 评估影响范围:当上游服务发生变更时,可以清晰地识别会受影响的下游服务,并制定应对方案。
- • 指导团队协作:上下游关系有助于明确各团队的职责和协作范围。上游团队需要考虑下游团队的需求,提供稳定的接口和服务,下游团队则需要适应上游的变化。
应用服务的交互方式
应用服务之间的交互方式有很多,最主要的就是同步调用和异步消息。
1、同步调用
同步调用是一种通信方式,客户端向被服务端发送请求,然后等待服务端处理完成并返回结果。
在此期间,客户端会被“阻塞住”,直到收到服务端的响应。这种方式要求双方都在线,而且调用方在等待响应时,没法做别的事。在微服务架构中,常用的同步调用协议包括 HTTP、REST API、Dubbo、Thrift、gRPC 和 SOAP 等。
同步调用适用于下游服务需要立刻从上游服务获取数据的场景。这种方式简单直接,但需要处理服务之间的可用性问题。举个例子,用户下单时,订单服务需要同步调用商品服务,获取商品的最新价格和商品信息,确保下单逻辑能正常执行。
通常来说,上游服务不应同步调用下游服务。如果上游服务同步调用下游服务,会导致上游需要了解下游的领域知识,违背DDD上下游的设计原则,加深系统耦合,并增加团队协作复杂性。
此外,这种做法还可能引发级联故障,降低系统可靠性。如果上下游直接互相调用,那下游服务发生故障时,也将直接影响上游服务的可用性,导致整个系统都瘫痪。
2、异步消息
异步消息是另一种通信方式,消息的生产者和消费者通过消息队列或消息中间件进行通信。
发送者发完消息就可继续其他操作,不用等接收者处理完。消息被发送到消息队列后,接收者从队列中异步获取并处理。这样一来,发送者和接收者的处理时间就不耦合了,双方可以各自独立运行,提高了系统的灵活性和可扩展性。
在微服务架构中,异步消息通常通过消息中间件实现,比如 RabbitMQ、Kafka、RocketMQ 等。
异步消息适用于上游服务向下游服务发布事件或通知的场景,能有效解耦服务,提高系统的弹性和可靠性。下游服务也可以通过异步消息向上游服务反馈信息,实现双向通信。
比如,用户提交订单后,订单服务调用支付服务发起支付。用户完成支付后,支付服务发布一个“支付成功”的消息,订单服务接收到消息后,更新订单状态。
3、其他交互方式
除了同步调用和异步消息这两种主要的交互方式外,在实际系统中还存在一些其他的交互方式。这些方式各有特点,在特定场景下可能会派上用场,但也都有其局限性。
1)共享数据库方式
多个服务访问同一个数据库,直接读取或写入数据。在微服务架构中,通常不建议采用共享数据库的方式,因为这违反了服务自治的原则,增加了服务之间的耦合度,修改数据库表结构可能会影响多个业务团队,这大大增加了评估影响面的难度。
2)文件传输
服务之间通过共享文件系统、FTP或其他文件传输协议来交换数据。这种方式主要用于处理大量历史数据或批量数据的场景,例如日终对账、数据备份和统计分析等。由于涉及文件读写和传输操作,实时性较差,因此不适合对响应时间要求高的业务场景。
3)服务总线(ESB)
使用统一的通信总线来连接不同的服务和系统,服务之间不直接通信,而是通过总线来“中转”,适用于需要集成多种异构系统和服务的大型企业级系统。但是,这种方式引入了额外的架构层,增加了系统的复杂性,所有服务都耦合到总线上,存在单点故障的风险。
对了,基于我10多年的架构经验,精心整理了一套 超全的架构学习路线 。帮你少走弯路,早日成为 百万年薪 架构师!
需要的同学,加我微信,备注【 架构资料 】,免费获取~
·············· END ··············
你好,我是汤师爷,南京大学硕士,曾就职于华为、阿里,创业公司CTO,现大厂资深架构师,Qcon、IAS、A2M大会特邀讲师。日常分享AI编程,系统架构,AI工具,欢迎围观。
往期文章精选:
1.业务分析
一文搞懂SaaS业务架构:价值流、业务能力、业务流程、业务对象、组织架构
2.系统规划
3.概念模型
4.应用分层
欢迎把文章 分享 至朋友圈
点赞、在看是对我最大的支持
↘↘↘
