字节跳动 Flink 状态查询实践与优化

字节跳动使用 Flink State 的经验分享 动手点关注干货不迷路????本文主要分享字节跳动在使用 Flink State 上的实践经验,内容包括 Flink State 相关实践以及部分字节内部在引擎上的优化,希望可以给 Flink 用户的开发及调优提供一些借鉴意义。前言Flink 作业需要借助 State 来完成聚合、Join 等有状态的计算任务,而 State 也一直都是作业调优的一个重点。目前 State 和... 阅读详情

本篇文章介绍了字节跳动在 Flink 状态查询方面所进行的优化,解决了查询 Flink 任务状态时开发成本高及无法查询状态元信息等问题,提出了 State Query on Flink SQL 的解决方案,让用户使用 Flink Batch SQL 就可以快速查询 Flink 任务状态。

背景

众所周知,Flink 中的 State 保存了算子计算过程的中间结果。当任务出现异常时,可以通过查询任务快照中的 State 获取有效线索。

但目前对于 Flink SQL 任务来说,当我们想要查询作业 State 时,通常会因为无法获知 State 的定义方式和具体类型等信息,而导致查询 State 的成本过高。

为了解决这个问题,字节跳动流式计算团队在内部提出了 State Query on Flink SQL 的解决方案——用户通过写 SQL 的方式就可以简单地查询 State。本文将主要介绍字节跳动在 Flink 状态查询这方面所进行的相关工作。

State Processor API 介绍

提到状态查询,我们自然会联想到 Flink 在 1.9 版本提出的特性 -- State Processor API。使用 State Processor API,我们可以将作业产生的 Savepoint 转换成 DataSet,然后使用 DataSet API 完成对 State 的查询、修改和初始化等操作。

下面简单介绍一下 如何使用 State Processor API 来完成 State 的查询:

  • 首先创建 ExistingSavepoint 用来表示一个 Savepoint。初始化 ExistingSavepoint 时需要提供 Savepoint 路径和 StateBackend 等信息;

  • 然后实现 ReaderFunction 用于重新注册所需要查询的 State 以及定义处理 State 的方式。查询状态的过程中会遍历所有的 Key 并按照我们定义的方式去操作 State;

  • 最后,调用 Savepoint.readKeyedState 并传入算子的 uid 和 ReaderFunction,就可以完成 State 的查询。

接下来为大家简述一下 State 查询背后的原理。

在 Savepoint 目录中包含两种文件,一种是状态数据文件,比如上图中的 opA-1-state ,这个文件里面保存着算子 A 在第一个 SubTask 状态的明细数据;还有一种元数据文件,对应上图中的 _metadata,元数据文件中保存了每个算子和状态文件的映射关系。

当我们在进行状态查询的时候。首先在 Client 端会根据 Savepoint 路径去解析 metadata 文件。通过算子 ID,可以获取需要查询的状态所对应的文件的句柄。当状态查询真正执行时,负责读取状态的 Task 会创建一个新的 StateBackend ,然后将状态文件中的数据恢复到 Statebackend 中。等到状态恢复完成之后就会遍历全部的 Key 并把对应的状态交给 ReaderFunction 处理。

有些同学可能会问,既然社区已经提供了查询 State 的功能,我们为什么还要去做同样的工作呢?主要是因为 我们在使用 State Processor API 的过程中发现一些问题:

  1. 每次查询 State 我们都需要独立开发一个 Flink Batch 任务,对用户来说具有一定的开发成本;

  2. 实现 ReaderFunction 的时候需要比较清晰地了解任务状态的定义方式,包括 State 的名称、类型以及 State Descriptor 等信息,对用户来说使用门槛高较高;

  3. 使用 State Processor API 时,只能查询单个算子状态,无法同时查询多个算子的状态;

  4. 无法直接查询任务状态的元信息,比如查询任务使用了哪些状态,或者查询某个状态的类型。

总体来说,我们的目标有两个,一是 降低用户的使用成本; 二是 增强状态查询的功能。 我们希望用户在查询 State 时能用最简单的方式;同时也不需要知道任何信息。

此外,我们还希望用户能同时查询多个算子的 State ,也可以直接查询作业使用了哪些 State,每个 State 的类型是什么。

因此,我们提出了 State Query on Flink SQL 的解决方案。 简单来说是 把 State 当成数据库一样,让用户通过写 SQL 的方式就可以很简单地查询 State。

在这个方案中,我们需要解决两个问题:

  • 如何对用户屏蔽 State 的信息: 参考 State Processor API 我们可以知道,查询 State 需要提供非常多的信息,比如 Savepoint 路径、 StateBacked 类型、算子 id 、State Descriptor 等等。通过 SQL 语句显然难以完整地表述这些复杂的信息,那么查询状态到底需要哪些内容,我们又如何对用户屏蔽 State 里复杂的细节呢?这是我们面对的第一个难点。

  • 如何用 SQL 表达 State: State 在 Flink 中的存储方式并不像 Database 一样,我们如何去用 SQL 来表达状态的查询过程呢?这是我们要解决的另一个难点。

StateMeta Snapshot 机制

首先我们来回答第一个问题, 查询一个 State 需要哪些信息呢?

可以参考上文中 State Processor API 的示例,当我们创建 ExistingSavepoint 和 ReaderFunction 的时候,我们需要提供的信息有 Savepoint 路径、Backend 类型、OperatorID、算子 key 的类型、State 名称以及 Serializer 等等,我们可以将这些统一称为状态的元信息。

对于 Flink SQL 任务来说,要清楚地了解这些信息,对用户来说门槛是非常高的。我们的想法是让用户只需要提供最简单的信息,即 Savepoint ID ,然后由 Flink 框架把其他的元信息都存在 Savepoint 中,这样就可以对用户屏蔽 State 那些复杂的细节,完成状态的查询。因此,我们引入了 StateMeta Snapshot 机制。

StateMeta Snapshot 简单来说就是把状态的元信息添加到 Savepoint Metadata 的过程, 具体步骤如下:

  • 首先在 State 注册的时候,Task 会把 operatorName\ID\KeySerializer\StateDescriptors 等元信息都保存在 Task 的内存中;

  • 触发 Savepoint 时,Task 会在制作快照的同时,对状态的元信息也同样进行快照。快照完成之后将状态的元信息 (StateMeta) 和状态文件的句柄 (StateHandle) 一起上报给 JobManager;

  • JobManager 在收到所有 Task 上报的 StateMeta 信息之后 ,将这些状态元信息进行合并,最后会把合并之后的状态元信息保存到 Savepoint 目录里名为 stateInfo 的文件中。

之后在状态查询时就只需解析 Savepoint 中的 stateInfo 文件,而不再需要用户通过代码去输入这些 State 的元信息。通过这样的方式可以很大程度地降低用户查询状态的成本。

State as Database

接下来我们来回答第二个问题,我们如何用 SQL 来表达 State。其实社区在设计 State Processor API 的时候就提出了一些解决思路,也就是 State As Database。

在传统的数据库中,通常用 Catalog、Database、Table 这个三个元素来表示一个 Table,其实我们也可以将用样的逻辑到映射到 Flink State 上。我们可以把 Flink 的 State 当作一种特殊的数据源,作业每次产生的 Savepoint 都当作一个独立 DB 。在这个 DB 中,我们将 State 元信息、State 的明细数据,都抽象成不同的 Table 暴露给用户,用户直接查询这些 Table 就可以获取任务的状态信息。

首先我们来看如何把 State 表示为 Table。我们都知道 在 Flink 中,常用的 State 有两种类型, 分别是 KeyedState 和 OperatorState。

  • 对于 OperatorState 来说,它只有 Value 这一个属性,用来表示这个 State 具体的值。因此我们可以把 OperatorState 表示为只包含一个 Value 字段的表结构。

  • 对于 KeyedState 来说,每个 State 在不同的 Key 和 Namespace 下的值可能都不一样, 因此我们可以将 KeyedState 表示为一个包含 Key、Namespace、Value 这三个字段的表结构。

当我们抽象出了单个 State 之后,想要表示多个 State 就比较容易了。可以看到在上图的例子中,这个算子包含 3 个 State,分别是两个 KeyedState 和一个 OperatorState,我们只需要将这些 Table 简单的 union 起来,再通过 state_name 字段去区分不同的 State,就可以表示这个算子中所有的 State。

最后还有一个问题, 我们如何知道一个任务到底用了哪些 State 或者这些 State 的具体类型呢?

为了解决这个问题,我们定义了一种特殊表 -- StateMeta ,用来表示一个 Flink 任务中所有 State 的元信息。StateMeta 中包含一个任务中每个 State 的名称、State 所在的算子 ID 、算子名称 、Key 的类型和 Value 的类型等等,这样用户直接查询 StateMeta 这个表就能获取任务中所有状态的元信息。

使用 Flink Batch SQL 查询任务状态

以上就是状态查询方案的整体介绍。那我们到底 如何去查询一个 State 呢, 我们以一个 Word Count 任务为例来说明。

首先,我们需要创建一个 Flink SQL 任务并启动。通过 web-ui 可以看到这个任务中包含三个算子,分别是 Source,Aggregate 还有 Sink。然后,我们可以触发 Savepoint,当 Savepoint 制作成功之后获取对应的 SavepointID。我们可以通过 SavepointID 去完成作业状态的查询。

假如我们现在对 Flink SQL 任务中状态的使用一无所知,那么首先我们需要查询的就是这个 Flink 任务中包含哪些 State 以及这些 State 的类型。我们可以从 StateMeta 表获取这些信息。如上图中场景一所示,通过查询 StateMeta 表,可以看到这个任务包含一个 ListState 和一个 ValueState,分别存在于 Source 算子和 Aggregate 算子中。

此外,有些对 Flink 比较了解的同学知道,KafkaSource 中的 State 是用于记录当前消费的 Offset 信息。如场景二所示,我们可以通过查询 Source 算子的状态,获取到任务中消费 Kafka Topic 的 Partition 和 Offset 信息。

还有一种比较常见的场景,比如下游的业务同学发现某个 key(比如 key_662)的结果异常。我们在定位问题的时候可以直接去查询作业中 aggregate 算子中的状态,同时去指定 key 等于 key_662 作为查询条件。如上图场景三所示,通过查询的结果可以看到,当 key 为 662 时对应的聚合结果是 11290。用户使用这样的方式就可以比较方便地验证状态是否正确。

未来展望

未来,我们计划 进一步丰富 State 的功能, 目前我们支持了使用 SQL 查询 State 的功能 ,其实社区还提供了 State 修改和初始化的能力。在一些场景下,这些能力也比较重要。比如,我们已知状态中的部分 key 计算错误,希望将状态中这部分的数据进行修正;或者任务逻辑发生变更以后和之前的状态不能完全兼容, 这个时候我们希望可以通过状态修改和初始化的能力去生成一个新的 Savepoint。同样,在使用方式上我们也希望用户能直接使用 SQL 中 insert 和 update 语法来完成状态的修改和初始化操作。

其次,我们会 进一步加强 State 的可用性。 我们使用 DAG 编辑的方案解决了作业拓扑发生变化时产生的状态不兼容问题,但是当 Flink SQL 任务修改字段时 State Serializer 可能会变化,同样导致状态无法兼容。针对这种情况我们设计了完整的 Flink SQL State Schema Evolution 方案,可以极大的增强 Flink SQL 任务发生变化之后状态的恢复能力,目前正在落地中。我们还提供了完善的状态恢复事前检查能力,能够做到在任务上线之前就检查出状态是否兼容并告知用户,避免状态不兼容引起作业启动失败对线上造成影响。

加入我们

字节跳动实时计算团队负责公司内部实时计算场景, 支撑了数仓/机器学习/推荐/搜索/广告/流媒体/安全和风控等众多核心业务,我们面临的挑战是超大单体作业(千万级别 QPS),超大集群规模(上万台机器)的应用场景,在 SQL, State, Runtime 上都有深度优化。公司仍处于高速发展阶段,欢迎有能力、有想法的同学来这里一起建设实时计算引擎。工作地点:北京、杭州,感兴趣的同学点击 阅读原文 投递简历。

flink理论干货笔记(2) 199.flinkcep的核心api是CEP.pattern(),它接受一个DataStream和一个Pattern,后者允许你定义要从输入流提取的复杂模式序列,比如begin、where、next、subtype、where、followedBy等。其中where中可以定义SimpleCondition类并重写filter方法。而CEP.pattern得到的流可以继续用select,并结合PatternSelectFunction,然后重写select方法......... 阅读详情

相关推荐

flink实战--状态管理(State TTL、Operator state、Keyed state)

简介 使用flink进行实时计算中,会遇到一些状态数不断累积,导致状态量越来越大的情形。例如,作业中定义了超长的时间窗口,或者在动态表上应用了无限范围的 GROUP BY 语句,以及执行了没有时间窗口限制的双流 JOIN 等等操作。对于这些情况,经常导致堆内存出现 OOM,或者堆外内存(RocksDB)用量持续增长导致超出容器的配额上限,造成作业的频繁崩溃。从 ...

阿华田的博客 2625

Flink SQL Client的使用

目录1. 启动SQL Client2. SQL Client结果查看模式3. 同步 / 异步执行DML语句 1. 启动SQL Client 先启动Flink集群 [root@flink1 ~]# [root@flink1 ~]# flink-1.14.3/bin/sql-client.sh ......省略部分...... Flink SQL> 目前sql-client.sh只能连接本地的集群,不能连接远程的集群 2. SQL Client结果查看模式 1. table模式 将结果物化到内存,

Bulut0907 5389

工业视觉开发者的福音:用C#玩转VisionMaster算子(非方案版完整教程)

本文为工业视觉开发者提供了一份完整的C#与VisionMaster算子二次开发教程,详细介绍了环境配置、算子调用原理、性能优化技巧及实战案例。通过模板匹配和二维码识别等实例,展示了如何高效集成VisionMaster算子到现有框架中,提升工业自动化视觉检测系统的灵活性和性能。

weixin_29280657的博客 273

Flink作业任务的9种状态简单介绍

当创建一个Flink任务后,该任务可能会经历多种状态。目前Flink给任务共定义了9种状态,包括:`Created`,`Running`,`Finished`,`Cancelling`,`Canceled`,`Restarting`,`Failing`,`Failed`,`Suspended`。

weixin_43914798的博客 6499

SEED-VII 实战指南:如何利用多模态脑电图数据提升情感识别精度

本文提供了SEED-VII多模态脑电图数据集的实战指南,详细介绍了如何利用该数据集提升情感识别精度。内容涵盖数据获取、预处理、特征提取,以及构建多模态融合神经网络模型的关键步骤,并强调了被试者独立评估的重要性,为情感计算研究者提供了从数据到模型的全流程解决方案。

weixin_29196891的博客 318

FPGA新手避坑指南:Vivado 2020.2里配置PLL IP核,从差分时钟输入到上板实测的全流程

本文详细介绍了在Vivado 2020.2中配置PLL IP核的全流程,包括差分时钟输入、参数设置、仿真验证及上板实测。针对FPGA新手常见的配置错误和硬件连接问题,提供了实用的解决方案和调试技巧,帮助开发者快速掌握时钟管理技术。

weixin_27051161的博客 490

利用Flink SQL实时统计单据状态(含历史数据)

利用Flink SQL实时统计单据状态(含历史数据)

东境物语 1万+

消费级显卡跑大模型:RTX 3060 12G 部署 70 亿参数 AI 编程助手的优化实战

本文详细介绍了如何在消费级显卡RTX 3060 12G上,通过量化、投机解码和分页KV-Cache等核心优化技术,成功部署并流畅运行70亿参数的CodeLlama-7B编程助手。文章提供了从环境配置、模型准备到参数调优的完整实战笔记,实测显存占用降至7.3GB,生成速度达21.7 token/秒,为开发者和技术爱好者提供了可行的本地AI部署方案。

weixin_29053067的博客 1263

Flink:状态和检查点

实际上,Flink的状态是由算子的子任务来创建和管理的;Flink事务写指Flink先把待输出的数据保存下来暂不祥外部系统提交,待CheckPoint结束,上下游算子的数据都一致时,再提交数据;无论是Keyed State还是Operator State,Flink的状态都是基于本地的,即每个算子子任务维护着自身的状态,不能访问其他算子子任务的状态。③继续处理新流入的数据,包括刚才缓存起来的数据。flink的错机制,定期对状态进行快照,当flink故障时,可以从存储的快照恢复,保证了本地状态不会丢失;

weixin_52635513的博客 566

深度学习---双层神经网络中矩阵的运算及其含义记录

深度学习---双层神经网络中矩阵的运算及其含义记录神经网络的正向传播与反向传播正向传播第一层的权重矩阵第一层的输入矩阵Z^1^ = W^1^X^1^ + b^1^A^1^ = σ(Z^1^)第二层的权重矩阵第二层的输入矩阵Z^2^ = W^2^A^1^ + b^2^反向传播dz^2^ = A^2^ - Ydw^2^ = 1/n dz^2^A^1T^db^2^ = 1/n np.sum(dz^2...

qq_43228441的博客 3748

模拟ic入门——设计一个单极运放(一)单级运算放大器设计基础

主要介绍了单级运放的基本理论和使用场景

qq_64956710的博客 3750

大数据架构师面试:谓词下推与Flink状态管理实战解析

谓词下推(Predicate Pushdown)是分布式查询优化的核心技术,通过将过滤条件提前至数据源端执行,显著减少数据传输与计算开销。其原理基于查询重写与存储格式特性(如Parquet的Min-Max索引),在PB级数据处理中可降低90%网络传输。Flink状态管理保障实时计算的一致性,涉及状态后端选型(内存/RocksDB)、TTL策略及扩缩容处理,是电商风控、实时推荐等场景的基石。本文结合字节跳动实战案例,详解JSON嵌套数据下推优化与混合状态后端设计,揭示工业级实现中的性能陷阱与调优方法。

weixin_32495691的博客 239

uniapp - H5网页uni.getLocation报错getLocation:fail Geolocation permission denied.Get ipLocation failed.

uni.getLocation getLocation:fail Geolocation permission denied.Get ipLocation failed.,uni.getLocation定位失败,uni-app getLocation()无法获取定位,一直fail()uniapp移动端h5网页,uniApp微信内置浏览器定位失败,如何解决这个问题,uniapp h5 uni.getLocation获取位置失败怎么办,UNI-APP获取当前位置,uni.getLocation定位失败,unia

🏆 前端领域优质创作者 4244

Flink OLAP 在字节跳动的查询优化和落地实践

业务落地情况字节 Flink OLAP 上线以来接入了包括 User Growth、飞书、电商和幸福里等 12 家以上核心业务方,集群规模达到 1.6 万 Core 以上,每天的查询规模超过 50w 次,单集群支持了复杂查询高峰期的 200 QPS,同时 Query Latency P99 控制在 5s 以内,较好的满足了业务的性能需求。架构Flink OLAP 的总体架构分为 Flink SQL Gateway 和 Flink Session Cluster 两部分。

字节跳动云原生计算官方账号 574

ATECC508A芯片开发笔记(三):获取508A串号、随机数源码及I2C抓包分析

ATECC508A芯片开发笔记(三):读取508A串号、获取随机数源码及I2C抓包分析 APP层函数编写及源码分析 At508_GetSernum() GetSernum抓包记录 At508_GetRandom( ) GetRandom抓包记录 经过前两章节,CryptoAuthlib库已经成功适配在代码中了,下面简单测试一下API函数,并分析下I2C通讯流程: APP层函数编写及源码分析利用li

HowieXue 薛永浩的博客 2万+

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

2026字节跳动大数据架构师面经:谓词下推与Flink状态深度解析

本文分享了字节跳动大数据架构师面试的核心知识点,包括SQL谓词下推技术和Flink状态管理机制。谓词下推通过提前过滤数据优化查询性能,文中通过SQL示例和原理图进行了详细说明。Flink状态管理部分重点解析了KeyedState和OperatorState的区别、扩缩容原理以及状态重建流程,并引入KeyGroup概念解决状态分配问题。文章还结合源码分析状态重建的实现逻辑,帮助读者深入理解大数据处理的核心技术。此外,文中提到字节26届校招顶尖人才年薪达260万,突显了大模型与AI领域的技术价值。

2401_85390073的博客 922

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

幸福里基于 Flink & Paimon 的流式数仓实践

字节跳动基础架构工程师李国君,在 Streaming Lakehouse Meetup 的分享。

Ververica的博客 1213

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

【Flink】字节跳动 Flink 基于 Slot 的资源管理实践

总体上来讲,Flink 整个资源管理、申请和分配围绕 Slot 展开,同时每个 TaskManager 中的 Slot 数量决定了作业在该 TaskManager 中运行的并发计算任务数量。本篇文章主要介绍了 Slot 对资源分配、释放以及计算执行的影响,希望可以帮助大家更好地决策每个 TaskManager 中的 Slot 数量,对 Flink 作业进行调优。

九师兄 682

幸福里基于 Flink & Paimon 的流式数仓实践

摘要:本文整理自字节跳动基础架构工程师李国君,在 Streaming Lakehouse Meetup 的分享。幸福里业务是一种典型的交易、事务类型的业务场景,这种业务场景在实时数仓建模中遇到了诸多挑战。本次分享主要介绍幸福里业务基于 Flink & Paimon 构建流式数仓的实践经验,从业务背景、流批一体数仓架构、实践中遇到的问题和解决方案,借助 Paimon 最终能拿到的收益,以及未...

大数据星球-浪尖 482

大数据架构师面试:谓词下推与Flink状态管理深度解析

在大数据处理领域,查询优化和流处理可靠性是核心技术挑战。谓词下推通过将过滤条件下推到数据源执行,显著减少数据传输量,特别适用于Parquet等列式存储格式。其实现依赖逻辑计划重写、数据源API扩展和统计信息利用等机制。Flink状态管理则解决了流处理中的状态持久化问题,通过Keyed State和Operator State支持复杂流式应用,配合RocksDB等状态后端实现精确一次处理。这两项技术在大数据架构师面试中常被深入考察,涉及实现原理、工程优化和故障处理等实践细节,是构建高性能大数据系统的关键能力。

weixin_29050513的博客 327
上一篇: 聊聊 Kubectl scale 命令的优秀实践
下一篇: Linux的TCP连接数量最大不能超过65535个吗,那服务器是如何应对百万千万的并发的?
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值