使用DDD(领域驱动设计)重构支付系统
01前言
领域驱动设计(DDD)和微服务架构是两种在架构设计领域广泛应用的方法。它们都旨在通过从业务视角分离应用系统的复杂度来提高系统响应力。
这篇文章将详细介绍DDD的基本概念、名词解释、架构模式以及如何对现有系统进行重构。
02 什么是DDD(领域驱动设计)
DDD是一种架构设计方法,强调从业务出发合理划分领域边界,调整现有架构并优化代码,以实现演进式架构。
其核心理念是通过领域拆分解决复杂业务问题,控制和管理业务复杂性。
定义领域
领域指特定的问题域,用来限定业务边界。领域模型是对业务领域中概念、规则和行为的抽象,通常由领域专家和开发人员共同创建。
例如,交易领域限制所有交易相关业务的范畴。
实际上,平台支付系统并不仅仅包含支付领域,相对的,它实际上是一个交易系统,支付只是交易的一部分,以下我们统一使用交易xxx来称呼。
领域模型
领域模型反映了业务领域中的实体、值对象、聚合、工厂和存储库等,它是领域专家和开发人员共同构建的一个抽象模型,用来描述和解决业务问题。
限界上下文
限界上下文定义了业务领域中的边界,确保在该边界内使用统一的术语和规则。不同限界上下文之间可以使用相同的术语表达不同的业务含义,从而实现独立的业务逻辑和数据模型。
例子
在交易业务中,订单和支付是两个紧密联系但逻辑上相互独立的领域。
通过限界上下文,可以将交易领域拆分为订单中心和支付中心两个子域。
集成方式
限界上下文之间可以通过多种方式集成,以实现系统的整体功能。其中常见的集成方式有:
-
事件驱动(Event-Driven):通过事件进行通信,一个上下文发布事件,另一个上下文订阅并处理事件。
-
请求响应(Request-Response):通过请求和响应进行通信,一个上下文发送请求,另一个上下文返回响应。
-
共享数据库(Shared Database):多个上下文共享同一个数据库进行通信。
-
REST API:一个上下文通过发送RESTful请求,另一个上下文返回响应。
集成示例
例如,在支付完成后,可以通过发布支付成功事件,触发订单中心完成支付的相关流程,像发货、推送统计等。
03架构演进
软件架构从单机、集中式到分布式微服务架构经历了三个阶段的演进,每个阶段都以提高系统响应力为目标,通过分离复杂度来实现业务优化。
04架构模式
DDD架构模式有多种,每种都有其优缺点和适用场景:
分层架构
分层架构通过将系统划分为不同层次,实现清晰的职责分离和松耦合:
-
接口层:与用户交互,定义API接口。
应用层:协调系统各部分,完成业务编排。
领域层:定义和实现业务逻辑,是DDD的核心。
防腐层:隔离外部系统,保护领域模型。
基础设施层:提供必要的技术支持,如数据存储和消息队列。
优势
-
职责清晰
易于理解和实现
支持良好的扩展性
劣势
-
可能导致层次过多,复杂度增加
CQRS架构
CQRS架构通过分离读写操作,优化系统性能:
-
命令模型:处理写操作。
查询模型:处理读操作。
优势
-
利于优化读写性能
容易扩展和维护
劣势
-
实现复杂度较高,需考虑命令和查询的同步问题
事件驱动架构(EDA)
事件驱动架构通过事件来驱动系统行为,实现松耦合和高并发:
-
事件生产者:发布事件。
事件消费者:订阅和处理事件。
优势
-
提高系统松耦合性
支持高并发
实现异步处理
劣势
-
需处理事件丢失或重复消费的问题
微服务架构
微服务架构将系统划分为多个小型服务,每个服务有独立职责,围绕业务领域构建:
-
服务定义和发现:确保服务可独立部署和运行。
负载均衡和容错:提高系统可用性。
优势
-
独立部署和扩展
支持多技术栈
更容易管理和维护
劣势
-
需处理服务间通信、服务发现和负载均衡等问题
05 重构设想
背景
目前交易系统的支付领域和订单领域耦合度高,存在职责不清晰、维护性和扩展性不佳的问题。
现存问题
-
职责不清晰:交易逻辑分散于多个模块,易与其他业务逻辑耦合。
可维护性不高:事务脚本式编码导致业务规则散落,影响阅读和维护。
可扩展性不高:历史技术债务多,新功能支持需改动多个关键链路。
重构目标
-
独立管理交易链路核心业务:拆分和迁移现有业务逻辑,实现核心业务内聚。
提高系统可维护性:通过DDD拆分业务子域,减少组件升级对业务逻辑的影响。
提高业务扩展性:利用设计模式和扩展点,区分不稳定节点和固定节点。
领域划分
合理划分领域
在进行领域划分时,需要考虑以下几点:
-
业务逻辑清晰:确保每个领域内的业务逻辑独立且清晰,使其不与其他领域业务逻辑混淆。通过业务用例的分析,识别出各个子域中的概念、流程和规则。
-
领域专家协作:领域模型应由领域专家和开发人员共同创建,反映实际业务情况。通过领域工作坊等活动,确保领域专家的知识得到充分应用。
-
避免过度划分:尽量避免过度细分领域,以免增加系统复杂度。适度划分有助于管理领域边界,并有助于日后的维护和扩展。
-
业务变化灵活应对:领域划分应当是灵活的,可以根据业务需求变化进行调整和优化。选择适合的设计模式(如策略模式、状态模式等)来处理业务变化。
-
聚合关系:根据实体间的聚合关系划分子领域,确保领域内高度内聚和外部低耦合。识别业务中的聚合根,确定其边界和生命周期。
步骤示例
-
识别业务域:通过访谈业务专家、分析业务流程和用例,识别出系统中的主要业务域。
划分子域:识别业务中的核心域(关键业务)、支撑域(辅助业务)和通用域(共享业务)。
-
定义领域模型:与领域专家合作,定义领域中的实体、值对象、聚合根、工厂和存储库。
确定限界上下文:根据业务边界确定限界上下文,清晰定义每个上下文的职责和接口。
-
设计交互模式:选择适合的交互模式(事件驱动、请求响应等)实现限界上下文间的通信。
划分实践
核心域
-
支付中心:负责玩家支付行为和渠道管理。
订单中心:负责订单生命周期管理和交易处理。
通用域
-
商品域:负责游戏商品信息的管理。
优惠域:负责优惠券、积分抵扣等业务。
支撑域
-
CP域:负责与游戏研发交互。
营销域:负责维护高净值玩家,增加收入。
整体结构
代码组织架构
-
API:接口实现,无业务逻辑。
Biz-Logic:业务流程编排。
OrderCenter:订单中心。
PayCenter:支付中心。
Dependency:防腐层。
Datatunnel:数据仓储。
Constant:常量定义。
CommonTool:通用工具类。
DDD-Framework:基础服务,如事件总线和命令总线。
Domainshared:领域共享服务。
06结语
通过学习和实践DDD概念,对复杂度较高的支付(交易)系统进行了详细的领域划分及架构重构,实现了更为合理的业务逻辑分离和代码结构优化。
DDD并不是银弹,但它帮助我们从业务角度更合理地划分系统,找到并改进现有架构中的问题。
为了进一步提升,对DDD框架的应用可以参考以下开源项目:
-
https://github.com/bytedance/dddfirework
-
https://github.com/8treenet/freedom
通过不断学习和优化,我们可以建立更强大的系统架构,从而更好地应对复杂的业务需求和技术挑战。