V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
passerbytiny
V2EX  ›  Java

github 上找到一个 spring cloud stream 驱动领域事件的项目,部署架构看起来很好,单项目内的代码架构看不懂了

  •  
  •   passerbytiny · 2018-08-22 16:34:48 +08:00 · 2665 次点击
    这是一个创建于 2045 天前的主题,其中的信息可能已经有所发展或是发生改变。

    项目地址: https://github.com/kbastani/event-stream-processing-microservices

    首先看了 spint-boot-starter/spring-boot-starter-data-events 项目下的 Aggregate 基类,没有完全看明白,遂决定先不看基类,从子类开始看。

    然后看 account/account-web 项目。一个 domain.Account (聚合根)的行为,本来在聚合根中自己处理就行了,但是先调用 action.SomeAction,再调用 domain.AccountService。这点完全没有看懂,这里的 Action、Module、包括 Service,貌似都是聚合根的辅助类,不明白为什么要加这些,尤其是 AccountService 还容易跟领域服务搞混。

    再接下来看到一个行为,我就直接开始怀疑人生了。

    • 表现为,accout-web、order-web 两个项目都定义了 demo.order.domain 包和相同的类,但每个类的内部不一样:
      • accout-web 项目的类通过 REST 接口获取数据,该项目的 Action 直接调用了 order.domain 包的类。
      • order-web 项目的类通过本地获取数据
    • 疑问:
      • order-web 的 Order 聚合,被直接暴漏给了 account-web 项目
      • 虽然名称、字段、行为声明都已经暴漏过去了,但又需要 accout-web 项目自己提供实现
      • order-web、account-web 项目定义了包名、类名一样的模型,两套模型之间存在主体和镜像的关系,怎么看怎么别扭,怎么看怎么容易出错。

    有没有见过这样代码架构的,解释和推广一下。

    11 条回复    2018-09-04 18:02:00 +08:00
    passerbytiny
        1
    passerbytiny  
    OP
       2018-08-22 16:58:58 +08:00
    好吧,整体架构上发现也不对,Web 与 Worker 的职责和关系是:Web 负责生产和存储事件; Worker 负责消费事件。而不是我原来想要的:Web 独立负责业务,生产事件时仅存储事件,主业务与存储事件有强一致性(即在同一个事务中); Worker 负责异步的将事件发送到消息中间件。
    xuanbg
        2
    xuanbg  
       2018-08-23 07:32:32 +08:00
    大致看了一下,我觉得他的设计的核心就是前端的功能路由由后端来提供。。。譬如创建了一个账号,就会返回给前端一些账号信息和 3 个 url,点这 3 个 url 进去优惠得到一些数据和 url。前端只要按一定的规范展示这些数据和 url 就行了,典型的软狗思维。

    过度设计,套了一些流行概念,很是能哄骗一些入世不深的小年轻。其实根本没鸟用,产品经理 /乙方老板才不要按你的这个套路来呢。
    passerbytiny
        3
    passerbytiny  
    OP
       2018-08-23 10:48:28 +08:00
    @xuanbg 你的第一段说的不对,这是标准的 RESTful 风格,跟路由无关,这种风格是没问题的。至于第二段说的,这个人是外国人,不能用中国国情去评判。

    你的回复与我的疑问并没有关系。
    xuanbg
        4
    xuanbg  
       2018-08-23 10:57:15 +08:00
    @passerbytiny 我不至于连 RESTful 也不知道。。。我说的路由是这个货:
    "_links": {
    "self": {
    "href": "http://localhost:54656/v1/accounts/1"
    },
    "events": {
    "href": "http://localhost:54656/v1/accounts/1/events"
    },
    "commands": {
    "href": "http://localhost:54656/v1/accounts/1/commands"
    }
    }
    这 3 个 url 是包含在账号信息里面的,文档里面也说得很清楚,就是进一步可以点击的 URL。

    我们也是 RESTful 的接口,但只返回账号信息数据,不返回这些进一步操作的 URL。你明白?
    passerbytiny
        5
    passerbytiny  
    OP
       2018-08-23 11:01:25 +08:00
    @xuanbg 这就是 RESTful 的 links
    passerbytiny
        6
    passerbytiny  
    OP
       2018-08-23 11:02:48 +08:00
    feiyuanqiu
        7
    feiyuanqiu  
       2018-08-26 04:16:15 +08:00
    @xuanbg Hypermedia As The Engine Of Application State (HATEOAS)
    feiyuanqiu
        8
    feiyuanqiu  
       2018-08-26 05:19:20 +08:00
    只看了 account-web 下面的 account 创建的逻辑,感觉没什么问题,基本是按照经典的领域驱动设计做的

    AccoutService 是 Account 领域服务这个没什么好说的,AccountService 在 registerAccount 时,先调用数据仓库持久化实体,再发布领域事件 ACCOUNT_CREATED,领域事件实际上就是个订阅发布者模式,account-worker 订阅了 AccountEvent,收到事件消息后,会再做一些处理
    (我不太喜欢它这里实体继承 Aggregate 的做法,account.sendAsyncEvent 并不是 account 的领域行为,不应该放在实体里,这样让实体不单纯了,同时还反向依赖了 AccountService,也不好测试)
    passerbytiny
        9
    passerbytiny  
    OP
       2018-08-27 10:45:41 +08:00
    @feiyuanqiu
    AccoutService 从它的位置来看是领域服务,但是从它的作用来看并不像领域服务。它只处理 Accout 的内部行为,换句话说它就是 Accout 实体的行为的集合。另外,在实体中调用领域服务是一个很危险的行为。领域服务是允许处理多个聚合根的,实体调用领域服务,一不小心就通过它调用了另外的聚合根。所以我很怀疑:在 account-web 的架构中,AccoutService 不是领域服务,而是 Account 实体的动作(由各个 Action 定义)的实现。

    sendAsyncEvent 发布异步领域事件,其中的发布领域事件就是聚合根的领域行为,这个没问题。但是发布时就确定异步这个处理是否合理就不确定了,我的意见是同步或异步应当由订阅方而不是发布方决定。

    我其实要找的是:强一致性的事件存储、部分事件内部直接订阅处理、部分事件读取事件存储发布到消息中间件(可重试)、外部限界上下文通过消息中间件订阅事件(可纠正顺序)、使用 Spring Cloud Stream。然而它那个架构并不是这样的,它只是 account-web 存储并立刻发送事件到消息中间件(不重试)、accout-worker 通过消息中间件订阅事件(未对接受顺序纠错)。
    jokefaker
        10
    jokefaker  
       2018-09-04 15:00:53 +08:00
    这个代码我倒是没怎么看过,不过 LZ 寻找的东西貌似和我很相似,在网上找了很多例子发现都不太符合自己的需求。所以最后我是 axon 实现了 Event Sourcing + CQRS,然后拓展了下事件的存储来保证事件发布到消息中间件的一致性问题(通过 Spring Cloud Stream ),Consumer 的消费顺序问题,我没有做深入的处理,只是所有的 Domain Event 都会带上 axon 中的 seq,在 Consume 的时候碰到 seq 不对的,在重试几次之后就直接丢到 DLQ 中走失败流程了。
    passerbytiny
        11
    passerbytiny  
    OP
       2018-09-04 18:02:00 +08:00
    @jokefaker Event Sourcing + CQRS 走得太远了,这个架构以后再处理。我现在需要把常规的、微服务用的事件驱动架构做出来。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1343 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 23:38 · PVG 07:38 · LAX 16:38 · JFK 19:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.