Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache kafka 如何忽略Kafka Streams应用程序中读取和写入同一主题中不同事件类型的某些消息_Apache Kafka_Spring Cloud_Avro_Apache Kafka Streams_Spring Cloud Stream - Fatal编程技术网

Apache kafka 如何忽略Kafka Streams应用程序中读取和写入同一主题中不同事件类型的某些消息

Apache kafka 如何忽略Kafka Streams应用程序中读取和写入同一主题中不同事件类型的某些消息,apache-kafka,spring-cloud,avro,apache-kafka-streams,spring-cloud-stream,Apache Kafka,Spring Cloud,Avro,Apache Kafka Streams,Spring Cloud Stream,让我们假设一个Spring Cloud Stream应用程序从一个订单主题创建一个KStream。它感兴趣的是OrderCreated{“id”:x,“productId”:y,“customerId”:z}事件。一旦有人到达,它将对其进行处理并生成输出事件OrderShipped{“id”:x,“productId”:y,“customerName”:您可以使用Kafka的记录头来存储记录的类型。请参阅。您可以在中设置头 处理过程如下: 从主题中读取值为serdeSerdes.BytesSer

让我们假设一个Spring Cloud Stream应用程序从一个
订单主题创建一个
KStream
。它感兴趣的是
OrderCreated{“id”:x,“productId”:y,“customerId”:z}
事件。一旦有人到达,它将对其进行处理并生成输出事件
OrderShipped{“id”:x,“productId”:y,“customerName”:您可以使用Kafka的记录头来存储记录的类型。请参阅。您可以在中设置头

处理过程如下:

  • 从主题中读取值为serde
    Serdes.BytesSerde
    的类型为
    KStream
  • 用于筛选和创建对象。更具体地说,在
    transformValues()
    中,您可以访问包含记录类型信息的记录标题。然后:

    • 如果类型为
      OrderShipped
      ,则返回
      null
    • 否则,从
      Bytes
      对象创建一个
      OrderCreated
      对象并返回它
  • 对于使用AVRO的解决方案,您可能需要查看以下文档


    我接受了布鲁诺的答案,认为这是解决这个问题的有效方法。不过,我认为我已经想出了一种更直接/更合理的方法,使用带有
    JsonTypeInfo
    注释的事件层次结构

    首先,您需要一个Order事件的基类,并指定所有子类。请注意,JSON文档中将添加一个type属性,这将有助于Jackson封送/解封DTO:

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes(value = [
        JsonSubTypes.Type(value = OrderCreatedEvent::class, name = "orderCreated"),
        JsonSubTypes.Type(value = OrderShippedEvent::class, name = "orderShipped")
    ])
    abstract class OrderEvent
    
    data class OrderCreatedEvent(var id: Int?, var productId: Int?, var customerId: Int?) : OrderEvent() {
        constructor() : this(null, null, null)
    }
    
    data class OrderShippedEvent(var id: Int?, var productId: Int?, var customerName: String?, var customerAddress: String?) : OrderEvent () {
        constructor() : this(null, null, null, null)
    }
    
    有了它,OrderCreatedEvent对象的生产者将生成如下消息:

    interface ShippingKStreamProcessor {
        ...
        @Input("order")
        fun order(): KStream<String, OrderCreated>
    
        @Output("output")
        fun output(): KStream<String, OrderShipped>
    
    key:1值:{“type”:“orderCreated”,“id”:1,“productId”:24,“customerId”:1}

    现在轮到KStream了。我已经将签名更改为
    KStream
    ,因为它可以接收OrderCreatedEvent或OrderShippedEvent。在接下来的两行中

    orderEvent.filter { _, value -> value is OrderCreatedEvent }
                    .map { key, value -> KeyValue(key, value as OrderCreatedEvent) }
    
    …我筛选以仅保留OrderCreatedEvent类的消息,并将它们映射为将
    KStream
    转换为
    KStream

    完整的KStream逻辑:

    @StreamListener
    @SendTo("output")
    fun process(@Input("input") input: KStream<Int, Customer>, @Input("order") orderEvent: KStream<Int, OrderEvent>): KStream<Int, OrderShippedEvent> {
    
            val intSerde = Serdes.IntegerSerde()
            val customerSerde = JsonSerde<Customer>(Customer::class.java)
            val orderCreatedSerde = JsonSerde<OrderCreatedEvent>(OrderCreatedEvent::class.java)
    
            val stateStore: Materialized<Int, Customer, KeyValueStore<Bytes, ByteArray>> =
                    Materialized.`as`<Int, Customer, KeyValueStore<Bytes, ByteArray>>("customer-store")
                            .withKeySerde(intSerde)
                            .withValueSerde(customerSerde)
    
            val customerTable: KTable<Int, Customer> = input.groupByKey(Serialized.with(intSerde, customerSerde))
                    .reduce({ _, y -> y }, stateStore)
    
    
            return (orderEvent.filter { _, value -> value is OrderCreatedEvent }
                    .map { key, value -> KeyValue(key, value as OrderCreatedEvent) }
                    .selectKey { _, value -> value.customerId } as KStream<Int, OrderCreatedEvent>)
                    .join(customerTable, { orderIt, customer ->
                        OrderShippedEvent(orderIt.id, orderIt.productId, customer.name, customer.address)
                    }, Joined.with(intSerde, orderCreatedSerde, customerSerde))
                    .selectKey { _, value -> value.id }
                    //.to("order", Produced.with(intSerde, orderShippedSerde))
        }
    
    @StreamListener
    @发送到(“输出”)
    趣味流程(@Input(“Input”)Input:KStream,@Input(“order”)orderEvent:KStream):KStream{
    val intSerde=Serdes.IntegerSerde()
    val customerSerde=JsonSerde(Customer::class.java)
    val orderCreatedSerde=JsonSerde(OrderCreatedEvent::class.java)
    val stateStore:具体化=
    具体化。`as`(“客户商店”)
    .withKeySerde(intSerde)
    .withValueSerde(customerSerde)
    val customerTable:KTable=input.groupByKey(序列化.with(intSerde,customerSerde))
    .reduce({uu,y->y},stateStore)
    返回(orderEvent.filter{},值->值为OrderCreatedEvent}
    .map{key,value->KeyValue(key,值为OrderCreatedEvent)}
    .selectKey{{,value->value.customerId}作为KStream)
    .join(customerTable,{orderIt,customer->
    OrderShippedEvent(orderIt.id、orderIt.productId、customer.name、customer.address)
    },加入。使用(intSerde、orderCreatedSerde、customerSerde))
    .selectKey{{,value->value.id}
    //.to(“订单”,由(intSerde、orderShippedSerde)生成)
    }
    

    在此过程之后,我将在订单主题中生成一条新消息
    key:1值:{“type”:“orderShipped”,“id”:1,“productId”:24,“customerName”:“Anna”,“customerAddress”:“Cipress Street”}
    ,但这将被流过滤掉。

    为什么
    KStream.filter()
    对你不起作用吗?因为所有内容都在卡夫卡主题中,那些
    订单发货
    仍将提供给该主题的其他消费者。正如@ArtemBilan提到的,这应该是可以通过
    过滤器控制的。如果你能分享更多代码,我们可以看看。我已经更新了问题的更多细节我认为你的解决方案可以很好地解决问题,但我对此表示怀疑(ValueTransformerSupplier状态存储可以省略。如果所有事件类型都已知,这对我来说很好。但是,有没有关于如何处理/忽略未知类型事件的建议?例如,可能有一个
    OrderDeletedEvent
    ,消费者服务应该忽略它,因为它不相关。在这种情况下,我不想包括取消附加的、不必要的
    OrderDeletedEvent
    类。一种解决方案是记录错误并通过配置
    org.apache.kafka.streams.errors.LogAndContinueExceptionHandler
    继续处理,但这意味着忽略所有可能不需要的反序列化异常。
    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes(value = [
        JsonSubTypes.Type(value = OrderCreatedEvent::class, name = "orderCreated"),
        JsonSubTypes.Type(value = OrderShippedEvent::class, name = "orderShipped")
    ])
    abstract class OrderEvent
    
    data class OrderCreatedEvent(var id: Int?, var productId: Int?, var customerId: Int?) : OrderEvent() {
        constructor() : this(null, null, null)
    }
    
    data class OrderShippedEvent(var id: Int?, var productId: Int?, var customerName: String?, var customerAddress: String?) : OrderEvent () {
        constructor() : this(null, null, null, null)
    }
    
    orderEvent.filter { _, value -> value is OrderCreatedEvent }
                    .map { key, value -> KeyValue(key, value as OrderCreatedEvent) }
    
    @StreamListener
    @SendTo("output")
    fun process(@Input("input") input: KStream<Int, Customer>, @Input("order") orderEvent: KStream<Int, OrderEvent>): KStream<Int, OrderShippedEvent> {
    
            val intSerde = Serdes.IntegerSerde()
            val customerSerde = JsonSerde<Customer>(Customer::class.java)
            val orderCreatedSerde = JsonSerde<OrderCreatedEvent>(OrderCreatedEvent::class.java)
    
            val stateStore: Materialized<Int, Customer, KeyValueStore<Bytes, ByteArray>> =
                    Materialized.`as`<Int, Customer, KeyValueStore<Bytes, ByteArray>>("customer-store")
                            .withKeySerde(intSerde)
                            .withValueSerde(customerSerde)
    
            val customerTable: KTable<Int, Customer> = input.groupByKey(Serialized.with(intSerde, customerSerde))
                    .reduce({ _, y -> y }, stateStore)
    
    
            return (orderEvent.filter { _, value -> value is OrderCreatedEvent }
                    .map { key, value -> KeyValue(key, value as OrderCreatedEvent) }
                    .selectKey { _, value -> value.customerId } as KStream<Int, OrderCreatedEvent>)
                    .join(customerTable, { orderIt, customer ->
                        OrderShippedEvent(orderIt.id, orderIt.productId, customer.name, customer.address)
                    }, Joined.with(intSerde, orderCreatedSerde, customerSerde))
                    .selectKey { _, value -> value.id }
                    //.to("order", Produced.with(intSerde, orderShippedSerde))
        }