微服务消息传递数据库分配的标识符

microservice messaging db-assigned identifiers

我工作的公司正在研究从我们当前的整体 API 迁移到微服务。我们当前的 API 严重依赖于 spring 并且我们使用 SQL 服务器来实现大多数持久性。我们的微服务调查倾向于 spring-cloud、spring-cloud-stream、kafka 和多语言持久性(每个微服务的独立数据库)。

我对微服务架构中通常如何通过 kafka 进行消息传递有疑问。我们计划在一组微服务和我们的客户端应用程序之间建立一个协调层,它将协调不同微服务之间的活动,并将客户端与微服务 API 的更改隔离开来。我们读过的关于使用 spring-cloud-stream 和 kafka 的大部分内容表明我们应该在协调层(源)使用流来进行资源更改操作(插入、更新、删除),而微服务是消息的一个消费者。

我一直遇到麻烦的地方是插入。我们大量使用数据库分配的标识符(身份 columns/auto-increment columns/sequences/surrogate 键),它们通常作为 post 请求的一部分分配并 returned 给调用者.协调层可能正在使用不同的微服务保存多个事物,并且通常需要从一个插入中分配的标识符,然后才能继续进行下一个操作。在协调层和微服务之间使用消息传递进行插入使得协调层无法从插入操作获得响应,因此它无法获得所需的分配标识符。此外,流上的其他消费者(即将数据发布到数据仓库的消费者)确实需要消息包含分配的标识符。

人们是如何处理这个问题的?数据库分配的标识符是微服务中的反模式吗?我们是否应该公开 return 数据库分配标识符的单独微服务端点,以便协调层可以在调用异步插入之前进行同步调用以获取标识符?我们可以使用 UUID,但我们的 DBA 讨厌将它们用作主键,并且它们不能用作订单号或其他面向用户的生成 ID。

如果您可以在从消息源接收时更早地以编程方式创建标识符,则可以将标识符嵌入为消息头的一部分,然后在数据库插入期间和任何其他使用者中使用消息头信息。

但是这种方法需要其他消费者针对数据库进行单独验证,以仅处理已提交的事务(如果您只关心处理插入)。

在我们公司,我们建立了一个专门的服务,负责生成唯一的 ID。其他所有服务都从那里获取他们需要的 ID。

这些生成的 ID 不能用作订单号,但我认为它不应该用于此工作。如果您需要按创建日期排序,最好有一个 created_date 字段。

还有一件事让我对这种方法感到困惑,那就是主要资源可能会在通过 ID 重新引用它的其他资源之后持久化。例如,插入用户和插入用户地址请求负载是异步发送的。插入用户负载包含生成的唯一 ID,用户地址负载包含该 ID 作为返回给用户的外部引用。插入用户地址可能在插入用户请求之前被处理,但这完全没问题。我认为这叫做最终一致性。