写点什么

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

  • 2019-11-03
  • 本文字数:1769 字

    阅读完需:约 6 分钟

基于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:003828

评论

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

2021Java面试心得:kafka工具

Java 程序员 面试 后端

Linux之free命令

入门小站

Linux

2021年最新大厂Android面试笔试题目,威力加强版

欢喜学安卓

奥运神颜运动员

6979阿强

Python OpenCV 图像处理之 图像运算和图像位运算知识补充

梦想橡皮擦

7月日更

【翻译】数据包的旅程 - OSI模型

luojiahu

计算机网络 OSI模型

Linux ssh命令详解,连ssh命令都不了解就别说自己会用Linux了

北游学Java

Java Linux SSH

云小课 | 一分钟了解AppCube中的应用

华为云开发者联盟

低代码 云小课 应用 AppCube 应用魔方

HarmonyOS开发者日杭州站举办,多维赋能开发者实现高效开发

科技汇

🏆【Java 技术之旅】带你深入理解和认识SPI运作机制

码界西柚

Java 抽象 spi 7月日更

🏆「推荐收藏」【Git实战专题】代码提交错误怎么办?教你如何回退版本!

码界西柚

git git flow git reset git revert

iOS开发底层面试攻略

面试 移动开发 ios开发

2021腾讯Android面试题精选,复习指南

欢喜学安卓

android 程序员 面试 移动开发

带你看清梦饷集团如何成为上海在线新经济四小龙

华为云开发者联盟

MySQL 数据库 mongodb 电商 华为云数据库

校友卡微信小程序开发总结

CC同学

个性化联邦学习算法框架发布,赋能AI药物研发

华为云开发者联盟

联邦学习 药物研发 算法框架

FIL云算力挖矿平台系统开发案例

Geek_23f0c3

云算力挖矿系统开发详解 云算力模式系统开发源码 filecoin矿机哪家好? fil挖矿

Python开发篇——如何在Flask下编写JWT登录

吴脑的键客

Python flask JWT

吴亦凡都美竹事件:男人全员恶人?

6979阿强

2021Java面试心得:docker运行springboot项目

Java 程序员 面试 后端

2021Java面试总结!Java中VO的使用

Java 程序员 面试 后端

2021年中国DevOps现状调查报告发布!

华为云开发者联盟

DevOps 敏捷 安全 华为云DevCloud 信通院

结对编程,到底是双剑合璧还是脚趾抠地?

华为云开发者联盟

编程 软件 敏捷 敏捷开发 结对编程

7月日更,FAIL!FAIL?

Nydia

IM与办公平台的关系设计

superman

产品经理 架构师 IM 移动办公平台 自建移动办公

在线诺基亚短信图片生成器工具

入门小站

工具

Confluence 7 如何修改启动内存

HoneyMoose

马拉松还是骇客松 Hackathon?

escray

学习 极客时间 朱赟的技术管理课 7月日更

golang--字典树

en

数据结构与算法 字典树

从0到1亿用户的架构设计

俞凡

架构

云计算架构师-带你安装MySQL数据库并去除安全隐患

学神来啦

MySQL 数据库 Linux 运维 MariaDB

基于DDD、CQRS、微服务和事件溯源构建系统_研发效能_Jan Stenberg_InfoQ精选文章