Kafka Streams PAPI:AbstractProcessor对象创建行为

时间:2019-06-17 09:47:19

标签: scala apache-kafka apache-kafka-streams

我有一个Kafka Streams拓扑,其中包含一个AbstractProcessor(实际上是两个)。 在其中之一中,我将Punctuation APIWALL_CLOCK_TIME结合使用,以调度刷新一些需要处理的参考数据。 我在任务开始时就这样做,然后每隔一段时间安排一次(比如说1小时)。 num.stream.threads配置为2。

例如我有一些这样的代码:

def loadReferenceData() = {
      logger.info("Loading All Reference Data...")
      // atomically (re)load some data
}

override def init(context: ProcessorContext) = {
      super.init(context)
      logger.info("Loading reference data initially...")
      loadReferenceData()

      context.schedule(1000 * reloadDataSeconds, PunctuationType.WALL_CLOCK_TIME, (timestamp) => {
        loadReferenceData()
        context.commit(); // Unsure if necessary
      });
}

没有传入记录,在正在运行的应用程序上的单个实例的日志中,我可以看到这些日志用于初始化:

    [2019-06-11 08:54:19,518] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 08:53:31,080] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 08:53:29,713] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 08:53:29,682] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:54:20,855] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:54:19,714] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:54:19,516] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:53:31,036] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:53:29,668] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 07:53:29,653] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 06:54:20,845] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)
    [2019-06-11 06:54:19,726] INFO Loading All Reference Data... (com.divvit.dp.streams.applications.StreamProcessor)

因此,似乎每小时都有很多日志用于输入loadReferenceData。我希望每小时只能看到2个条目(2个线程),但是更多(通常是6个)。

在日志中,我在创建应用程序开始时只看到6次创建处理器:

[2019-06-10 16:54:19,849] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)
[2019-06-10 16:54:18,231] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)
[2019-06-10 16:54:17,874] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)
[2019-06-10 16:53:29,675] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)
[2019-06-10 16:53:27,132] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)
[2019-06-10 16:53:24,923] INFO Loading reference data initially... (com.divvit.dp.streams.applications.StreamProcessor)

所以这很有意义:处理器创建一次,每小时创建一次,它将更新。

但是,当我在应用程序中增加更多的负载时,我会经常看到创建新的Processor对象。

  • 在什么情况下,Kafka Streams会创建这些处理器的新实例?
  • 如何知道我的应用程序实例将创建多少个处理器实例?
  • 如果可以根据Kafka Streams的判断来关闭/创建处理器,那么对于这些​​“外部”操作来说,标点API似乎是过大的(或者不是为此目的而设计的),而单独的定期更新线程会更好地解决这一问题,不是吗?

1 个答案:

答案 0 :(得分:1)

Kafka-Streams将在输入主题的每个分区上创建一个处理器,每个处理器都有自己的时间表。 (如果您使用状态存储,这实际上非常有用,因为状态也会被分区。)

如果要对内部状态应用常规操作,则调度程序很有用。它很好地停止了常规处理,并确保您在计划操作期间所做的所有操作都是一致的。如果手头的任务与流本身无关,那么单独的线程可能也不错。

如果选择单独的线程,请确保在kafka-streams thread crashes时适当地杀死它。否则,您的应用程序将挂在计时器线程上,但不会消耗任何kafka消息。

增加线程数(num.stream.threads)意味着将同时使用多个分区。它具有与启动多个彼此相邻的实例相同的行为。参见https://docs.confluent.io/current/streams/architecture.html#threading-model