【Flink状态】FsStateBackend 下 ValueState > MapState
背景:
对程序进行状态后端替换(Rocks —> Fs)时,程序产生了背压。(状态开启了TTL)
分析办法:
利用Arthas生成CPU采样火焰图,分析是否存在性能瓶颈。
分析过程
发现问题
CPU火焰图

明显看出来,程序在处理MapState时,进行TTL处理时,花费了大量时间,成为了性能瓶颈。
程序主要处理逻辑(已模糊化):
1、将用户按用户组KeyBy(通过用户ID取余1000);
2、利用MapState存储状态,该状态存储了多个用户数据;(1万用户/Key)
源码分析
MapState的底层对象。

如图,无论是Fs还是RocksDB,都采用TtlMapState封装。
当对MapState进行读取, 通过getWrapped拿到封装后的TtlValue返回,里面包含userValue、lastAccessTimestamp,即用户存储的状态,以及最后一次访问时间(用于判断是否过期);
org.apache.flink.runtime.state.ttl.TtlMapState
@Override
public UV get(UK key) throws Exception {
TtlValue<UV> ttlValue = getWrapped(key);
return ttlValue == null ? null : ttlValue.getUserValue();
}
private TtlValue<UV> getWrapped(UK key) throws Exception {
accessCallback.run();
return getWrappedWithTtlCheckAndUpdate(
() -> original.get(key), v -> original.put(key, v), () -> original.remove(key));
}
TTL处理的主要逻辑就在getWrapped。
其中getWrappedWithTtlCheckAndUpdate,逻辑:对指定Key数据进行过期删除及返回状态,同时对Key的TTL进行更新(读是否更新取决于是否配置StateTtlConfig.UpdateType.OnReadAndWrite)。
org.apache.flink.runtime.state.ttl.AbstractTtlDecorator
<SE extends Throwable, CE extends Throwable, CLE extends Throwable, V> TtlValue<V> getWrappedWithTtlCheckAndUpdate(
SupplierWithException<TtlValue<V>, SE> getter,
ThrowingConsumer<TtlValue<V>, CE> updater,
ThrowingRunnable<CLE> stateClear) throws SE, CE, CLE {
TtlValue<V> ttlValue = getter.get();
if (ttlValue == null) {
return null;
} else if (expired(ttlValue)) {
stateClear.run(); // 执行删除 () -> original.remove(key)
if (!returnExpired) {
// 若配置了不返回过期状态,则会直接返回null
return null;
}
} else if (updateTsOnRead) {
updater.accept(rewrapWithNewTs(ttlValue));
}
return ttlValue;
}
每次获取数据时必定会调用put方法,将状态放入(无论读写)。
org.apache.flink.runtime.state.ttl.TtlMapState
@Override
public void put(UK key, UV value) throws Exception {
accessCallback.run();
original.put(key, wrapWithTs

最低0.47元/天 解锁文章
1228

被折叠的 条评论
为什么被折叠?



