Apache Flink - 实现可能具有非常大状态的流处理器

时间:2017-03-28 18:21:30

标签: scala apache-flink flink-streaming

我希望从一系列事件中预测一个可能非常大的状态。这就是我以强制方式实现这一点的方式:

class ImperativeFooProcessor {

  val state: mutable.Map[UUID, BarState] = mutable.HashMap.empty[UUID, BarState]

  def handle(event: InputEvent) = {
    event match {
      case FooAdded(fooId, barId) => {
        // retrieve relevant state and do some work on it
        val barState = state(barId)

        // let the world know about what may have happened
        publish(BarOccured(fooId, barId))
        // or maybe rather
        publish(BazOccured(fooId, barId))
      }
      case FooRemoved(fooId, barId) => {
        // retrieve relevant state and do some work on it
        val barState = state(barId)

        // let the world know about what may have happened
        publish(BarOccured(fooId, barId))
        // or maybe rather
        publish(BazOccured(fooId, barId))
      }
    }
  }

  private def publish(event: OutputEvent): Unit = {
    // push event to downstream sink
  }
}

在最坏的情况下,BarState的大小会随着FooAdded

提及的次数而增长

相对于每个barId的事件总数,唯一barId的数量非常小。

我如何开始在Flink中表示这个处理结构?

我如何处理每个BarState可能变得非常大的事实?

1 个答案:

答案 0 :(得分:1)

Flink在所谓的州后端维持状态。有一些状态后端(MemoryStateBackendFsStateBackend)在工作进程的JVM堆上运行。这些后端不适合处理大型状态。

Flink还有一个RocksDBStateBackend,它基于RocksDB。 RocksDB在每个工作节点上用作本地数据库(无需将其设置为外部服务),并将状态数据写入磁盘。因此,它可以处理超出内存的非常大的状态。

Flink提供KeyedStream,这是一个在特定属性上分区的流。在您的情况下,您可能希望对同一个ID的所有访问都转到相同的状态实例,因此您可以使用barId作为键。然后,根据barId将状态划分为所有并行工作线程。这基本上是分布式键值存储或映射。因此,您不需要将状态表示为地图,因为它由Flink自动分发。