flink增量检查点降低状态依赖实现的详细步骤
增量检查点启动恢复的时间是很久的,业务上不能接受,所以可以通过降低状态依赖来减少恢复的时间。
降低状态依赖
尽可能减少状态的复杂性和依赖关系,通过拆分状态或将状态外部化到其他服务中,从而降低恢复的开销。
实施措施:
- 将状态分割为更小的单元,减少每次恢复的状态量。
- 使用外部状态存储服务,减少 Flink 状态后端的负担。
拆分状态和将状态外部化到其他服务可以帮助减少作业的状态依赖,从而降低恢复时间和复杂度。以下是详细的步骤和方法,涵盖状态拆分以及将状态外部化的常见实现方式。
1. 状态拆分(State Partitioning)
状态拆分旨在减少单一作业的状态大小和复杂度,通过将大状态分割为多个较小的状态单元,从而减少每次恢复和处理状态的开销。
a. 按业务逻辑拆分
根据业务逻辑,将不同的状态拆分为多个独立的模块,使每个模块管理单独的一部分状态。
-
步骤:
- 分析业务流程:确定哪些状态可以逻辑上独立拆分。每个状态模块应该只处理与其业务逻辑相关的数据。
- 拆分状态:在 Flink 作业中,将不同的状态管理逻辑分散到多个处理函数或算子中。例如,将订单处理状态和用户状态分开处理。
public class OrderProcessFunction extends KeyedProcessFunction<Long, OrderEvent, OrderResult> {private ValueState<OrderState> orderState;@Overridepublic void open(Configuration parameters) throws Exception {ValueStateDescriptor<OrderState> descriptor = new ValueStateDescriptor<>("orderState", OrderState.class);orderState = getRuntimeContext().getState(descriptor);}@Overridepublic void processElement(OrderEvent event, Context ctx, Collector<OrderResult> out) throws Exception {// Order processing logic} }public class UserProcessFunction extends KeyedProcessFunction<Long, UserEvent, UserResult> {private ValueState<UserState> userState;@Overridepublic void open(Configuration parameters) throws Exception {ValueStateDescriptor<UserState> descriptor = new ValueStateDescriptor<>("userState", UserState.class);userState = getRuntimeContext().getState(descriptor);}@Overridepublic void processElement(UserEvent event, Context ctx, Collector<UserResult> out) throws Exception {// User processing logic} }
-
效果:
- 每个算子只管理相关的状态数据,减少了每个算子需要恢复的状态大小。
- 作业的维护和调试更加容易,因为状态变得模块化。
b. 按 Key 拆分
通过引入更多的 key,将状态细粒度化。Flink 的 Keyed State 是根据 key 进行分区的,key 的数量越多,每个分区的状态就越小。
-
步骤:
-
重新设计 key:在业务允许的情况下,引入更细粒度的 key,以便将状态均匀分布在多个节点上。例如,不仅按用户 ID 分区,还可以按订单 ID、时间窗口等维度进行分区。
-
使用
keyBy
:确保 Flink 中的状态都是 keyed state,而不是 operator state,确保状态按 key 分布。
stream.keyBy(order -> order.getUserId()).process(new OrderProcessFunction());
-
-
效果:
- 通过更细的 key 拆分,单个任务槽上的状态减少,从而加快恢复速度。
2. 将状态外部化到其他服务
外部化状态意味着将 Flink 作业的部分或全部状态存储在外部服务中,而不是使用 Flink 内部的状态后端(如 RocksDB 或内存)。这通常适用于那些需要频繁共享、访问或跨作业使用的状态。
a. 外部化到 Redis
Redis 是一个流行的键值存储系统,适合存储经常访问的状态数据。通过将部分状态外部化到 Redis,可以减少 Flink 本地状态的负担。
-
步骤:
-
引入 Redis 客户端库:在 Flink 项目中添加 Redis 依赖。可以使用 Redis 官方的
Jedis
库或其他 Redis 客户端库。<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>4.0.1</version> </dependency>
-
连接 Redis:在 Flink 的算子中,通过 Redis 进行读写操作,将状态存储到 Redis。
public class RedisStateProcessFunction extends KeyedProcessFunction<Long, Event, Result> {private transient Jedis jedis;@Overridepublic void open(Configuration parameters) throws Exception {jedis = new Jedis("localhost");}@Overridepublic void processElement(Event event, Context ctx, Collector<Result> out) throws Exception {// 从 Redis 中读取状态String state = jedis.get("state:" + event.getKey());// 更新状态jedis.set("state:" + event.getKey(), updatedState);}@Overridepublic void close() throws Exception {jedis.close();} }
-
使用外部化的状态:通过将部分大状态放入 Redis,可以在 Flink 作业之间共享状态,也可以减少本地状态的存储和恢复负担。
-
-
效果:
- 状态可以跨作业共享,并且外部化的状态不依赖 Flink 内部的状态存储,减少了 Flink 自身的存储压力。
b. 外部化到 Cassandra 或 HBase
对于需要复杂查询或高可靠性的状态管理,可以将状态外部化到分布式数据库如 Cassandra 或 HBase。这些数据库可以存储大规模数据,并且支持分布式访问。
-
步骤:
-
引入 Cassandra/HBase 客户端库:
对于 Cassandra,可以使用 Datastax 的 Cassandra 客户端:<dependency><groupId>com.datastax.oss</groupId><artifactId>java-driver-core</artifactId><version>4.13.0</version> </dependency>
对于 HBase,使用官方的 HBase 客户端:
<dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.4.9</version> </dependency>
-
读写 Cassandra/HBase 状态:
通过适配 Cassandra 或 HBase API,在 Flink 的算子中实现状态的读写操作。// Cassandra 示例 public class CassandraStateProcessFunction extends KeyedProcessFunction<Long, Event, Result> {private transient CqlSession session;@Overridepublic void open(Configuration parameters) throws Exception {session = CqlSession.builder().build();}@Overridepublic void processElement(Event event, Context ctx, Collector<Result> out) throws Exception {// 从 Cassandra 中读取状态ResultSet rs = session.execute("SELECT state FROM state_table WHERE key = ?", event.getKey());// 处理状态并更新session.execute("UPDATE state_table SET state = ? WHERE key = ?", updatedState, event.getKey());}@Overridepublic void close() throws Exception {session.close();} }
-
将状态外部化:通过 Cassandra 或 HBase 提供的分布式存储,可以将 Flink 作业的大规模状态数据转移到外部持久化存储中。
-
-
效果:
- 状态可跨任务共享,持久化存储提供了高可靠性。
- 通过分布式数据库,减少了 Flink 本地存储的负担。
c. 使用外部缓存系统(如 Memcached)
对于那些需要频繁访问但不需要持久化的状态,可以使用外部缓存系统(如 Memcached),这可以显著减少状态的读取和恢复时间。
-
步骤:
- 引入 Memcached 客户端:将 Memcached 的客户端库添加到项目中。
- 通过缓存读取和写入状态:在 Flink 中使用缓存进行状态管理,尤其适用于需要频繁访问的状态。
使用 Memcached 进行状态管理可以提高 Apache Flink 作业中频繁访问的状态的性能。Memcached 是一个高性能的分布式内存对象缓存系统,适用于存储短期状态和减轻 Flink 本地状态存储的负担。
1. 准备工作
a. 安装和配置 Memcached
在使用 Memcached 之前,你需要在你的环境中安装并启动 Memcached。可以使用以下命令安装:
-
在 Ubuntu 上安装:
sudo apt-get update sudo apt-get install memcached
-
在 CentOS 上安装:
sudo yum install memcached
启动 Memcached 服务:
sudo service memcached start
b. 引入 Memcached 客户端库
在 Java 项目中使用 Memcached 通常需要一个客户端库,比如 SpyMemcached 或 XMemcached。你可以在 Maven 项目中添加依赖:
-
SpyMemcached:
<dependency><groupId>net.spy</groupId><artifactId>spymemcached</artifactId><version>2.12.3</version> </dependency>
-
XMemcached:
<dependency><groupId>com.googlecode.xmemcached</groupId><artifactId>xmemcached</artifactId><version>2.4.6</version> </dependency>
2. 在 Flink 中使用 Memcached 进行状态管理
以下是如何在 Flink 作业中使用 Memcached 进行状态管理的步骤:
a. 连接到 Memcached
首先,你需要在 Flink 的算子中连接到 Memcached。使用 SpyMemcached 或 XMemcached 创建一个 Memcached 客户端实例。
import net.spy.memcached.MemcachedClient;import java.net.InetSocketAddress;public class MemcachedConnector {private MemcachedClient client;public MemcachedConnector(String host, int port) throws Exception {// 创建 Memcached 客户端实例client = new MemcachedClient(new InetSocketAddress(host, port));}public MemcachedClient getClient() {return client;}public void close() {client.shutdown();}
}
b. 在 Flink 中使用 Memcached
在 Flink 中的 KeyedProcessFunction
或其他处理函数中使用 Memcached 进行状态管理。
import net.spy.memcached.MemcachedClient;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.util.Collector;public class MemcachedStateProcessFunction extends KeyedProcessFunction<String, MyEvent, MyResult> {private transient MemcachedClient memcachedClient;@Overridepublic void open(Configuration parameters) throws Exception {// 连接到 Memcached 服务器MemcachedConnector connector = new MemcachedConnector("localhost", 11211);memcachedClient = connector.getClient();}@Overridepublic void processElement(MyEvent event, Context ctx, Collector<MyResult> out) throws Exception {// 构建状态键String stateKey = "state:" + event.getKey();// 从 Memcached 中读取状态String state = (String) memcachedClient.get(stateKey);// 如果状态不存在,初始化if (state == null) {state = "initial_state";}// 处理事件并更新状态String updatedState = processEvent(state, event);// 将更新后的状态写回 MemcachedmemcachedClient.set(stateKey, 3600, updatedState); // 3600 秒过期// 输出处理结果out.collect(new MyResult(event.getKey(), updatedState));}@Overridepublic void close() throws Exception {memcachedClient.shutdown();}private String processEvent(String currentState, MyEvent event) {// 根据当前状态和事件更新状态return currentState + "_" + event.getValue();}
}
在这个例子中,Memcached 用于存储和管理状态,而不是将状态存储在 Flink 的本地状态后端中。每次处理新事件时,Flink 会从 Memcached 中读取相关状态,进行处理,然后将更新后的状态写回 Memcached。
c. 状态读取和写入操作
-
读取状态: 使用
memcachedClient.get(key)
从 Memcached 获取状态。如果状态不存在,可以设置一个默认值。 -
写入/更新状态: 使用
memcachedClient.set(key, exp, value)
将状态存储到 Memcached。exp
参数指定状态的过期时间(以秒为单位)。
d. 注意事项
- 状态一致性:Memcached 适合处理不需要严格一致性的状态。如果状态的一致性要求较高,Memcached 可能不适合。
- 内存管理:Memcached 存储在内存中,注意监控和管理内存使用情况,避免内存不足导致状态丢失。
- 状态过期:合理设置状态的过期时间,避免不再需要的状态占用内存资源。
- 集群环境:在分布式环境中使用 Memcached 时,确保各个节点都可以访问同一个 Memcached 实例或集群。
3. 扩展与优化
- 缓存失效策略:根据业务需求设置缓存的失效时间,确保过期的数据不会继续被使用。
- 分布式 Memcached 集群:如果状态量很大,可以使用 Memcached 集群来分担存储压力。
- 异步操作:使用异步 Memcached 客户端以提高性能,避免阻塞 Flink 的处理线程。
总结
使用 Memcached 进行状态管理是一种灵活且高效的方法,尤其适用于频繁访问但不需要持久化的状态。通过将状态存储在 Memcached 中,Flink 作业可以减少本地状态存储的压力,并且通过外部缓存提高状态访问的速度。在实际应用中,需要根据业务需求调整 Memcached 的使用策略,以确保系统的高效性和可靠性。
-
效果:
- 提高频繁访问状态的效率,减少状态恢复时间。
总结
通过状态拆分和外部化,可以显著降低 Flink 状态的恢复时间和存储压力。拆分状态有助于减少单个算子的状态复杂性,而将状态外部化则可以利用外部存储系统的优势来处理大规模、复杂的状态需求。
关键步骤:
- 状态拆分:通过业务逻辑或 key 拆分状态,减少状态的大小和依赖。
- 外部化状态:将状态存储在 Redis、Cassandra、HBase 或其他分布式数据库中,减少 Flink 状态后端的存储和恢复压力。
- 缓存和持久化:对于频繁访问的状态,可以使用外部缓存系统,而对于需要持久化的状态,可以使用分布式数据库。
这种方式结合了灵活性和可靠性,既优化了状态管理,又提升了系统的可扩展性。
相关文章:

flink增量检查点降低状态依赖实现的详细步骤
增量检查点启动恢复的时间是很久的,业务上不能接受,所以可以通过降低状态依赖来减少恢复的时间。 降低状态依赖 尽可能减少状态的复杂性和依赖关系,通过拆分状态或将状态外部化到其他服务中,从而降低恢复的开销。 实施措施&…...

Redis总结,是什么,干什么,怎么利用?
Redis(Remote Dictionary Server)是一个开源的内存数据库,遵守 BSD 协议,它提供了一个高性能的键值(key-value)存储系统,常用于缓存、消息队列、会话存储等应用场景 Redis主要特性 (…...

Vue3状态管理Pinia
Vue3 的 Pinia 使用指南 Pinia 是 Vue3 中官方推荐的状态管理库,作为 Vuex 的替代品,它更简洁易用,并且支持模块化、类型推断和 DevTools 集成。Pinia 非常适合在 Vue3 项目中管理全局状态。 1. 安装 Pinia 首先,我们需要在 Vu…...

box64 安装
ARM运行x86程序 docker安装 box64 安装方法 docker run --name a001 -itd --networkhost -v /www/wwwroot/docker/Box64/f:/f ubuntu:22.04 /bin/bash docker exec -it a001 bash cd /home //创建目录qq547176052 mkdir -p qq547176052 cd /home/qq547176052 apt update apt …...

OpenCV通过鼠标提前ROI(C++实现)
文章目录 鼠标绘制矩形提取ROI任意形状绘制提前ROI 废话不多说,直接上代码 鼠标绘制矩形提取ROI #include <iostream> #include <opencv2\opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/core.hpp>us…...

6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)
目录 一.堆(Heap)的基本介绍 二.堆的常用操作(以小根堆为例) 三.实现代码 3.1 堆结构定义 3.2 向下调整算法* 3.3 初始化堆* 3.4 销毁堆 3.4 向上调整算法* 3.5 插入数据 3.6 删除数据 3.7 返回堆顶数据 四.下篇内容 1.堆排序 2.TopK问题 一…...

【智能终端】HBuilder X 与微信开发者工具集成与调试实战
目录 1. 需求和理解库、框架、平台 1.1 需求 1.2 理解 2.3 库、框架、平台 2.3.1 库(Library) 2.3.2 框架(Framework) 2.3.3 平台(Platform) 2.3.4 总结 2. 使用 HBuilder X 创建第一个 uni-app 应…...

结构体的字节对齐方式(__attribute_pack(packed))#pragma pack())
结构体的字节对齐方式(__attribute_pack(packed))&#pragma pack()) 1、编译器的字节对齐方式 当前编译器都有默认的字节对齐方式, struct PackedStruct {char a;int b;short c; };如上代码段中的结构体,在编译运行后发现他的大小并不…...

若依Ruoyi之智能售货机运营管理系统(新增运营运维工单管理)
idea抽取独立方法快捷键:ctrlaltm TaskDto.java package com.dkd.manage.service.impl;import java.time.Duration; import java.util.List; import java.util.stream.Collectors;import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUti…...

ModuleNotFoundError: No module named ‘keras.layers.core‘怎么解决
问题 ModuleNotFoundError: No module named keras.layers.core,如图所示: 如何解决 将from keras.layers.core import Dense,Activation改为from tensorflow.keras.layers import Dense,Activation,如图所示: 顺利运行…...

C++(三)----内存管理
1.C/C内存分布 看下面这个问题(考考你们之前学的咋样): int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pCh…...

使用 ShuffleNet 模型在 CIFAR-100 数据集上的图像分类
简介 在深度学习领域,图像分类任务是衡量算法性能的重要基准。本文将介绍我们如何使用一种高效的卷积神经网络架构——ShuffleNet,来处理 CIFAR-100 数据集上的图像分类问题。 CIFAR-100 数据集简介 CIFAR-100 数据集是一个广泛使用的图像分类数据集&…...

怎么利用短信接口发送文字短信
在当今这个快节奏的数字时代,即时通讯已成为人们日常生活和工作中不可或缺的一部分。而短信接口(SMS Interface),作为传统与现代通讯技术结合的典范,凭借其高效、稳定、广泛覆盖的特性,在众多领域发挥着不可…...

【C#生态园】提升C#开发效率:掌握这六款单元测试利器
从xUnit到SpecFlow:C#测试驱动开发全指南 前言 在C#开发中,单元测试和模拟框架是至关重要的工具,它们可以帮助开发人员确保代码的质量和可靠性。本文将介绍一些常用的C#单元测试框架和相关库,包括xUnit、NUnit、Moq、FluentAsse…...

【QT】自制一个简单的小闹钟,能够实现语音播报功能
做了一个自制的小闹钟,能够自己输入时间,以及对应的闹铃,时间到了自动播放设定的闹铃,可以随时取消重新设定,采用分文件编译 注意:需要在.pro文件中加入:QT core gui texttospeech 代码…...

基于深度学习的图像描述生成
基于深度学习的图像描述生成(Image Captioning)是一种将计算机视觉与自然语言处理结合的任务,其目标是通过自动生成自然语言来描述输入的图像。该技术能够理解图像中的视觉内容,并生成相应的文本描述,广泛应用于视觉问…...

Linux和C语言(Day11)
一、学习内容 讲解有参函数 形参 和 实参 形参——定义时的参数,形式上的参数,没有实际意义,语法上必须带有数据类型 void fun(int a,int b); void fun(int a[],int n); void fun(char *s); 可以是:变量、数组、指针 实参——调用…...

使用Zlib库进行多文件或者多文件夹的压缩解压缩
zlib库可在git上自己clone下来然后使用cmake工具生成解决方案,编译、生成zlib二进制文件。然后将zlib库引入项目: //zlib库支持 #include "../zlib/include/zlib.h" #ifdef _DEBUG #pragma comment(lib, "../zlib/lib/zlibd.lib") …...

CSGHub携手Nvidia NIM、阿里计算巢打造企业级私有化部署解决方案
强强联合 人工智能与大数据的迅速发展,大模型的推理应用和资产管理已成为企业数字化转型的重要组成部分,企业正寻求高效、安全的AI模型部署解决方案。为应对日益增长的计算需求和复杂的数据管理挑战,CSGHub、Nvidia和阿里云计算巢强强联手&a…...

opencv的球面投影
cv::detail::SphericalProjector 在全景图像拼接任务中,可能需要对多个图像进行球面投影以实现无缝拼接。每个cv::detail::SphericalProjector可以负责一个图像的球面投影操作。通过将多个这样的投影器存储在std::vector中,可以对一组图像依次进行投影处…...

5. 去中心化应用(dApp)
去中心化应用(dApp) 去中心化应用(dApp)是基于区块链技术构建的应用程序,其核心特性是去中心化、透明和开放。dApp与传统应用有许多显著的区别,它们在实现和功能上都带来了新的变革。以下是对dApp的详细介…...

k8s服务发布Ingress
Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、NodePort Service、Ingress,通俗来讲,ingress和之前提到的Service、Deployment,也是一个k8s的资源类型,ingress用于实现用域名的方式访问k8s内部应用。 In…...

区块链学习笔记1--比特币
区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式。 从狭义上来说:区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构,并以密码学的方式保证的不可篡改和不可伪造的分布式账本。 意思就是…...

在 Vite 项目中自动为每个 Vue 文件导入 base.less
在 Vue.js 项目中,使用 Less 作为 CSS 预处理器时,我们通常会创建一个全局的样式文件(如 base.less),用于存放一些全局变量、混合、通用样式等。为了避免在每个 Vue 组件中手动导入这个文件,我们可以通过配…...

RUST 学习之全局变量
RUST 全局变量 rust 全局变量编译期初始化的全局变量静态常量静态变量原子类型的静态变量 运行期初始化的全局变量lazy_staticBox::leakOnceCell & OnceLock 参考文档 rust 全局变量 编译期初始化的全局变量 静态常量 在编译期初始化,所以其赋值只能是表达式…...

代码随想录八股训练营第三十九天| C++
前言 一、说一下 lambda函数? 1.1.Lambda 函数的一般语法如下: 1.2.捕获子句: 二、C 怎么实现一个单例模式? 2.1.懒汉式(线程不安全): 2.2.饿汉式(线程安全): 2.3.双重检查锁定ÿ…...

服务网关工作原理,如何获取用户真实IP?
文章目录 一、什么是网关二、网关工作原理 (★)三、SpringCloud Gateway3.1 Gateway 简介3.2 Gateway 环境搭建3.3 自定义路由规则 (★)3.4 局部过滤器3.5 全局过滤器(案例:获取用户真实IP地址) (★) 补充1:不同类型的客户端如何设…...

单链表的实现(C语言)
目录 1.单链表 1.1 实现单链表 1.1.1 文件创建 1.1.2 链表功能了解 1.1.3 链表的结点 1.1.4 链表的函数声明 1.1.5 链表功能的实现 链表是一种链式结构,物理结构不连续,逻辑结构是连续的,在计算机中链表的实际存储是按照一个结点内存放…...

sql语句的训练2024/9/9
1题 需要看清思路:不是将数据库中的device_id的名字改为user_infors_example,而是在查找的时候,需要将device_id看成user_infors_example来进行查找。 答案 select device_id AS user_infos_example FROM user_profile limit 2 2 当固定查找…...

【QT】常用控件-下
欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:QT 目录 👉🏻QComboBox👉🏻 QSpinBox👉🏻QDateTimeEdit👉🏻QD…...