写点什么

领域驱动设计框架 Axon 实践

  • 2020-09-15
  • 本文字数:3445 字

    阅读完需:约 11 分钟

领域驱动设计框架Axon实践

背景

2004 年,Eric Evans 发表了 Domain Driven Design(领域驱动设计,DDD)这一著作,并在书中对领域驱动作出了开创性的理论阐述,至今领域驱动设计已问世十几年。

近几年来随着微服务盛行, ES (Event Sourcing)事件溯源和 CQRS (Command Query Responsibility Segregation)读写分离也成为了一个越来越流行的概念,使用 ES 和 CQRS 好处在此不做赘述,但是也存在颇多弊端,比如事件数量巨大、回溯状态需要提前预热、缺少成熟的框架支撑等。在这种情况下,2009 年 Allard Buijze 在 JVM 平台开源了 Axon Framework 用来解决此问题,简单说来 Axon 就是集成了 DDD、ES 和 CQRS 于一身,落地实现的一套框架方案,并成立了一家公司 Axon IQ,专门与 Axon 产品合作。

爱奇艺号技术团队,在实施微服务化过程中,应用领取驱动思想,采用 Axon 框架落地了多个服务,下面是实施过程中的经验总结。

技术选型

爱奇艺号合同中台面向用户提供签约功能,从发起签约到运营审核、供应商、采购单、扫描件、归档等流程漫长,状态颇多,业务较为复杂,同第三方系统交互较多,对于有问题数据需要进行定位和回溯。项目初期为了更好的满足这些需求,我们调研了一下比较成熟的框架,包括 Cola、Axon、Activiti、Spring StateMachine 等,图 1-1 是框架的一些对比:



图 1-1


从对比中可以看出,Axon 支持事件回溯,排查历史问题较为方便,并且官方文档完善,一直处于更新维护中。StateMachine 较为轻量,流程变更对于历史数据兼容性良好。综合考虑采用 Axon+StateMachine 相结合,实现简版工作流引擎。

Axon 框架介绍

Axon 框架的程序遵循基于领域驱动设计(DDD)、命令查询责任隔离 (CQRS)、事件驱动架构(Event Driven Architecture,EDA)的体系结构模式,这些原则的结合,使基于 Axon 的程序更加健壮、适应性更强。图 1- 2 是基于 Axon 框架程序的典型体系结构:



图 1-2


基于 Axon 框架程序的典型体系结构图特性如下:


  1. 领域驱动模型:可以使业务实体不会“贫血”,更加饱满,实现高内聚、低耦合;

  2. 命令查询责任隔离:命令模型和查询模型的分离,使得每个模型更容易理解,更易开发维护,天然适合高并发场景;

  3. 事件驱动架构:支持事件溯源,方便对历史事件重放,记录数据变化完整过程,便于 BI 分析、线上问题排查、还原系统状态到任意时间点等。


Axon 系统调用链如图 1-3 所示:



图 1-3

Spring StateMachine 介绍

Spring StateMachine 是使用 Spring 框架下的状态机概念创建的一种应用程序开发框架。它使得状态机结构层次化,简化了配置状态机的过程。拥有有现状态机的特性功能:现态、条件、动作、次态,支持触发器、状态转移器、保护机制、状态转移动作和状态事件监听器,可基于 Zookeeper 实现分布式状态机,可配置多层次、结构复杂的状态机。图 1-4 是简单配置效果图:



图 1-4

爱奇艺号合同中台服务实践

【项目介绍】

用户入驻爱奇艺号后发表作品会获得分成收益,账号满足一定条件后可以申请提现,提现之前需要跟公司签约电子合同。为了保证合同安全有效,线上签约流程比较漫长,包括用户填写信息、运营审核、采购单申请审核、合同审核、合同附件盖章邮寄、作品关联等等,累计 20+状态,业务逻辑较为复杂,需求迭代变更频繁,对数据一致性要求较高。


项目 1.0 版本采用的是 Activiti 工作流作为引擎设计实现的,基于 Activiti 特性,可以严格控制每一步状态的流转,历史操作事件都会记录到系统数据库中,对于线上问题排查有一定的优势。但是学习成本较大,需要开发人员了解框架系统的二十多张表功能、使用 BMPN 进行流程定义设计等。图 1-5 是最初版本的流程设计图:



图 1-5


随着业务的发展,想要修改流程设计,增加一些新状态,此时 Activiti 的弊端更加暴露出来:如果在原有流程上修改,对于历史数据的显示会报错,如果新增流程,对于正在流程中的数据又没法使用新流程,只能终止掉重新发起。Activiti 针对这种流程升级,或者中国特色式的工作流一直没有很好的解决办法,网上的一些解决方法较为复杂,涉及到修改系统内置数据库,实现起来成本较大。针对这种情况,爱奇艺号开发团队对系统进行了升级,采用 Axon+Spring StateMachine 相结合进行项目架构设计,实现了合同系统 2.0 版本,最终呈现的结果如图 1-6:



图 1-6


架构说明如下:


  1. 用户接口层:主要是 MQ 消息、UI 和 API 接口,接收用户请求、运营审批命令、第三方系统交互通知等;

  2. 应用层:接口参数校验、组装业务参数,转换成 Axon Command 进行命令分发;

  3. 领域层:接收到领域事件,转换成状态机 Event,驱动状态机进行状态更迭,触发对应业务逻辑处理;

  4. 基础服务层:提供底层存储服务,第三方服务等。


系统调用流程如下图 1-7:



图 1-7


Axon+StateMachine 结合,实现简版工作流引擎功能,相比于 Activiti 更加轻量级。以合同对象多为领域对象,系统操作命令使用状态机进行控制流转。所有对系统的修改操作均以 Axon 的 Command 进行,Axon 会记录所有对领域对象操作过的事件,可以还原合同生命周期内每一步的状态,对于问题排查,统计分析有着很大的帮助;snapshot 机制对事件进行预热,解决事件过多加载慢的问题;sage 对系统失败操作进行补偿事件,保证系统间数据状态的一致性;StateMachine 特性,可以修改状态之间流转走向及流转条件,新增状态对于历史数据或者进行中的数据没有影响,对系统的迭代开发有很大的效率提升,天然适合互联网性质工作流。

价值

通过在爱奇艺号后端服务应用 Axon 框架,可以达成以下效果:


1、 开发方面的优势


  • 转换思维:Java 语言开发一直提倡面向对象开发,但是很多业务开发人员的思维还是面向过程开发的思维,按照 MVC 分层进行业务代码的堆叠。Axon 思维更倾向于面向对象,以领域对象为核心,由于领域对象有明确的领域边界,所以容易促进开发人员思维模式的转变。

  • 提升开发效率:项目基于命令模型开发,可以让熟悉业务的开发人员专注于领域层开发,接口和应用层开发则可以由对业务比较陌生的开发人员负责,二者通过命令发送消息机制进行通信。这种职责分离的优势在于不需要所有的开发人员都对业务非常熟悉,减少了熟悉具体业务的时间,且每个开发人员都职责明确,可显著提升开发效率。


2、 运行维护时的优势


  • 便于问题排查:事件溯源机制使得领域对象的每次操作变更状态都有记录,对于排查线上问题有很大的帮助,可以按照先后顺序还原对象的每一步状态。snapshot 机制有很好的解决了 ES 事件预热的问题。对于 BI 的分析也有着更好的支撑。

  • 支持系统高吞吐量:CQRS 的支持,天然适合高并发场景,如果系统有高并发的需求,使用 Axon 框架可以得到更好的支持。

  • 便于维护和拓展:Axon 框架的代码层次清晰,易维护,使用的事件机制让系统更具可扩展性。

难点

  • 分布式事务一致性问题,saga 虽然能保证分布式事务的最终一致性,但是实施起来困难很大,需要开发各种补偿机制来实现。而且没有考虑到服务的宕机、幂等、重试支持等问题

  • 批量事务处理能力较弱,对于一些批量功能,目前只能转换成单独的命令进行处理,没有提供很好的批处理能力。

  • 与 Spring cloud 整合问题,Axon 支持与 Spring Cloud 结合,使用分布式消息队列来实现分布式系统间命令的分发,但是目前没有比较良好的实现,中文文档较少,需要进一步研究实施。

  • Axon 的充血模型虽然是一大特色,但是实施起来比较繁琐,对于简单的业务实现,贫血模型更加适合。

  • 中文文档少,上手难度较高,国内使用人少,遇到问题可请教或讨论的人少。

未来规划

从 4.0 版本开始,Axon 已经不止是个框架,而是一个由 Axon Framework 和 Axon Server 组成的平台。目前官方发布的最新 Axon 版本已经是 v4.3.3,本文中的项目基于 Axon 框架 v3.04 进行开发,并且是基于单机事件传播,对于 Axon Server 机制还未深入研究使用。另外对于一些高级特性如:与 Spring Cloud 整合、分布式命令、分布式事件、分布式事务等需要进一步实践和总结。Axon 命令分发支持与配置 AMQP 协议的 MQ(Message Queue)绑定,MQ 用于把 Event 分发到 MQ 中,采用这种机制可以针对性的对服务进行更细粒度的拆分,命令分发和处理可以配置成不同的模块,按照各自吞吐量进行服务部署。此外,分布式事务一直是个令人头疼的问题,对于 saga 的优雅实现需要花费更多的时间进行深入研究。


领域思想的转变对面向对象开发语言有着重大的帮助,成熟的架构支持及持久的维护性对于技术选型有着很大的影响,流行的 Axon, Akka, Cola 等框架势头正猛,相信领域思想未来会更深入人心。


作者介绍


本文转载自公众号爱奇艺技术产品团队(ID:iQIYI-TP)。


原文链接


领域驱动设计框架Axon实践


2020-09-15 14:055429

评论

发布
暂无评论
发现更多内容

关于微服务架构思考

Axe

消息疯狂堆积!RocketMQ出Bug了?

Edison

RocketMQ 中间件

Netty之旅:你想要的NIO知识点,这里都有!

一枝花算不算浪漫

Netty nio

learn go with tests 学习笔记(一) hello world

Geek_4z9ami

Go 语言

learn go with tests 学习笔记(六)进程同步

Geek_4z9ami

Go 语言

“啰嗦”是成事唯一正确的方法

霍太稳@极客邦科技

团队管理 个人成长 团队协作 沟通

话题讨论 | 特朗普正式封禁微信,iPhone 和微信二选一?

InfoQ写作社区官方

写作平台 话题讨论

踩坑记 | Flutter升级影响了NestedScrollView?

哈利迪

android

learn go with tests 学习笔记(四)依赖注入

Geek_4z9ami

Go 语言

learn go with tests 学习笔记(七)反射

Geek_4z9ami

反射 Go 语言

政策加持迎来区块链技术应用“红利期”

CECBC

500行代码写一个俄罗斯方块游戏

程序员生活志

以区块链为基础 通证经济是下一代互联网的数字经济

CECBC

区块链 落地应用

人生修炼秘籍

xiaoboey

时间管理 人生修炼 知行合一 熵增 时间复利

零代码/无代码 vs 低代码 如何分类?如何区别?到底有什么不同?分析超过20款零代码低代码产品

代码制造者

编程 低代码 行业资讯 零代码

我是如何参与硅谷顶级开源项目并赚得2500美金

阿水

硅谷 Minio

企业网站搭建避坑指南

姜奋斗

网站 新手指南 企业 网站搭建 避坑

Web 开发必须掌握的三个技术:Token、Cookie、Session

华为云开发者联盟

HTTP Token web开发 session Cookie

learn go with tests 学习笔记(二) 数组与切片

Geek_4z9ami

Go 语言

Python爬取微信公众号文章保存到数据库

wjchenge

RocketMQ源码解析-开篇

Edison

RocketMQ 中间件

learn go with tests 学习笔记(五)并发

Geek_4z9ami

Go 语言

《effective-go》 学习笔记

Geek_4z9ami

Go 语言

疫情之年 下半年区块链应用落地会加速么?

CECBC

区块链 场景应用落地

Executor看不懂?教你如何盘它

Edison

后端 线程池

MySQL事物-学习笔记

Edison

MySQL 数据库 数据库事务

nested exception is java.lang.IllegalStateException: refreshAfterWrite requires a LoadingCache异常解决

谙忆

用户体验(UX)设计≠用户界面(UI)设计

刘华Kenneth

敏捷 设计 UX 用户体验

数据采集能力受限?企业数字化运营如何迈出第1步

易观大数据

字符串匹配 - Sunday算法

Geek_4z9ami

数据结构与算法 字符串匹配算法

learn go with tests 学习笔记(三) 指针和错误

Geek_4z9ami

Go 语言

领域驱动设计框架Axon实践_开源_爱奇艺技术产品团队_InfoQ精选文章