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的信息。
解决有两种方案:
- 提交enrichment的消息时,找到对应的media,再找到对应media的productId。
- enrichment直接关联product。
但是这两种方案都会破坏对实体的封装,实体需要意识到,自己还有parent的概念。
目标
要达到的目标是:
- 为不同stream下的事件定序。
- 实体应该在依赖对象的上下文下处理。
最终方案
被依赖实体要消费 直接 依赖它的实体的流。将消费到的实体发布在被依赖的实体之后。
在这种情况下,productId需要同时消费media和enrichment的消息, 但是只取直接关联product的enrichment ,将enrichment放到关联的product消息之后。
对于直接关联media的enrichment消息,由media来消费,product流通过消费media来定序。
好处
定序的复杂度被分散在了各个producer处,一个producer只关注直接和他关联的实体。