一、简介

说的是持久化状态的数据存放在哪
默认情况下,所有的状态都存储在 JVM 的堆内存中,在状态数据过多的情况下,这种方式很有可能导致内存溢出,因此 Flink 该提供了其它方式来存储状态数据,这些存储方式统一称为状态后端 (或状态管理器)

Flink中定义了三种State Backend

  1. The MemoryStateBackend:内存
  2. The FsStateBackend:文件系统,比如hdfs
  3. The RocksDBStateBackend:DB

就是说数据可以存在内存中,也可以存在HDFS中,也可以存在数据库中

状态(state):
包含算子状态、监控状态,就是task在执行时产生的一些结果数据需要存储起来 (以状态这种形式存储)

检查点(checkpoint):
存储的是应用迄今为止计算后的结果

State Backend(状态的后端存储):

  1. **默认情况下,state会保存在taskmanager的内存中,**checkpoint会存储在JobManager的内存中。
  2. state的store和checkpoint的位置取决于State Backend的配置(env.setStateBackend(…)

Restart Strategies(重启策略)

  1. Flink支持不同的重启策略,以便在故障发生时控制作业如何重启
  2. 集群在启动时会伴随一个默认的重启策略,在没有定义具体重启策略时会使用该默认策略
  3. 如果在工作提交时指定了一个重启策略,该策略会覆盖集群的默认策略
  4. 默认的重启策略可通过Flink的配置文件flink-conf.yaml指定(配置参数restart-strategy)

常用的重启策略

  1. 固定间隔(Fixed delay)
  2. 失败率(Failure rate)
  3. 无重启(No restart)

二、三种模式详细说明

MemoryStateBackend

  1. 内存级的状态后端
  2. 将键控状态作为内存中的对象进行管理,将它们存储在TaskManager的JVM堆上
  3. 执行checkpoint的时候,会把state的快照数据保存到jobmanager的内存中
  4. 特点: 高效、低延迟、但不稳定;在生产环境下不建议使用

FsStateBackend

  1. 基于文件系统进行存储,可以是本地文件系统,也可以是 HDFS 等分布式文件系统。 需要注意而是虽然选择使用了 FsStateBackend ,但正在进行的state数据仍是存储在 TaskManager 的内存中的,只有在 checkpoint 时,才会将state的快照数据写入到指定文件系统(hdfs)上。
  2. 特点:同时拥有内存级的访问速度和更好的容错保证可使用hdfs等分布式文件系统

RocksDBStateBackend

  1. RocksDBStateBackend 在本地文件系统中维护状态,state会直接写入本地rocksdb中。同时RocksDB需要配置一个远端的filesystem。
    uri(一般是HDFS),在做checkpoint的时候,会把本地的数据直接复制到filesystem中。fail over的时候从filesystem中恢复到本地。
    RocksDB克服了state受内存限制的缺点,同时又能够持久化到远端文件系统中,比较适合在生产中使用

三、如果是存在文件系统中则在Flink中的具体使用

3.1 两种模式

  1. 在代码中配置,生效范围为当前job
val env = StreamExecutionEnvironment.getExecutionEnvironment()
env.setStateBackend(...)//只针对这一个job
  1. 在配置文件中设置,生效范围,部署在这个集群中的所有job
state.backend: filesystem
state.checkpoints.dir: hdfs://namenode:port/flink/checkpoints
#检查点中保存的数据是否采用增量的方式
state.backend.incremental: false
#flink应用失败后的重启策略
jobmanager.execution.failover-strategy: region

3.2 配置完成后验证

  1. 配置文件配置完成之后,重新启动Flink,检查全局state backend配置是否成功
[root@flink flink-1.10.0]# pwd
/opt/install/flink-1.10.0
[root@flink flink-1.10.0]# bin/start-cluster.sh
Starting cluster.
Starting standalonesession daemon on host flink.
Starting taskexecutor daemon on host flink.
  1. 打开UI界面查看日志信息 hadoop10:8081
  2. 注意:因为state backend需要将数据同步到HDFS,所以Flink需要和Hadoop集成。需要在环境变量中配
    置HADOOP_CLASSPATH
vi /etc/profile,然后最下面添加以下内容
export HADOOP_CLASSPATH=`hadoop classpath`
  1. 然后更新一下 source /etc/profile

3.3 结合着检查点以及状态完成数据的故障恢复

  1. 在flink配置文件中配置state backend
  2. 在flink代码中开启checkpoint
  3. 把flink代码打包,通过flink UI界面传输到flink环境中执行
  4. 确认checkpoint的配置是否生效
  5. flink数据mysql Flink数据存储_重启

  6. 让程序执行计算结果,在taskManager中查看
  7. 取消掉job
  8. 到hdfs中复制生成的checkpoint路径
  9. flink数据mysql Flink数据存储_flink_02

  10. 重新启动flink程序,在checkpoint的位置,输入恢复数据需要的hdfs路径
  11. flink数据mysql Flink数据存储_数据_03

四、如果是存在RocksDB中则在Flink中的具体使用

第一步:导入依赖

<dependency>
  <groupId>org.rocksdb</groupId>
  <artifactId>rocksdbjni</artifactId>
  <version>5.11.3</version>
</dependency>

第二步:通过程序验证数据的写入和读取

import org.rocksdb.Options;
import org.rocksdb.RocksDB;
import org.rocksdb.RocksDBException;
public class RocksDBTest {
    //因为RocksDB是由C++编写的,在Java中使用首先需要加载Native库
    static{
        RocksDB.loadLibrary();
    }
    public static void main(String[] args) throws RocksDBException {
        //1.打开数据库
        //1.1 创建数据库配置
        Options dbOpt = new Options();
        //1.2 配置当数据库不存在时自动创建
        dbOpt.setCreateIfMissing(true);
        //1.3 打开数据库,因为RocksDB默认是保存在本地磁盘,所以需要指定位置
        RocksDB rdb = RocksDB.open("/Users/lijun/Downloads/flink_input/rocksdb");
        //2.写入数据
        //2.1 RocksDB是以字节流的方式写入数据库中,所以我们需要将字符串转换为字节流再写入
        byte[] key = "张五".getBytes();
        byte[] value = "20".getBytes();
        //2.2 调用put方法写入数据
        rdb.put(key,value);
        System.out.println("写入数据到RocksDB完成");
        //3.调用get方法读取数据
        System.out.println("从RocksDB读取key="+new String(key)+"的value为"+new String(rdb.get(key)));
        //4.移除数据
        rdb.delete(key);
        //关闭资源
        rdb.close();
        dbOpt.close();
    }
}

效果确认
第一步:确认RocksDB中存储的state值
第二步:确认hdfs上对应的checkpoints中的内容