Kafka流用例以添加全局存储

时间:2019-11-25 10:43:27

标签: java apache-kafka apache-kafka-streams

在kafka流中定义拓扑时,可以添加全局状态存储。它需要一个源主题以及一个ProcessorSupplier。 处理器接收记录,并可以在理论上对其进行转换,然后再将其添加到存储中。但是,在进行还原的情况下,记录将直接从源主题(更改日志)插入到全局状态存储中,从而跳过了最终在处理器中完成的转换。

   +-------------+             +-------------+              +---------------+
   |             |             |             |              |    global     |
   |source topic  ------------->  processor  +-------------->    state      |
   |(changelog)  |             |             |              |    store      |
   +-------------+             +-------------+              +---------------+
          |                                                         ^
          |                                                         |
          +---------------------------------------------------------+
              record directly inserted during restoration

StreamsBuilder#addGlobalStore(StoreBuilder storeBuilder, String topic, Consumed consumed, ProcessorSupplier stateUpdateSupplier)将全局StateStore添加到拓扑。

根据文档

  

注意:您不应使用处理器将已转换的记录插入全局状态存储。该存储使用源主题作为变更日志,并且在还原过程中将直接直接从源插入记录。应该使用此ProcessorNode来保持StateStore的最新状态。

同时,由于主要错误已在kafka错误跟踪器KAFKA-7663 Custom Processor supplied on addGlobalStore is not used when restoring state from topic上打开,该错误确切解释了文档中所述的内容,但似乎是可以接受的错误。

我想知道KAFKA-7663是否确实是一个错误。根据文档,它似乎是这样设计的,在这种情况下,我很难理解用例。
有人可以解释这个底层API的主要用例吗?我唯一能想到的就是处理副作用,例如在处理器中执行一些日志操作。

奖励问题:如果源主题充当全局存储的变更日志,则由于保留已过期而从主题中删除记录时,是否会将其从全局状态存储中删除?还是仅在从更改日志中对整个商店进行还原之后,才会在商店中进行删除。

2 个答案:

答案 0 :(得分:5)

是的,这是一个很奇怪的小问题22,但是文档是正确的。全局状态存储的处理器不得对记录做任何事情,而应将其持久存储到存储中。

AFAIK,这不是一个哲学问题,只是一个实际问题。原因仅仅是您观察到的行为... Streams将输入主题视为商店的changelog主题,因此在还原过程中会绕过处理器(以及反序列化)。

状态恢复绕过任何处理的原因是通常更改日志中的数据与存储中的数据相同,因此对它进行任何新操作实际上都是错误的。另外,仅将字节从线中删除并将它们批量写入状态存储中就更有效。我之所以说“通常”,是因为在这种情况下,输入主题与普通的changelog主题并不完全一样,因为在存储放置期间它不会接收其写入。

对于它的价值,我也很难理解用例。看来,我们应该:

  1. 完全摆脱该处理器,就像恢复一样,总是将二进制数据从网络中转储到存储中。
  2. 重新设计全局存储,以允许在全局存储之前进行任意转换。我们可以:
    • 在还原过程中也继续使用输入主题并反序列化并调用处理器,或者
    • 为全局商店添加 real 更改日志,以便我们轮询输入主题,应用一些转换,然后写入全局商店 -变更日志。然后,我们可以使用变更日志(而非输入)进行还原和复制。

顺便说一句,如果您想要后者的行为,则可以立即应用转换,然后使用to(my-global-changelog)来制造一个“ changelog”主题,以近似其行为。然后,您将创建全局存储区以从my-global-changelog而不是输入中读取内容。

因此,为了给您一个直接的答案,KAFKA-7663不是错误。我将对建议将票证转换为功能请求的票证进行评论。

奖励答案:用作状态存储的变更日志的主题绝不能进行保留配置。实际上,这意味着您应该通过启用压缩来防止无限增长,并禁用日志保留。

在实践中,旧数据丢失并丢失并不是一个“事件”,并且消费者无法知道是否/何时发生。因此,无法响应此非事件而从状态存储中删除数据。就像您描述的那样,它将发生……记录将无限期地存在于全局存储中。如果/当替换实例时,新实例将从输入中恢复,并且(显然)仅接收当时该主题中存在的记录。因此,整个Streams集群将在全局状态不一致的情况下结束。这就是为什么您应该禁用保留功能。

从存储中“删除”旧数据的正确方法是将所需键的逻辑删除写入输入主题。然后,它将正确传播到群集的所有成员,在还原过程中正确应用,并由代理正确压缩。

我希望这对您有所帮助。肯定的,请输入票证,并帮助我们使API更加直观!

答案 1 :(得分:0)

目前似乎没有一种方法可以监听KGlobalTable上的更改。

使用全局存储和自定义处理器可以达到类似的结果。

我在How to be notified about updates to state store of GlobalKTable?

上偶然发现了这个

我并不是说这是一个好的用例,但是作为一种变通办法,它可能会有所帮助。