links: https://engineering.zalando.com/posts/2018/01/simplicity-by-distributing-complexity.html

TLDR

如何迁移到全event流式的开发,同时分散异步的控制流带来的复杂度。

背景

项目有三类实体,Product、Media、Enrichment。Media对Product有依赖,Enrichment对Media Product都有依赖。

问题

初始设计是,product,media, enrichment各有一个kafka topic。

消费方需要有一个聚合视图,包括productId、media和enrichment的全部数据。

消费方消费三个topic的顺序是不固定的,有可能Media来了,product还没创建。

消费方定序方案

消费方定序,有一个服务专门维护本地状态,将定完序的消息发送到聚合视图的topic里。

这个方案的问题是:代码复杂度太高,而且随着流数量和实体状态增高而增高。

原因

初始设计,丢失了创建时的顺序信息。创建时因为有依赖关系,顺序是对的,但是分开传入不同的topic中后,状态信息丢了。

单Topic方案

将所有的信息放入一个Topic中,因为所有的实体对product都有直接或者间接依赖,可以按照productId作为partition key。

问题:

需要用productId作为key,但是并不是所有实体都直接与product作关联。比如说: enrichment依赖media,media依赖于product。 enrichment并不直接知道product的信息。

解决有两种方案:

  1. 提交enrichment的消息时,找到对应的media,再找到对应media的productId。
  2. enrichment直接关联product。

但是这两种方案都会破坏对实体的封装,实体需要意识到,自己还有parent的概念。

目标

要达到的目标是:

  1. 为不同stream下的事件定序。
  2. 实体应该在依赖对象的上下文下处理。

最终方案

被依赖实体要消费 直接 依赖它的实体的流。将消费到的实体发布在被依赖的实体之后。

在这种情况下,productId需要同时消费media和enrichment的消息, 但是只取直接关联product的enrichment ,将enrichment放到关联的product消息之后。

对于直接关联media的enrichment消息,由media来消费,product流通过消费media来定序。

好处

定序的复杂度被分散在了各个producer处,一个producer只关注直接和他关联的实体。