首页 > 编程语言 >十五、Flink状态编程之Flink状态

十五、Flink状态编程之Flink状态

时间:2023-02-05 16:55:34浏览次数:36  
标签:状态 编程 托管 Flink 任务 算子 数据

简介

在流处理中,数据是连续不断到来和处理的。每个任务进行计算处理时,可以基于当前数据直接转换得到输出结果;也可以依赖一些其他数据。这些由一个任务维护,并且用来计算输出结果的所有数据,就叫作这个任务的状态

一、有状态算子

​ 在Flink中,算子任务可以分为无状态有状态两种情况。
​ 无状态的算子任务只需要观察每个独立事件,根据当前输入的数据直接转换输出结果,如下图所示。如,可以将一个字符串类型的数据拆分开作为元组输出;也可以对数据做一些计算,比如每个代表数量的字段加1。之前讲到的基本转换算子,如map、filter、flatMap,计算时不依赖其他数据,就都属于无状态的算子
image
而有状态的算子任务,则除当前数据之外,还需要一些其他数据来得到计算结果。这里的“其他数据”,就是所谓的状态(state),最常见的就是之前到达的数据,或者由之前数据计算出的某个结果。比如,做求和(sum)计算时,需要保存之前所有数据的和,这就是状态;窗口算子中会保存已经到达的所有数据,这些也都是它的状态。另外,如果我们希望检索到某种“事件模式”(eventpattern),比如“先有下单行为,后有支付行为”,那么也应该把之前的行为保存下来,这同样属于状态。很容易发现,之前讲过的聚合算子、窗口算子都属于有状态的算子
image

如上图所示为有状态算子的一般处理流程,具体步骤如下。
(1)算子任务接收到上游发来的数据;
(2)获取当前状态;
(3)根据业务逻辑进行计算,更新状态;
(4)得到计算结果,输出发送到下游任务。

二、状态的管理

​ 在传统的事务型处理架构中,这种额外的状态数据是保存在数据库中的。而对于实时流处理来说,这样做需要频繁读写外部数据库,如果数据规模非常大就达不到性能要求了。所以Flink的解决方案是,将状态直接保存在内存中来保证性能,并通过分布式扩展来提高吞吐量。
​ 在Flink中,每一个算子任务都可以设置并行度,从而可以在不同的slot上并行运行多个实例,我们把它们叫作“并行子任务”。而状态既然在内存中,那么就可以认为是子任务实例上的一个本地变量,能够被任务的业务逻辑访问和修改。
​ 这样看来状态的管理似乎非常简单,可以直接把它作为一个对象交给JVM就可以了。然而大数据的场景下,必须使用分布式架构来做扩展,在低延迟、高吞吐的基础上还要保证容错性,一系列复杂的问题就会随之而来了。

  • 【状态的访问权限】:Flink上的聚合和窗口操作,一般都是基于KeyedStream的,数据会按照key的哈希值进行分区,聚合处理的结果也应该是只对当前key有效。然而同一个分区(也就是slot)上执行的任务实例,可能会包含多个key的数据,它们同时访问和更改本地变量,就会导致计算结果错误。所以这时状态并不是单纯的本地变量。

  • 【容错性】:也叫故障后的恢复。状态只保存在内存中显然是不够稳定的,我们需要将它持久化保存,做一个备份;在发生故障后可以从这个备份中恢复状态。

  • 【分布式应用的横向扩展性】:处理的数据量增大时,应该相应地对计算资源扩容,调大并行度。这时就涉及到了状态的重组调整。
    ​ 可见状态的管理并不是一件轻松的事。好在Flink作为有状态的大数据流式处理框架,已经帮我们搞定了这一切。Flink有一套完整的状态管理机制,将底层一些核心功能全部封装起来,包括状态的高效存储和访问、持久化保存和故障恢复,以及资源扩展时的调整。这样,我们只需要调用相应的API就可以很方便地使用状态,或对应用的容错机制进行配置,从而将更多的精力放在业务逻辑的开发上

三、状态的分类

1.托管状态(Managed State)和原始状态(Raw State)

​ Flink的状态有两种:托管状态(ManagedState)和原始状态(RawState)
托管状态就是由Flink统一管理的,状态的存储访问、故障恢复和重组等一系列问题都由Flink实现,只要调接口就可以;
而原始状态则是自定义的,相当于就是开辟了一块内存,需要自己管理,实现状态的序列化和故障恢复。
​ 具体来讲,托管状态是由Flink的运行时(Runtime)来托管的;在配置容错机制后,状态会自动持久化保存,并在发生故障时自动恢复。当应用发生横向扩展时,状态也会自动地重组分配到所有的子任务实例上。对于具体的状态内容,Flink也提供了值状态(ValueState)、列表状态(ListState)、映射状态(MapState)、聚合状态(AggregateState)等多种结构,内部支持各种数据类型。聚合、窗口等算子中内置的状态,就都是托管状态;也可以在富函数类(RichFunction)中通过上下文来自定义状态,这些也都是托管状态。
​ 而对比之下,原始状态就全部需要自定义了。Flink不会对状态进行任何自动操作,也不知道状态的具体数据类型,只会把它当作最原始的字节(Byte)数组来存储。需要花费大量的精力来处理状态的管理和维护。
所以只有在遇到托管状态无法实现的特殊需求时,我们才会考虑使用原始状态;一般情况下不推荐使用。绝大多数应用场景,我们都可以用Flink提供的算子或者自定义托管状态来实现需求。

2.算子状态(Operator State)和按键分区状态(Keyed State)

接下来重点就是托管状态(Managed State)。
​ 在Flink中,一个算子任务会按照并行度分为多个并行子任务执行,而不同的子任务会占据不同的任务槽(taskslot)。由于不同的slot在计算资源上是物理隔离的,所以Flink能管理的状态在并行任务间是无法共享的,每个状态只能针对当前子任务的实例有效。
而很多有状态的操作(比如聚合、窗口)都是要先做 keyBy 进行按键分区的。按键分区 之后,任务所进行的所有计算都应该只针对当前 key 有效,所以状态也应该按照 key 彼此隔离。 在这种情况下,状态的访问方式又会有所不同。
基于这样的想法,又可以将托管状态分为两类:算子状态和按键分区状态。
<1> 算子状态(Operator State)
​ 状态作用范围限定为当前的算子任务实例,也就是只对当前并行子任务实例有效。这就意味着对于一个并行子任务,占据了一个“分区”,它所处理的所有数据都会访问到相同的状态,状态对于同一任务而言是共享的,如下图所示。
image
​ 算子状态可以用在所有算子上,使用的时候其实就跟一个本地变量没什么区别——因为本地变量的作用域也是当前任务实例。在使用时,我们还需进一步实现CheckpointedFunction接口。
<2> 按键分区状态(Keyed State)
状态是根据输入流中定义的键(key)来维护和访问的,所以只能定义在按键分区流(KeyedStream)中,也就keyBy之后才可以使用,如下图所示。
image
​ 按键分区状态应用非常广泛。之前讲到的聚合算子必须在keyBy之后才能使用,就是因为聚合的结果是以KeyedState的形式保存的。另外,也可以通过富函数类(RichFunction)来自定义KeyedState,所以只要提供了富函数类接口的算子,也都可以使用KeyedState。
​ 所以即使是map、filter这样无状态的基本转换算子,也可以通过富函数类给它们“追加”KeyedState,或者实现CheckpointedFunction接口来定义OperatorState;从这个角度讲,Flink中所有的算子都可以是有状态的,不愧是“有状态的流处理”。
​ 无论是KeyedState还是OperatorState,它们都是在本地实例上维护的,也就是说每个并行子任务维护着对应的状态,算子的子任务之间状态不共享。关于状态的具体使用,会在下面章节继续展开讲解。

标签:状态,编程,托管,Flink,任务,算子,数据
From: https://www.cnblogs.com/kunande/p/17093578.html

相关文章

  • 面向对象编程
    面向对象编程Java的核心思想就是OOP面向过程&面向对象对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统,但是,具体到围观......
  • Python黑客编程之tcp代理
    目的写一款socket代理工具,其实就是在原来两极通信中再加一极,中间极用来转发socket的流量,可以在中间层面实现流量的拦截和篡改代码代理importsocketimportsysim......
  • C++基础编程题
     一、第一种类型题,普遍是简单运算计算球的体积V=4/3πr^3,输入球的半径r,求出体积保留3位小数#include<bits/stdc++.h>usingnamespacestd;intmain(){double......
  • Python黑客编程之类nc工具
    目的用pythonsocket编写一款类似NetCat的工具,可以在服务器上远程执行命令,从服务器上下载文件代码服务端和客户端用同一套代码,用-l参数进行区分importargparsei......
  • 学习ASP.NET Core Blazor编程系列二十三——登录(3)
    学习ASP.NETCoreBlazor编程系列文章之目录学习ASP.NETCoreBlazor编程系列一——综述学习ASP.NETCoreBlazor编程系列二——第一个Blazor应用程序(上)学习A......
  • 5.4节约内存的编程方式
    以图形用户界面(GUI,GraphicalUserInterface)为基础的Windows,可以说是一个巨大的操作系统。Windows的前身是MS-DOS操作系统,最初版本可以在128KB左右的内存上运行,而想要W......
  • 【C++ 泛型编程01:模板】函数模板与类模板
    【模板】除了OOP外,C++另一种编程思想称为泛型编程,主要利用的技术就是模板C++提供两种模板机制:函数模板和类模板函数模板函数模板作用建立一个通用函数,其函数......
  • python基础:计算机五大组成部分详细介绍、计算机三大核心硬件、操作系统、编程与编程语
    目录一、计算机五大组成部分详细介绍1.控制器2.运算器3.存储设备4.输入设备5.输出设备二、计算机三大核心硬件1.cpu2.内存举例:写文档时,突然关机了。3.磁盘cpu为什么不和磁......
  • MRS芯片状态错误排查方向
    1.如手里的LINK板子标注是WCH-LINK,而不是WCH-LINKE,那么与开发板连接线最好别超过15CM2.芯片供电是否正常,VDDA和VDD要正常供电2.检查连线是否正确,SWDIO-PA1......
  • 我,35岁,还单身,生活状态如何?
    为本人真实情况,不怕遇到熟人,但也不希望有人身攻击,更不想成为别人的茶余饭后,更不希望这篇文章出现某些博客或者某机构或号主等媒体平台上!今年35岁了,也不在乎虚岁或周岁了,在......