Apache spark 基于流的应用程序中的受控/手动错误/恢复处理

Apache spark 基于流的应用程序中的受控/手动错误/恢复处理,apache-spark,error-handling,apache-kafka,stream,apache-flink,Apache Spark,Error Handling,Apache Kafka,Stream,Apache Flink,我正在开发一个基于ApacheFlink的应用程序,它使用ApacheKafka进行输入和输出。这个应用程序可能会被移植到apachespark,所以我也添加了这个标签,问题仍然是一样的 我要求通过kafka接收的所有传入消息都必须按顺序处理,并且安全地存储在持久层(数据库)中,并且任何消息都不得丢失 此应用程序中的流式处理部分相当琐碎/小,因为主要逻辑可以归结为: environment.addSource(consumer) // 1) DataStream[Option[Elem]]

我正在开发一个基于ApacheFlink的应用程序,它使用ApacheKafka进行输入和输出。这个应用程序可能会被移植到apachespark
,所以我也添加了这个标签,问题仍然是一样的

我要求通过kafka接收的所有传入消息都必须按顺序处理,并且安全地存储在持久层(数据库)中,并且任何消息都不得丢失

此应用程序中的流式处理部分相当琐碎/小,因为主要逻辑可以归结为:

environment.addSource(consumer)    // 1) DataStream[Option[Elem]]
  .filter(_.isDefined)             // 2) discard unparsable messages
  .map(_.get)                      // 3) unwrap Option
  .map(InputEvent.fromXml(_))      // 4) convert from XML to internal representation
  .keyBy(_.id)                     // 5) assure in-order processing on logical-key level
  .map(new DBFunction)             // 6) database lookup, store of update and additional enrichment
  .map(InputEvent.toXml(_))        // 7) convert back to XML
  .addSink(producer)               // 8) attach kafka producer sink
现在,在这个管道中,可能会出现以下几种错误情况:

  • 数据库变得不可用(关闭、表空间已满等)
  • 由于逻辑错误(来自列格式),无法存储更改
  • 由于代理不可用,卡夫卡制作人无法发送消息
可能还有其他情况

现在我的问题是,在这些情况下,我如何确保一致性,而事实上,我必须做以下事情:

environment.addSource(consumer)    // 1) DataStream[Option[Elem]]
  .filter(_.isDefined)             // 2) discard unparsable messages
  .map(_.get)                      // 3) unwrap Option
  .map(InputEvent.fromXml(_))      // 4) convert from XML to internal representation
  .keyBy(_.id)                     // 5) assure in-order processing on logical-key level
  .map(new DBFunction)             // 6) database lookup, store of update and additional enrichment
  .map(InputEvent.toXml(_))        // 7) convert back to XML
  .addSink(producer)               // 8) attach kafka producer sink
  • 流操作员6)检测到问题(数据库不可用)
  • 必须恢复
    DBFunction
    对象的数据库连接,这可能需要几分钟后才能成功
  • 这意味着必须暂停整个处理,最好是暂停整个管道,以便将传入消息批量加载到内存中
  • 恢复数据库后恢复处理。处理必须与在1)处遇到问题的消息完全恢复
  • 现在我知道关于故障处理至少有两种工具:

  • 卡夫卡消费补偿
  • 阿帕奇·弗林克检查站
  • 然而,在搜索文档时,我看不到从一个操作符中可以在流处理的中间使用任何一个。 那么,对于流媒体应用程序中的细粒度错误处理和恢复,建议采用哪些策略?

    以下几点:

    keyBy不会帮助确保订单处理的有序性。如果有什么区别的话,它可能会交错来自不同卡夫卡分区(每个分区内可能都是有序的)的事件,从而在以前不存在的地方造成无序。如果不了解您打算使用多少FlinkKafkaConsumer实例,每个实例将从多少个分区中使用,密钥如何分布在Kafka分区中,就很难更具体地评论您如何保证按顺序处理,以及为什么您认为有必要设置钥匙孔——但如果您设置正确,保持秩序可能是可以实现的。这可能会有所帮助,但此功能很难理解,并且很难正确使用

    您可以使用Flink以容错的方式管理到外部DB的连接,只需一次


    Flink不支持系统化的细粒度恢复——它的检查点是整个分布式集群状态的全局快照,设计用于在恢复期间作为一个整体的、自一致的快照使用。如果作业失败,通常唯一的办法是从检查点重新启动,这将涉及到倒带输入队列(到检查点中存储的偏移量),重放这些偏移量之后的事件,重新发出DB查找(异步函数将自动执行),并使用kafka事务实现端到端的精确语义。然而,在令人尴尬的平行工作的情况下,有时可以利用

    我的理解是,
    keyBy
    导致始终由相同的操作符实例处理相同的键,无论并行性如何,从而确保在操作符范围内进行有序处理。当然,
    keyBy
    永远无法使通过卡夫卡提供的东西正常运转。我在这方面的要求很简单:必须按顺序处理具有相同逻辑键的消息,并且由我决定如何设置kafka主题、使用者和flink应用程序。目前,正好有1个
    FlinkKafkaConsumer011
    实例。。。。和一个关于这个主题的分区。关于恢复:当然,该应用程序将是一个全天候的在线应用程序,而且很可能在任何时候都没有可用的人工支持。因此,如果出现故障(=手动任务),仅依靠从检查点重新启动不是一条出路。我更愿意尝试在所有情况下实现一个稳定的实现,它不需要用户交互,或者在最坏的情况下,在错误无法恢复的情况下使一切停止。这就是我的问题,如何让一切自动停止。更准确地说,我不了解flink在以下情况下会发生什么:1)操作员线程因陷入试图恢复数据库连接的循环而被阻塞2)操作员线程因检测到无法恢复的错误而被阻塞,处理必须停止。这个主题有点复杂,因为我所有的操作员都是无状态的,但我很可能会按照这里给出的Fabian Hueske的建议:并实现事务处理。从检查点重新启动是一个完全自动的过程,您可以对自动重新启动策略进行一定程度的控制。不需要人工干预。如果您确保对于任何给定的密钥,其所有事件都在同一个kafka分区中,则它们将自然保持有序,因为它们都将被同一FlinkKafkaConsumer011实例使用。在这种情况下,keyBy不会将它们与来自其他分区的相同密钥的事件一起洗牌(这将导致无序)。