可查询的状态

注意:可查询状态的客户端API目前处于不断发展的状态,对所提供接口的稳定性不做保证。在即将到来的Flink版本中,客户端的API很可能会有突破性的变化。

简而言之,该功能将Flink的托管键值(分区)状态(参见Working with State)暴露给外界,并允许用户从Flink外部查询作业的状态。对于某些场景来说,可查询状态消除了与外部系统(如键值存储)进行分布式操作/交易的需求,而这往往是实践中的瓶颈。此外,该功能对于调试目的可能特别有用。

注意事项 当查询一个状态对象时,该对象是在没有任何同步或复制的情况下从一个并发线程访问的。这是一个设计上的选择,因为上述任何一种情况都会导致作业延迟的增加,这是我们想要避免的。因为任何使用Java堆空间的状态后端,如MemoryStateBackend或FsStateBackend,在检索值时都不会使用副本,而是直接引用存储的值,所以读-修改-写模式是不安全的,可能会导致可查询状态服务器因并发修改而失败。RocksDBStateBackend则可以避免这些问题。

架构

在展示如何使用可查询状态之前,先简单介绍一下构成它的实体。Queryable State功能由三个主要实体组成。

  1. QueryableStateClient,它(可能)运行在Flink集群之外,并提交用户查询。
  2. QueryableStateClientProxy,它运行在每个任务管理器上(即Flink集群内部),负责接收客户端的查询,代表他从负责的任务管理器中获取所请求的状态,并将其返回给客户端,以及
  3. QueryableStateServer,它运行在每个TaskManager上,负责为本地存储的状态提供服务。

客户端连接到其中一个代理,并发送一个与特定键 k 相关联的状态的请求。正如在 "与状态一起工作 "中所述,键状态被组织在键组中,每个任务管理器都被分配了一些这样的键组。为了发现哪个任务管理器负责持有k的键组,代理将询问JobManager。根据答案,代理将查询运行在该 TaskManager 上的 QueryableStateServer,以获取与 k 相关联的状态,并将响应转发回客户端。

激活查询状态功能

要在Flink集群上启用可查询状态,你需要做以下工作。

  1. 将flink-queryable-state-runtime_2.11-1.12.0.0.jar从Flink发行版的opt/文件夹中复制到lib/文件夹中。
  2. 设置属性queryable-state.enable为true。请参阅配置文档了解详情和附加参数。

要验证您的群集是否在启用可查询状态后运行,请检查任何任务管理器的日志中的行。"Started the Queryable State Proxy Server @ ..."。

使状态变得可查询

现在你已经在集群上激活了可查询状态,现在是时候看看如何使用它了。为了使一个状态对外界可见,它需要通过使用以下方式明确地成为可查询状态。

  • QueryableStateStream, 一个方便的对象,它作为一个汇,并把它的传入值作为可查询的状态提供,或者是
  • stateDescriptor.setQueryable(String queryableStateName)方法,使得状态描述符所代表的键控状态,可以查询。

下面的章节将解释这两种方法的使用。

可查询的状态流

在 KeyedStream 上调用 .asQueryableState(stateName, stateDescriptor) 会返回一个 QueryableStateStream,它将其值作为可查询状态提供。根据状态的类型,asQueryableState()方法有以下几种变体。

// ValueState
QueryableStateStream asQueryableState(
String queryableStateName,
ValueStateDescriptor stateDescriptor) // Shortcut for explicit ValueStateDescriptor variant
QueryableStateStream asQueryableState(String queryableStateName) // ReducingState
QueryableStateStream asQueryableState(
String queryableStateName,
ReducingStateDescriptor stateDescriptor)

  

注意:没有可查询的ListState汇,因为这会导致一个不断增长的列表,可能无法清理,因此最终会消耗过多的内存。
返回的QueryableStateStream可以被看作是一个汇,不能被进一步转换。在内部,一个QueryableStateStream会被翻译成一个操作符,它使用所有传入的记录来更新可查询状态实例。更新逻辑是由asQueryableState调用中提供的StateDescriptor的类型暗示的。在像下面这样的程序中,键入流的所有记录将通过ValueState.update(value)来更新状态实例。

stream.keyBy(value -> value.f0).asQueryableState("query-name")

  

这就像Scala API的flatMapWithState一样。

受管理的键状态

通过StateDescriptor.setQueryable(String queryableStateName)使相应的状态描述符可查询,可以使操作符的托管键控状态(参见使用托管键控状态)成为可查询状态,如下面的例子。

ValueStateDescriptor<Tuple2<Long, Long>> descriptor =
new ValueStateDescriptor<>(
"average", // the state name
TypeInformation.of(new TypeHint<Tuple2<Long, Long>>() {})); // type information
descriptor.setQueryable("query-name"); // queryable state name

  

注意:queryableStateName参数可以任意选择,并且只用于查询。它不一定要与状态本身的名称相同。
这个变体对于哪种类型的状态可以被查询没有限制。这意味着它可以用于任何ValueState、ReduceState、ListState、MapState和AggregatingState。

查询状态

到目前为止,你已经设置了你的集群以可查询的状态运行,并且你已经将你的(部分)状态声明为可查询。现在是时候看看如何查询这个状态了。

为此,你可以使用 QueryableStateClient 辅助类。它可以在flink-queryable-state-client jar中找到,它必须和flink-core一起被显式地包含在项目的pom.xml中作为依赖,如下图所示。

<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-core</artifactId>
<version>1.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-queryable-state-client-java</artifactId>
<version>1.12.0</version>
</dependency>

更多的内容,可以查看如何设置Flink程序。

QueryableStateClient会将你的查询提交给内部代理,然后代理会处理你的查询并返回最终结果。初始化客户端的唯一要求是提供一个有效的任务管理器主机名(记住每个任务管理器上都有一个可查询状态代理运行)和代理监听的端口。更多关于如何配置代理和状态服务器端口的信息,请参见配置部分。

QueryableStateClient client = new QueryableStateClient(tmHostname, proxyPort);

  

在客户端准备就绪的情况下,要查询一个类型为V的状态,与类型为K的键相关联,可以使用该方法。

CompletableFuture<S> getKvState(
JobID jobId,
String queryableStateName,
K key,
TypeInformation<K> keyTypeInfo,
StateDescriptor<S, V> stateDescriptor)

  

以上返回一个CompletableFuture,最终持有ID为jobID的作业的queryableStateName所标识的可查询状态实例的状态值。key是你对其状态感兴趣的键,keyTypeInfo将告诉Flink如何序列化/解序列化它。最后,stateDescriptor包含了关于所请求的状态的必要信息,即它的类型(Value、Reduce等)和如何序列化/解序列化它的必要信息。

细心的读者会注意到,返回的future包含一个S类型的值,即一个包含实际值的State对象。这可以是Flink支持的任何一种状态类型。ValueState、ReduceState、ListState、MapState和AggregatingState。

注意:这些状态对象不允许对包含的状态进行修改。您可以使用它们来获取状态的实际值,例如使用valueState.get(),或者迭代包含的<K,V>条目,例如使用mapState.entry(),但您不能修改它们。举个例子,在返回的列表状态上调用add()方法会抛出一个UnsupportedOperationException。
注意:客户端是异步的,可以被多个线程共享。在未使用时需要通过QueryableStateClient.shutdown()来关闭它,以释放资源。

例子

下面的例子扩展了CountWindowAverage的例子(参见使用托管键控状态),使其可查询,并展示了如何查询这个值。

public class CountWindowAverage extends RichFlatMapFunction<Tuple2<Long, Long>, Tuple2<Long, Long>> {

    private transient ValueState<Tuple2<Long, Long>> sum; // a tuple containing the count and the sum

    @Override
public void flatMap(Tuple2<Long, Long> input, Collector<Tuple2<Long, Long>> out) throws Exception {
Tuple2<Long, Long> currentSum = sum.value();
currentSum.f0 += 1;
currentSum.f1 += input.f1;
sum.update(currentSum); if (currentSum.f0 >= 2) {
out.collect(new Tuple2<>(input.f0, currentSum.f1 / currentSum.f0));
sum.clear();
}
} @Override
public void open(Configuration config) {
ValueStateDescriptor<Tuple2<Long, Long>> descriptor =
new ValueStateDescriptor<>(
"average", // the state name
TypeInformation.of(new TypeHint<Tuple2<Long, Long>>() {})); // type information
descriptor.setQueryable("query-name");
sum = getRuntimeContext().getState(descriptor);
}
}

  

一旦在作业中使用,你可以检索作业ID,然后从这个操作符中查询任何键的当前状态。

QueryableStateClient client = new QueryableStateClient(tmHostname, proxyPort);

// the state descriptor of the state to be fetched.
ValueStateDescriptor<Tuple2<Long, Long>> descriptor =
new ValueStateDescriptor<>(
"average",
TypeInformation.of(new TypeHint<Tuple2<Long, Long>>() {})); CompletableFuture<ValueState<Tuple2<Long, Long>>> resultFuture =
client.getKvState(jobId, "query-name", key, BasicTypeInfo.LONG_TYPE_INFO, descriptor); // now handle the returned value
resultFuture.thenAccept(response -> {
try {
Tuple2<Long, Long> res = response.get();
} catch (Exception e) {
e.printStackTrace();
}
});

  

配置

以下配置参数会影响可查询状态服务器和客户端的行为,它们定义在QueryableStateOptions中。它们定义在QueryableStateOptions中。

状态服务器

  • queryable-state.server.ports:可查询状态服务器的服务器端口范围。如果在同一台机器上运行多个任务管理器,这对避免端口冲突很有用。指定的范围可以是:一个端口。"9123",一个端口范围: "50100-50200",或者一个范围和或点的列表。“50100-50200,50300-50400,51234”. 默认端口为9067。
  • queryable-state.server.network-threads:接收状态服务器传入请求的网络(事件循环)线程数(0 => #slots)。
  • queryable-state.server.query-threads:为状态服务器处理/服务传入请求的线程数(0 => #slots)。

代理

  • queryable-state.proxy.ports:可查询状态代理服务器的端口范围。如果在同一台机器上运行多个任务管理器,这对避免端口冲突很有用。指定的范围可以是:一个端口。"9123",一个端口范围: "50100-50200",或者一个范围和或点的列表。“50100-50200,50300-50400,51234”. 默认端口为9069。
  • queryable-state.proxy.network-threads:为客户端代理接收传入请求的网络(事件循环)线程数(0 => #slots)。
  • queryable-state.proxy.query-threads:为客户端代理处理/服务传入请求的线程数(0 => #slots)。

局限性

可查询状态的生命周期与任务的生命周期绑定,例如,任务在启动时注册可查询状态,在处置时取消注册。在未来的版本中,我们希望将其解耦,以便在任务完成后允许查询,并通过状态复制加快恢复速度。
关于可用 KvState 的通知是通过一个简单的告诉发生的。将来应该改进这个功能,使其更加强大,包括询问和确认。
服务器和客户端会跟踪查询的统计数据。目前默认情况下,这些数据是被禁用的,因为它们不会暴露在任何地方。一旦有更好的支持通过Metrics系统发布这些数字,我们应该启用统计。

Flink-v1.12官方网站翻译-P025-Queryable State Beta的更多相关文章

  1. Flink-v1.12官方网站翻译-P023-The Broadcast State Pattern

    广播状态模式 在本节中,您将了解如何在实践中使用广播状态.请参考状态流处理,了解状态流处理背后的概念. 提供的API 为了展示所提供的API,我们将在介绍它们的全部功能之前先举一个例子.作为我们的运行 ...

  2. Flink-v1.12官方网站翻译-P022-Working with State

    有状态程序 在本节中,您将了解Flink为编写有状态程序提供的API.请看一下Stateful Stream Processing来了解有状态流处理背后的概念. 带键值的数据流 如果要使用键控状态,首 ...

  3. Flink-v1.12官方网站翻译-P021-State & Fault Tolerance-overview

    状态和容错 在本节中,您将了解Flink为编写有状态程序提供的API.请看一下Stateful Stream Processing来了解有状态流处理背后的概念. 下一步去哪里? Working wit ...

  4. Flink-v1.12官方网站翻译-P005-Learn Flink: Hands-on Training

    学习Flink:实践培训 本次培训的目标和范围 本培训介绍了Apache Flink,包括足够的内容让你开始编写可扩展的流式ETL,分析和事件驱动的应用程序,同时省略了很多(最终重要的)细节.本书的重 ...

  5. Flink-v1.12官方网站翻译-P002-Fraud Detection with the DataStream API

    使用DataStream API进行欺诈检测 Apache Flink提供了一个DataStream API,用于构建强大的.有状态的流式应用.它提供了对状态和时间的精细控制,这使得高级事件驱动系统的 ...

  6. Flink-v1.12官方网站翻译-P015-Glossary

    术语表 Flink Application Cluster Flink应用集群是一个专用的Flink集群,它只执行一个Flink应用的Flink作业.Flink集群的寿命与Flink应用的寿命绑定. ...

  7. Flink-v1.12官方网站翻译-P008-Streaming Analytics

    流式分析 事件时间和水印 介绍 Flink明确支持三种不同的时间概念. 事件时间:事件发生的时间,由产生(或存储)该事件的设备记录的时间 摄取时间:Flink在摄取事件时记录的时间戳. 处理时间:您的 ...

  8. Flink-v1.12官方网站翻译-P004-Flink Operations Playground

    Flink操作训练场 在各种环境中部署和操作Apache Flink的方法有很多.无论这种多样性如何,Flink集群的基本构件保持不变,类似的操作原则也适用. 在这个操场上,你将学习如何管理和运行Fl ...

  9. Flink-v1.12官方网站翻译-P001-Local Installation

    本地安装 按照以下几个步骤下载最新的稳定版本并开始使用. 第一步:下载 为了能够运行Flink,唯一的要求是安装了一个有效的Java 8或11.你可以通过以下命令检查Java的正确安装. java - ...

随机推荐

  1. 杭电2734----Quicksum(C++)(数字与字符的关系)

    Quicksum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total S ...

  2. 【JavaWeb】Cookie&Session

    Cookie&Session Cookie 什么是 Cookie Cookie 即饼干的意思 Cookie 是服务器通知客户端保存键值对的一种技术 客户端有了 Cookie 后,每次请求都发送 ...

  3. Python作业---内置数据类型

    实验2 内置数据类型 实验性质:验证性 一.实验目的 1.掌握内置函数.列表.切片.元组的基本操作: 2.掌握字典.集合和列表表达式的基本操作. 二.实验预备知识 1.掌握Python内置函数的基/本 ...

  4. (十八)configparser模块

    configparser模块一般是用来处理配置文件的,如: [DEFAULT] ServerAliveInterval = 45 Compression = yes CompressionLevel ...

  5. 最新详解android自动化无障碍服务accessibilityservice以及高版本问题_1_如何开启获得无障碍

    前言 无障碍服务accessibilityservice是什么 简单来说 无障碍服务就是一个为残障人士 尤其是视觉障碍人士提供的一个帮助服务.具体就是可以识别控件 文字 可以配合语音助手 操作和 使用 ...

  6. kubernets之secret资源

    一  对于一些保密度比较高的文件,k8s又是如何存储的呢? 针对那些保密度比较高的配置文件,例如证书以及一些认证配置不能直接存储在configmap中,而是需要存储在另外一种资源中,需要对存储在里面的 ...

  7. ctfhub技能树—sql注入—Refer注入

    手注 查询数据库名 查询数据表名 查询字段名 查询字段信息 脚本(from 阿狸) #! /usr/bin/env python # _*_ coding:utf-8 _*_ url = " ...

  8. 私有镜像仓库Harbor基础介绍与部署

    企业级私有镜像仓库Harbor 一:介绍 Harbor,是一个英文单词,意思是港湾,港湾是干什么的呢,就是停放货物的,而货物呢,是装在集装箱中的,说到集装箱,就不得不提到Docker容器,因为dock ...

  9. 1.2V转3V芯片,电路图很少就三个元件

    1.2V的镍氢电池由于稳定高,应用产品也是很广,但是由于电压低,需要1.2V转3V芯片,来将1.2V的电压升压转3V,稳定输出供电. 一般性的1.2V转3V芯片,都是用PW5100比较多,固定输出电压 ...

  10. C#从入门到放弃治疗一:初探C#世界

    C#是一款高级的面向对象语言,运行于.NET framework之上的高级程序设计语言.其语言规范和,语法和java有着惊人的类似之处.所以如果你在学习C#之前有着java的基础,你将快速地入门.当然 ...