Kafka、MongoDB和反应式编程的增量价值

Kafka、MongoDB和反应式编程的增量价值,mongodb,apache-kafka,architecture,spring-data,reactive,Mongodb,Apache Kafka,Architecture,Spring Data,Reactive,很抱歉标题不好,但我想不出任何描述性的 我有一种设计问题,因此我需要增加我文档中关于上一条记录的字段的值,我的意思是,假设我有以下模型: @Document data class Example( @Id var id: String?=null, val count: Long, @Indexed(unique = true) val type: Enum(YES,NO) ) 这是我的存储库 interface ExampleRepository :

很抱歉标题不好,但我想不出任何描述性的

我有一种设计问题,因此我需要增加我文档中关于上一条记录的字段的值,我的意思是,假设我有以下模型:

@Document
data class Example(
    @Id
    var id: String?=null,
    val count: Long,
    @Indexed(unique = true)
    val type: Enum(YES,NO)
)
这是我的存储库

interface ExampleRepository : ReactiveSortingRepository<Example, String> {
    fun findOneByType(type: Enum): Mono<Example>
}
基本上,我有一个Kafka侦听器,它从主题获取请求并调用createOrIncrease方法,然后检查是否存在,增加计数如果不存在,它将创建一个默认值

现在,我的问题发生在我用Kafka多次发送同一个文档并从不同线程读取它时,所以在同一时间,所有人都试图找到他们无法找到的文档,因为这是第一次,然后他们尝试使用默认文档,MongoDB抛出重复错误。我正在努力寻找更好的方法来实现相同的功能,但在分布式系统中,这是在微服务体系结构中,多个微服务可以同时从不同的Kafka分区获取相同的文档

你知道我如何解决这个问题吗

我可以想出两种可能的解决办法:

  • 有一个临时集合并在那里插入,而不考虑任何重复项,然后有一个调度程序,每10分钟运行一次,聚合数据并清理数据库,但我正在寻找一种非调度程序的方法
  • producer将类型作为Kafka主题键发送,因此Kafka将把它放在同一个分区中,并且一个分区仅用于一个使用者,这意味着它将是连续的,但这意味着,producer需要了解下游问题,我正试图避免这种问题,以便进行更多的解耦设计
  • 在我的count字段中使用$inc mongodb,但我不知道这种方法的缺点
  • @Service
    class ExampleService(private val repository: ExampleRepository) {
    
        private val logger = LoggerFactory.getLogger(javaClass)
        
        fun createOrIncrease(type: Enum) = repository
            .findOneByType(type)
            .map { item ->
                logger.info("TEST - Found item $item")
                Example(item.id, item.count+1, item.type)
            }
            .defaultIfEmpty(Example(null, 1, NO))
            .flatMap { item ->
                logger.info("TEST - Saving item $item")
                repository
                    .save(item)
                    .retryWhen(Retry.backoff(3, Duration.ofSeconds(5)))
            }
    
    }