使用 Kafka Streams 发送带有聚合警报的电子邮件

时间:2021-04-12 09:33:55

标签: apache-kafka apache-kafka-streams

我有一个简单的用例:汇总一段时间(1 分钟)内的警报,然后发送一封电子邮件,其中包含在此期间发生的所有警报。

因此,总的来说,我可以毫无问题地定义一个窗口、聚合用户的警报并使用 Kafka Streams 发送电子邮件。如果警报定期出现,它就像一个魅力。如果没有更多警报,将永远不会触发发送电子邮件。原因很明显:Kafka Streams 逻辑是由传入事件触发的。因此,如果主题中没有新事件 - 什么都不会发生。

这是一个简单的用例,显示了问题:

Time: 0:00:00
-> Event 1
-> Event 2
-> Event 3
Time: 0:01:00
-> Event 4 (This will trigger email with events 1,2,3)

因此,如果没有事件 4 - 将永远不会发送任何电子邮件。

我的解决方案之一是编写自定义处理器并定义将发送电子邮件的调度程序。理想情况下,我仍然会使用官方 Kafka API 进行分组和聚合,并且仅使用调度程序逻辑发送电子邮件。在这种情况下,我似乎需要将 kvStore 共享给处理器(java)。不幸的是,我没有找到关于该用例的任何有据可查的文章。

我还尝试将所有内容“委托”到处理器上(将新事件添加到自定义定义的存储中,查看所有事件,发送电子邮件并从存储中删除已发送的事件),但看起来并不“干净”对我来说。

    var kvStore: KeyValueStore<Window, AlertNotificationMessage>? = null

    override fun init(context: ProcessorContext) {
        kvStore = context.getStateStore(AlertMessageProcessorSupplier.STORE_NAME)
            as KeyValueStore<Window, AlertNotificationMessage>
        context.schedule(
            Duration.ofSeconds(AlertProcessor.AGGREGATION_SECONDS),
            PunctuationType.WALL_CLOCK_TIME,
            this::sendNotification
        )
    }

    override fun process(key: Windowed<String>, value: AlertNotificationMessage) {
        kvStore?.put(
            Window(key.key(), key.window().start(), key.window().end()),
            value
        )
    }

    private fun sendNotification(callTime: Long) {
        kvStore?.all()?.forEach {
            if (it.key.endMs < callTime) {
                notificationService.send(it.key.recipientId, it.value)
                kvStore?.delete(it.key)
            }
        }
    }

有没有人有类似的用例和任何在多分区/故障转移环境中也有效的好的解决方案?

1 个答案:

答案 0 :(得分:0)

我有类似的用例。解决办法如下:

  1. 创建一个简单的生产者应用,以在每分钟的第一秒在每个分区中生成假警报。

    现在警报流:

    时间:0:00:00

    -> 假事件(分区 0~N)

    -> 事件 1

    -> 事件 2

    -> 事件 3

    时间:0:01:00

    -> 假事件(分区 0~N)

    -> 事件 4(这将触发带有事件 1、2、3 的电子邮件)

    时间:0:02:00

    -> 假事件(分区 0~N)

  2. 在kafka流应用中,聚合窗口时忽略假事件