学习Flink的ProcessFunction过程中,官方文档中涉及状态处理的时候,不止一次提到只适用于keyed stream的元素,如下图红框所示:

flink简单理解(深入了解ProcessFunction的状态操作)(1)

之前写过一些flink应用,keyed stream常用但不是必须用的,所以产生了疑问:

  1. 为何只有keyed stream的元素能读写状态?
  2. 每个key对应的状态是如何操作的?
Flink的"状态"

flink简单理解(深入了解ProcessFunction的状态操作)(2)

flink简单理解(深入了解ProcessFunction的状态操作)(3)

官方demo

为了学习ProcessFunction就去看官方demo,地址是:https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/stream/operators/process_function.html ,简单说说这个demo的功能:

以上就是官方demo的功能,本来是想通过demo来加深认识,结果看完不但没有明白,反而更晕了,下图是我对demo代码的疑惑:

flink简单理解(深入了解ProcessFunction的状态操作)(4)

从上图可见我的疑惑,这里再复述一下:

  1. 入参value是Tuple2类型,假设其f0字段等于aaa,那么processElement方法的作用,就是取出aaa的状态,更新后保存;
  2. 从代码上看,state.value()返回了aaa的状态,这个value方法并没有将aaa作为入参,那怎么做到返回aaa的状态呢?如果下一个入参value的f0字段等于bbb了,这个state.value()能返回bbb的状态吗?
  3. 对更新状态的代码state.update(current)也是同样的疑惑;
  4. 然后又产生了新的疑惑:成员变量state难道是一直在变?每执行一次processElement,都会变成该key对应的state实例?
先反思为何会有上述疑惑

flink简单理解(深入了解ProcessFunction的状态操作)(5)

跟踪源码

flink简单理解(深入了解ProcessFunction的状态操作)(6)

flink简单理解(深入了解ProcessFunction的状态操作)(7)

flink简单理解(深入了解ProcessFunction的状态操作)(8)

flink简单理解(深入了解ProcessFunction的状态操作)(9)

flink简单理解(深入了解ProcessFunction的状态操作)(10)

flink简单理解(深入了解ProcessFunction的状态操作)(11)

flink简单理解(深入了解ProcessFunction的状态操作)(12)

flink简单理解(深入了解ProcessFunction的状态操作)(13)

flink简单理解(深入了解ProcessFunction的状态操作)(14)

flink简单理解(深入了解ProcessFunction的状态操作)(15)

  • 代码读到这里,只剩最后一处需要印证了:更新状态的state.update(current)方法,应该也是以StateBackend的keyContext中的key作为自己的key,再将入参的current作为value,更新到stateMap中,来吧,一起印证这个推测;
  • 展开方法,看到的是stateTable.put方法(前面刚看过stateTable的get方法,稳了):
  • flink简单理解(深入了解ProcessFunction的状态操作)(16)

  • stateTable.put方法里面和前面的get方法一样,直接拿keyContext保存的key作为自己的key:
  • flink简单理解(深入了解ProcessFunction的状态操作)(17)

    flink简单理解(深入了解ProcessFunction的状态操作)(18)

    得益于Flink代码自身规范、清晰的设计和实现,再加上IDEA强大的debug功能,整个阅读和分析过程十分顺利,这其中的收获会逐渐在今后深入学习DataStreamAPI的过程中见效;

    最后,根据上面的分析过程绘制了一幅简陋的流程图,希望能帮助您加快理解:

    flink简单理解(深入了解ProcessFunction的状态操作)(19)

    欢迎关注我的公众号:程序员欣宸

    flink简单理解(深入了解ProcessFunction的状态操作)(20)

    ,