Apache flink 当TTL清除RocksDB列表状态时,Flink应用程序失败

Apache flink 当TTL清除RocksDB列表状态时,Flink应用程序失败,apache-flink,Apache Flink,每当TTL config清除列表状态时,一个使用来自2个Kafka主题的数据并加入相关事件的应用程序就会不断失败。平面图的逻辑与我所看到的大多数平面图略有不同。第一个流中的每个事件都可能与第二个流中的事件多次连接,因此这是一个一对多的上下文 这是连接的代码: val join = streamA .connect(streamB) .flatMap( new JoinOneToManyStreams[StreamA, StreamB]( "s

每当TTL config清除列表状态时,一个使用来自2个Kafka主题的数据并加入相关事件的应用程序就会不断失败。平面图的逻辑与我所看到的大多数平面图略有不同。第一个流中的每个事件都可能与第二个流中的事件多次连接,因此这是一个一对多的上下文

这是连接的代码:

val join = streamA
    .connect(streamB)
    .flatMap(
      new JoinOneToManyStreams[StreamA, StreamB](
        "streamA",
        "streamB",
        Time.minutes(3)
      )
    ).uid("join")
    .keyBy(_.streamB.id)
这是实现逻辑的类:

class JoinOneToManyStreams[A, B] (stateDescriptorA: String, stateDescriptorB: String, time: Time) extends RichCoFlatMapFunction[A, B, StateOut[A, B]] {
    val ttlConfig: StateTtlConfig = StateTtlConfig
        .newBuilder(time)
        // Set TTL just once
        .setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
        .setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
        .cleanupInRocksdbCompactFilter(1000)
        .build

    val streamAStateDescriptor = new ValueStateDescriptor[StateIn[A]](stateDescriptorA, classOf[StateIn[A]])
    streamAStateDescriptor.enableTimeToLive(ttlConfig)
    lazy val streamAState: ValueState[StateIn[A]] = getRuntimeContext.getState(streamAStateDescriptor)

    val streamBStateDescriptor = new ListStateDescriptor[StateIn[B]](stateDescriptorB, classOf[StateIn[B]])
    streamBStateDescriptor.enableTimeToLive(ttlConfig)
    lazy val streamBState: ListState[StateIn[B]] = getRuntimeContext.getListState(streamBStateDescriptor)

    override def flatMap1(streamA: A, out: Collector[StateOut[A, B]]): Unit = {
        streamAState.update(StateIn[A](stateValue = streamA))
        val stateB = streamBState.get
        if (stateB.nonEmpty) {
        streamBState.clear()
        stateB.forEach(row => {
            out.collect(StateOut(streamA, row.stateValue))
        })
        }
    }

    override def flatMap2(streamB: B, out: Collector[StateOut[A, B]]): Unit = {
        streamBState.add(StateIn(streamB))
        val stateA = streamAState.value
        if (stateA != null) {
        val stateB = streamBState.get
        streamBState.clear()
        stateB.forEach(row => {
            out.collect(StateOut(stateA.stateValue, row.stateValue))
        })
        }
    }
}
正如您所看到的,使用了cleanupInRocksdbCompactFilter,但我也尝试了fullSnapshot,发现了相同的行为

错误:

    Exception in thread "Thread-19" java.lang.IllegalArgumentException: classLoader cannot be null.
at com.esotericsoftware.kryo.Kryo.setClassLoader(Kryo.java:975)
at org.apache.flink.api.java.typeutils.runtime.kryo.KryoSerializer.checkKryoInitialized(KryoSerializer.java:477)
at org.apache.flink.api.java.typeutils.runtime.kryo.KryoSerializer.deserialize(KryoSerializer.java:337)
at org.apache.flink.api.common.typeutils.CompositeSerializer.deserialize(CompositeSerializer.java:151)
at org.apache.flink.contrib.streaming.state.ttl.RocksDbTtlCompactFiltersManager$ListElementFilter.nextElementLastAccessTimestamp(RocksDbTtlCompactFiltersManager.java:193)
at org.apache.flink.contrib.streaming.state.ttl.RocksDbTtlCompactFiltersManager$ListElementFilter.nextUnexpiredOffset(RocksDbTtlCompactFiltersManager.java:180)

我知道列表状态是问题所在,因为我禁用了这种状态的tll,问题停止了。有什么方法可以让它工作吗?

streamA和streamB都是键控流吗?它们是如何键入的?是的,它们是。val streamA=env.addSource(streamAConsumer).keyBy(u.id)这是中报告和讨论的错误。另见,明白了。建议的解决方法是使用基本类型或POJO来避免此问题。状态列表中的状态是StateIn类型,它只有一个名为StateValue的参数。由于StateIn是一个case类,它不被认为是一个POJO吗?不。case类不是POJO,而且泛型类型(和类型擦除)会给Flink的类型推理系统带来问题。