写点什么

基于 DDD、CQRS、微服务和事件溯源构建系统

2019 年 11 月 03 日

基于DDD、CQRS、微服务和事件溯源构建系统

对于构建系统来说,模块化是至关重要的,但实现模块化需要应对一些反模块化的做法。两种典型的反模块化做法就是在不考虑业务领域的情况下走捷径和拆分微服务,这会增加技术债务。最近,在由AxonIQ举办的阿姆斯特丹事件驱动微服务大会上,Allard Buijze分享了他的一些想法,以及基于DDDCQRS、微服务和事件溯源构建系统的亲身经验。


Buijze 是 AxonIQ 的 CTO。他指出,另一个反模块化做法就是名词驱动设计(noun-driven design)。名词驱动设计用于发现应用程序中的对象,通常是通过查找应用程序中出现的名词,而非采用那些用于创建服务的对象。如果开发人员需要一次性重新部署多个服务,或是某个服务需要依赖于其他服务,就会从单体应用转为分布式单体应用,但潜在的问题并没有得到解决,这并不是微服务架构。


Buijze 认为,转向微服务需要一个过程,无法一步将业务模型转为微服务。反之,我们应该从那些具有良好结构和模块化的单体应用着手,根据需求逐步拆分出新的微服务。他强调,创建微服务的需求应该是非功能性需求。


Buijze 指出,将组件抽取成微服务的重点在于实现位置透明性。组件不应该知道或者假定知道与之交互的其他组件的位置。这意味着当组件可被抽取为微服务时就无需重写现有组件与新服务之间的通信。


解决位置透明性问题的通常做法是使用事件。一个服务无需直接调用与之通信的其他服务,而是通过发布事件并设置服务去监听事件。Buijze 指出,使用事件的一个重要特点是实现了依赖关系的转置,即订阅事件的组件或服务可以直接监听发送的事件。


Buijze 介绍了只使用事件会出现的一个常见错误,即事件也会被用于间接请求发生于其他服务中的操作,这会增加服务间的耦合度,可能导致双向依赖,使得服务间依赖关系难以编排。如下例,图中没有负责业务流程的服务:



组件间会因为不同的原因发起通信。除了使用事件之外,还存在另外两种消息,一种是用于表示改变事物的“命令”(Command),另一是用于获取信息的“查询”(Query)。在上例中,订单服务(Order)可使用“命令”去请求支付(Payment)和交货(Shipping)服务,交货服务可使用“查询”去请求订单服务细节。Buijze 建议我们应该像使用事件那样同等使用命令和查询。


事件溯源是另一个与事件相关的概念。在使用事件溯源时,组件中存储的并非实体的具体状态,而是导致每个实体状态发生变更的事件。Buijze 认为,事件源就是获取所有的事实,并且只关心事实。但他也指出,事件溯源必须被正确实现,否则就无法确保事实的完整性。要验证事件溯源是否被正确实现,可以试着抛开事件存储以外的东西。如果应用程序的状态可重现,说明事件溯源做对了。Buijze 进一步指出,要在服务中使用事件溯源,服务必须使用自己发布的事件来保持一致的状态。


从业务和技术方面来看,事件溯源都有一些优势,审计和单一数据源就是两个很好的例子。 事件溯源同样存在一些挑战,例如增加了存储规模、实现复杂度高。但 Buijze 认为,这些问题现已不复存在,目前最大的挑战在于事件思维(event thinking)。在 Buijze 看来,事件是一种更为自然的理解应用程序行为的思维方式。他建议,我们应该将注意力放在行为上,而非状态上。事件和命令描述了应用程序的功能,因此让应用程序的行为变得更容易理解。但他并不建议对所有应用程序使用事件溯源。与其他工具一样,事件溯源仅在合适的场景才能发挥作用。


最后,Buijze 强调,所有的通信都是某种形式的合约。基于事件架构的一个缺点是需要对很多未知的组件建立合约。因此,我们要对事件和合约的范围加以约束,避免各个有界上下文之间存在耦合。在同一上下文中,所有服务使用同一种语言,并且能理解所有的事件。但是很多事件,尤其是事件溯源中的事件,只在特定的上下文中是有用的,不应该被发布到上下文之外。对于一些公共事件,一种好的做法是将事件转换为公共 API。


Martin Fowler 在 2015 年发表的一篇博文中提到,他已经注意到乎所有成功的微服务均源于单体应用。但此后不久,Stefan Tilkov 在其博客中提出了不同的看法,即如果目标是实现微服务架构,那么从单体应用着手是完全错误的做法


欧洲2019 DDD大会的一个演讲中,Eric Evans 介绍了各种类型的“有界上下文”,其中一些类型尤其适用于基于事件的系统。


大会演讲全程录像,并将于近几周内公开发布。


原文链接:


Sense and Nonsense in Event Thinking and Microservices


2019 年 11 月 03 日 08:002585

评论

发布
暂无评论

android布局优化!Android屏幕适配很难嘛?其实也就那么回事,内含福利

欢喜学安卓

android 程序员 面试 移动开发

Wiki.js 配置 LDAP 认证

东风微鸣

wiki

华为云举办AI经典论文复现活动,打造领先AI开发者学习社区

华为云开发者社区

AI 华为云 modelarts 论文 AI Gallery

Linux入门篇 —— Linux 磁盘管理之磁盘理论篇

若尘

Linux linux编程 磁盘

GaussDB(DWS):非侵入式备份及其在NBU上的应用

华为云开发者社区

架构 GaussDB 集群 备份 NBU

海豚调度dolphinscheduler SQL脚本初始化流程

cloudcoder

海豚调度 调度引擎 分布式任务调度

刷屏洗脑的“吗咿呀嘿”,到底是个啥?

架构精进之路

商业模式 28天写作 3月日更

山东青岛推进平安小区建设!源中瑞智慧社区平台解决方案

源中瑞-龙先生

解决方案 山东 源中瑞 青岛 智慧社区

聊一聊library,framework以及toolkits之间的异同

御剑

架构

工作两三年了,整不明白架构图都画啥?

小傅哥

Java 后端 小傅哥 架构设计 画架构图

QA视角看数据匿名化

BY林子

数据安全 测试右移 用户数据 数据脱敏

树莓派上的温湿度环境监控

冯骐

运维 树莓派 物联网 监控告警

看完你就明白什么是图神经网络

华为云开发者社区

神经网络 深度学习 节点 图神经网络 图结构

如何写好一份解决方案

数列科技杨德华

28天写作

构建一套适合微服务的高可用架构

环信

OS命令--shell中数组的操作

cloudcoder

数组 Shell 循环引用

Node集群思考以及cluster包初探

秋呈

后台开发 Node

MySQL字段默认值设置详解

Simon

MySQL 数据库

程序员之禅(一)

每天读本书

读书笔记

更新啦!第 59 期《HelloGitHub》开源月刊

HelloGitHub

GitHub 开源项目

Elasticsearch Fetch Phase

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试

华为云原生数据仓库GaussDB(DWS)深度技术解读:融、快、大、稳、易

华为云开发者社区

数据库 云原生 华为云 GaussDB 数仓

建立博客数据库并连接ES用MySQL还是MongoDB更合理

读字节

MySQL mongodb 分布式 分布式数据库 分布式存储

使用 pyVmomi 采集 vSphere 监控指标

冯骐

Python 运维 监控 Open-Falcon vpshere

技术案例 | 云原生微服务落地难?百度自用CRM这样做

百度开发者中心

CRM 云原生微服务 #百度智能云#

android程序开发!2021Android精选面试实战总结整理,大厂直通车!

欢喜学安卓

android 程序员 面试 移动开发

元宵节元宵钱,不买元宵买云资源! | 2核4G低至0.79元/天

京东科技开发者

云主机 云服务器 云存储 云硬盘

树莓派上的家庭监控中心

冯骐

运维 树莓派 监控系统 Open-Falcon 物联网,

搭建一个 802.1x 的 web 测试服务

冯骐

网络 监控系统 Open-Falcon radius eduroam

程序员专属“灯谜”大挑战,答对六题算你赢!

京东科技开发者

编程语言 集群

MongoDB 在评论中台的实践

vivo互联网技术

数据库 mongodb 分布式 集群

基于DDD、CQRS、微服务和事件溯源构建系统-InfoQ