flink--state状态管理

前提:

1 flink state分为三种,1)operator state是跟算子关联的,粒度是task,即便相同的算子的其他并行的task也不能互相访问各自的状态。 2)keyed state是跟key stream关联的。粒度是key,相同的task不同key的数据状态不共享,只有相同key才可以共享状态。, 3)broadcast state, 分为批Set的广播状态和流stream的流合并,一个广播流,一个事实流。

当Flink左右从checkpoint恢复,或者从savepoint中重启的时候,就回涉及到状态的重新分配,尤其是当并行度发生改变的时候。

Operator State Redistribute

当operator改变并行度的时候(Rescale),会触发状态的Redistribute,即Operator State里的数据会重新分配到Operator的Task实例。这里有三种方式,举例说明平行度由3改为2

1 这个是普通的ListState, 原先所有State中的元素均匀划分给新的Task

2 这个是UnionList State,所有的State中的元素全部分配给新的Task

3 还有一张是BroadState State,所有Task上的State都是一样的,新的Task获得State的一个备份。

选择方式:

由于是operate state所以只能在operate中使用,并且由于是state从checkpoint中的重分配,所以对应的类必须实现CheckpointedFunction接口。如下图方式应用,这样就会初始化ListState了,就可以不用在open方法里初始化了。

public class BufferingSink
        implements SinkFunction<Tuple2<String, Integer>>,
                   CheckpointedFunction {

    private final int threshold;

    private transient ListState<Tuple2<String, Integer>> checkpointedState;

    private List<Tuple2<String, Integer>> bufferedElements;

    public BufferingSink(int threshold) {
        this.threshold = threshold;
        this.bufferedElements = new ArrayList<>();
    }

    @Override
    public void invoke(Tuple2<String, Integer> value) throws Exception {
        bufferedElements.add(value);
        if (bufferedElements.size() == threshold) {
            for (Tuple2<String, Integer> element: bufferedElements) {
                // send it to the sink
            }
            bufferedElements.clear();
        }
    }

    @Override
    public void snapshotState(FunctionSnapshotContext context) throws Exception {
        checkpointedState.clear();
        for (Tuple2<String, Integer> element : bufferedElements) {
            checkpointedState.add(element);
        }
    }

    @Override
    public void initializeState(FunctionInitializationContext context) throws Exception {
        ListStateDescriptor<Tuple2<String, Integer>> descriptor =
            new ListStateDescriptor<>(
                "buffered-elements",
                TypeInformation.of(new TypeHint<Tuple2<String, Integer>>() {}));

        checkpointedState = context.getOperatorStateStore().getListState(descriptor);
//在这里选择模式,getListState或者getUnionListState

        if (context.isRestored()) {
            for (Tuple2<String, Integer> element : checkpointedState.get()) {
                bufferedElements.add(element);
            }
        }
    }
}

Keyed State Redistribute

对于Keyed State就比较好处理了,对应的Key被Redistribute到哪个task,对应的keyed state就被Redistribute到哪个Task

Keyed state redistribute是基于Key Group来做分配的:

    将key分为group
    每个key分配到唯一的group
    将group分配给task实例
    Keygroup由最大并行度的大小所决定

Keyed State最终被分配到哪个Task,需要经过一下三个步骤:

    hash = hash(key)
    KeyGroup = hash%numOfKeyGroups
    SubTask=KeyGroup*parallelism/numOfKeyGroups
 

小结

  • flink有两种基本的state,分别是Keyed State以及Operator State(non-keyed state);其中Keyed State只能在KeyedStream上的functions及operators上使用;每个operator state会跟parallel operator中的一个实例绑定;Operator State支持parallelism变更时进行redistributing
  • Keyed State及Operator State都分别有managed及raw两种形式,managed由flink runtime来管理,由runtime负责encode及写入checkpoint;raw形式的state由operators自己管理,flink runtime无法了解该state的数据结构,将其视为raw bytes;所有的datastream function都可以使用managed state,而raw state一般仅限于自己实现operators来使用
  • stateful function可以通过CheckpointedFunction接口或者ListCheckpointed接口来使用managed operator state;CheckpointedFunction定义了snapshotState、initializeState两个方法;每当checkpoint执行的时候,snapshotState会被调用;而initializeState方法在每次用户定义的function初始化的时候(第一次初始化或者从前一次checkpoint recover的时候)被调用,该方法不仅可以用来初始化state,还可以用于处理state recovery的逻辑
  • 对于manageed operator state,目前仅仅支持list-style的形式,即要求state是serializable objects的List结构,方便在rescale的时候进行redistributed;关于redistribution schemes的模式目前有两种,分别是Even-split redistribution(在restore/redistribution的时候每个operator仅仅得到整个state的sublist)及Union redistribution(在restore/redistribution的时候每个operator得到整个state的完整list)
  • FunctionSnapshotContext继承了ManagedSnapshotContext接口,它定义了getCheckpointId、getCheckpointTimestamp方法;FunctionInitializationContext继承了ManagedInitializationContext接口,它定义了isRestored、getOperatorStateStore、getKeyedStateStore方法,可以用来判断是否是在前一次execution的snapshot中restored,以及获取OperatorStateStore、KeyedStateStore对象

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章