当真相来源是Apache Kafka时如何生成身份?

时间:2017-01-01 18:12:04

标签: domain-driven-design apache-kafka cqrs event-sourcing

我正在构建一个由几个微服务组成的系统。他们将遵循CQRS,ES和DDD方法。我想使用Apache Kafka作为真相的来源" - 正如Jay Kreps在Confluent&LinkedIn和LinkedIn的工程博客上的许多材料中所说的那样。

我的问题和主要问题是:

当Apache Kafka是真相的来源时,如何为新实体生成身份?

示例:

我有订单(在网上商店)。由于Kafka是我的真相来源所以我想首先将数据放到Kafka然后我使用来自Kafka的数据来填充一些数据库,例如MySQL或弹性搜索。当用户创建新订单时,我正在添加" newOrder"事件到日志与订单的详细信息(订购了哪些物品和数量,客户数据,送货地址等)。我希望Order有一个ID,这样我就可以在MySQL和Elastic Search中填充数据时使用它。

您是否了解任何技术,最佳实践如何为订单分配ID(身份)?

使用例如,这很容易MySQL作为事实的来源。在这种情况下,我会有一些" id" MySQL将为其分配ID整数的列。

修改

我知道GUID的概念,但我正在寻找其他一些概念。

2 个答案:

答案 0 :(得分:1)

@miglanc我认为您应该使用独立的ID机制(就像GUID一样简单)。从系统的角度来看,ID"看起来并不重要。喜欢。确保您选择的是cross-paltform(它将与MySQL,MSSQL,弹性搜索一起使用)。

如果您打算在一个宁静的网络服务中使用该ID,并希望它看起来更自然,那么您也可以创建自己的ID系统。如果使用6个字符(字母数字),则有数百种可能性。只需创建一个为您执行此操作的服务。

IdentityService.NewId()=> " X4ER4T&#34 ;.这样你就可以在宁静的api中使用它,感觉自然"。获取api / order / X4ER4T

此外,您可以在生成验证规则时创建自己的验证规则。您可以随机或顺序生成它们。您可以存储批次'内存中的ID已经被使用并加快了进程(消除了往数据库的往返以检查可用的最新ID)。

我为一家保险公司(类似于你的公司)这样做,他们非常高兴。

答案 1 :(得分:0)

有一个'简单'的解决方案,但正如您将看到的,它在实践中变得更加复杂。

kafka中的每条消息都由代理分配唯一的偏移ID(64位长)。它是一种类似sql的序列,随着消息单调增加,它总是与实际有效载荷(密钥/消息)一起发送到客户端。它是kafka协议的核心(客户端通过向经纪人发送最后看到的偏移量来保持轮询数据),因此新版本不会消失。

只要您拥有永不失败的单一分区,它就是您的问题的完美解决方案 - 精心排序的人工密钥,可以放入单个db列,如果您重放kafka流,它将完全按预期重新发送(然后你可以将它与你的数据库进行协调,执行upserts,或者只是在pk违规时失败)。你可能真的不想在pk重复上失败,因为在你的应用程序崩溃的情况下,kafka会重新发送你已经看过的部分消息,所以某种类型的upsert / reconcilation更好。无论如何,它应该没有问题。

对于多个分区(在kafka中很常见),事情变得更加复杂。偏移仅在单个分区的上下文中是唯一的,并且分区之间没有数字关系 - 因此id 1000分区0可能比id 5000分区1晚了很多('later'在引号中,因为当你考虑parititions时以适当的方式,你不应该把它们之间的事情视为按时排序。这意味着:

  • 你需要用分区ID来丰富你的主键,这不再是那么漂亮了

  • 通过主键及时正确订购的所有订单都会失去良好的视觉副作用

只要您的kafka群集没有发生灾难性故障,这仍然有效。如果您需要对kafka / zookeeper环境进行全面干净重启,所有偏移都将重置为0.我不知道有什么方法可以让它们从更高的数字开始(有很多方法可以改变消费者的偏移,但我没有发现任何影响生产者/经纪人的抵消)。那时你的整个逻辑都被打破了,并且没有简单的方法可以从那个状态恢复(除了改变你的代码和做一个技巧,比如假设partitionid = partitionid + 100或类似的东西,有效地添加第三部分主键,是'世代身份')。

根据我的理解,假设kafka永远不会以这种方式失败 - 如果配置正确,将会有副本,故障转移,滚动更新等等。但是你打赌你的整个设计永远不会打出来内存,磁盘空间不足,普通bug在新版本的kafka-when-updated-from-old-old-format等类型的问题?

您可能希望与拥有更多kafka经验的人交谈 - 我们遇到了需要在开发中进行几次干净安装的主要问题(总是我们的错误 - 达到物理RAM限制并且让Linux OOM杀掉随机内容,磁盘空间不足或搞乱码头启动/安装)。可能,通过更多的努力,有可能在每种情况下恢复旧状态,我们只是通过重置所有东西(它是dev,我们不依赖于外部的偏移)来取消廉价路线。