Flink SQL 元数据持久化实战:从“每次重启表消失”到“Hive Metastore 永久存储”

一、背景与痛点

在使用 Flink SQL Client 进行实时计算开发时,你是否遇到过这样的场景:

  1. 花费大量时间创建好 orders_sourceproducts_sourcecategory_sales_sink 等表定义

  2. 调试好一个窗口聚合任务,成功运行并验证结果

  3. 第二天重启 Flink SQL Client,准备继续开发时,发现所有表定义都消失了

  4. 不得不重新执行一大段 CREATE TABLE 语句,重复劳动,效率极低

这是因为 Flink SQL Client 默认使用内存 Catalog(GenericInMemoryCatalog),所有表定义只存在于当前会话中,一旦退出或重启,元数据全部丢失。

解决方案 :将元数据持久化到 Hive Metastore,使表定义跨会话、跨集群共享,一次创建,永久使用。

二、整体思路

步骤 内容
1 准备 Flink Hive Connector 依赖 Jar 包
2 将 Hive 相关依赖复制到 Flink lib 目录
3 配置 hive-site.xml,指定 Hive Metastore 服务地址
4 启动 Hive Metastore 服务
5 在 Flink SQL Client 中创建并切换 Hive Catalog
6 在 Hive Catalog 下创建表,验证持久化

三、环境准备

3.1 版本信息

组件 版本
Flink 1.17.0
Hive 3.1.3
Scala 2.12
Hadoop 3.1.3
MySQL 5.7.28

3.2 安装自定义脚本(可选但推荐)

为了方便将文件同步到集群所有节点,可以自定义 xsync 脚本:

bash

复制代码
vim /usr/local/bin/xsync

脚本内容:

bash

复制代码
#!/bin/bash

#1. 判断参数个数
if [ $# -lt 1 ]
then
    echo Not Enough Arguement!
    exit;
fi

#2. 遍历集群所有机器
for host in hadoop102 hadoop103 hadoop104
do
    echo ====================  $host  ====================
    #3. 遍历所有目录,挨个发送
    for file in $@
    do
        #4. 判断文件是否存在
        if [ -e $file ]
            then
                #5. 获取父目录
                pdir=$(cd -P $(dirname $file); pwd)
                #6. 获取当前文件的名称
                fname=$(basename $file)
                ssh $host "mkdir -p $pdir"
                rsync -av $pdir/$fname $host:$pdir
            else
                echo $file does not exists!
        fi
    done
done

添加执行权限:

bash

复制代码
chmod +x /usr/local/bin/xsync

同步批量查看进程脚本 jpsall

bash

复制代码
vim /usr/local/bin/jpsall

bash

复制代码
#!/bin/bash
for host in hadoop102 hadoop103 hadoop104
do
    echo =============== $host ===============
    ssh $host jps
done

bash

复制代码
chmod +x /usr/local/bin/jpsall

根据 Flink 和 Hive 版本,下载对应的连接器 Jar 包:

bash

复制代码
cd /opt/module/flink-1.17.0/lib

# 下载 Flink Hive Connector
wget https://repo.maven.apache.org/maven2/org/apache/flink/flink-sql-connector-hive-3.1.3_2.12/1.17.0/flink-sql-connector-hive-3.1.3_2.12-1.17.0.jar

3.4 复制 Hive 依赖 Jar 包

Flink Hive Connector 需要 Hive 自身的依赖包才能工作:

bash

复制代码
# 从 Hive 安装目录复制核心依赖
cp /opt/module/hive/lib/hive-exec-3.1.3.jar /opt/module/flink-1.17.0/lib/
cp /opt/module/hive/lib/hive-metastore-3.1.3.jar /opt/module/flink-1.17.0/lib/
cp /opt/module/hive/lib/hive-hcatalog-core-3.1.3.jar /opt/module/flink-1.17.0/lib/

提示 :如果 Flink 的 lib 目录中已有 Hadoop 相关依赖,可跳过 Hadoop Jar 包的复制,避免冲突。

3.5 同步到所有节点

如果你有 Flink 集群(多台机器),需要将 lib 目录同步到所有节点:

bash

复制代码
cd /opt/module/flink-1.17.0
xsync lib/

如果没有 xsync 脚本,可以手动在每台机器上复制,或使用 scp 命令。

四、配置 Hive Metastore

4.1 创建 hive-site.xml

在 Flink 的 conf 目录下创建 hive-site.xml,指向 Hive Metastore 服务:

bash

复制代码
vim /opt/module/flink-1.17.0/conf/hive-site.xml

写入以下内容:

xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <!-- 关键配置:Flink 通过此地址连接 Hive Metastore -->
  <property>
    <name>hive.metastore.uris</name>
    <value>thrift://hadoop102:9083</value>
  </property>

  <!-- Hive 在 HDFS 上的数据仓库目录 -->
  <property>
    <name>hive.metastore.warehouse.dir</name>
    <value>/user/hive/warehouse</value>
  </property>
</configuration>

4.2 同步配置文件到所有节点

bash

复制代码
cd /opt/module/flink-1.17.0
xsync conf/hive-site.xml

五、启动 Hive Metastore

hadoop102 上启动 Hive Metastore 服务(只需一台机器启动,其他机器通过配置连接):

bash

复制代码
cd /opt/module/hive
nohup bin/hive --service metastore &

验证是否启动成功:

bash

复制代码
# 检查进程
jps | grep RunJar

# 检查端口(默认 9083)
netstat -tlnp | grep 9083

预期输出:

text

复制代码
tcp6       0      0 :::9083                 :::*                    LISTEN      34368/java

6.1 启动并创建 Catalog

bash

复制代码
cd /opt/module/flink-1.17.0
./bin/sql-client.sh

在 SQL Client 中执行:

sql

复制代码
-- 1. 创建 Hive Catalog
CREATE CATALOG myhive WITH (
  'type' = 'hive',
  'hive-conf-dir' = '/opt/module/flink-1.17.0/conf'
);

-- 2. 查看 Catalog
SHOW CATALOGS;

-- 3. 切换到 Hive Catalog
USE CATALOG myhive;

-- 4. 创建业务数据库
CREATE DATABASE IF NOT EXISTS flink_demo;
USE flink_demo;

6.2 创建持久化的表

sql

复制代码
-- 订单源表(Kafka)
CREATE TABLE orders_source (
  order_id INT,
  product_id INT,
  quantity INT,
  order_time TIMESTAMP_LTZ(3),
  status STRING,
  `op` STRING,
  WATERMARK FOR order_time AS order_time - INTERVAL '1' SECOND
) WITH (
  'connector' = 'kafka',
  'topic' = 'retail_db.retail_db.orders',
  'properties.bootstrap.servers' = 'hadoop102:9092,hadoop103:9092,hadoop104:9092',
  'properties.group.id' = 'flink-orders-group',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'debezium-json',
  'debezium-json.timestamp-format.standard' = 'ISO-8601'
);

-- 商品源表(Kafka)
CREATE TABLE products_source (
  product_id INT,
  product_name STRING,
  category STRING,
  price DECIMAL(10,2),
  stock INT,
  `op` STRING
) WITH (
  'connector' = 'kafka',
  'topic' = 'retail_db.retail_db.products',
  'properties.bootstrap.servers' = 'hadoop102:9092,hadoop103:9092,hadoop104:9092',
  'properties.group.id' = 'flink-products-group',
  'scan.startup.mode' = 'earliest-offset',
  'format' = 'debezium-json'
);

-- 品类销售额结果表(MySQL Sink)
CREATE TABLE category_sales_sink (
  window_start TIMESTAMP(3),
  category STRING,
  total_sales DECIMAL(10,2),
  PRIMARY KEY (window_start, category) NOT ENFORCED
) WITH (
  'connector' = 'jdbc',
  'url' = 'jdbc:mysql://hadoop102:3306/retail_db',
  'table-name' = 'minute_category_sales',
  'username' = 'root',
  'password' = '123456',
  'sink.buffer-flush.max-rows' = '1',
  'sink.buffer-flush.interval' = '1s'
);

6.3 验证表已创建

sql

复制代码
SHOW TABLES;

预期输出:

text

复制代码
+---------------------+
|          table name |
+---------------------+
| category_sales_sink |
|       orders_source |
|     products_source |
+---------------------+
3 rows in set

七、验证持久化效果

7.1 退出并重启 SQL Client

sql

复制代码
EXIT;

bash

复制代码
./bin/sql-client.sh

7.2 重新连接 Catalog 并查看表

sql

复制代码
USE CATALOG myhive;
USE flink_demo;
SHOW TABLES;

如果三张表都仍然存在,说明持久化成功!

text

复制代码
+---------------------+
|          table name |
+---------------------+
| category_sales_sink |
|       orders_source |
|     products_source |
+---------------------+
3 rows in set

八、最佳实践:使用 init.sql 自动初始化

创建一个 init.sql 文件,用于每次启动 Flink SQL Client 时自动加载:

bash

复制代码
vim /opt/module/flink-1.17.0/init.sql

sql

复制代码
-- /opt/module/flink-1.17.0/init.sql
CREATE CATALOG myhive WITH (
  'type' = 'hive',
  'hive-conf-dir' = '/opt/module/flink-1.17.0/conf'
);

USE CATALOG myhive;
USE flink_demo;

启动时自动加载:

bash

复制代码
./bin/sql-client.sh -i init.sql

注意init.sql不支持 查询语句(如 SHOW TABLESSELECT),只支持 DDL 语句(CREATE TABLEUSE CATALOGUSE DATABASE 等)。

九、踩坑记录

坑 1:Embedded metastore is not allowed

现象

text

复制代码
java.lang.IllegalArgumentException: Embedded metastore is not allowed. 
Make sure you have set a valid value for hive.metastore.uris

原因hive-site.xml 中缺少 hive.metastore.uris 配置,Flink 默认使用内嵌 Metastore。

解决 :在 hive-site.xml 中添加:

xml

复制代码
<property>
  <name>hive.metastore.uris</name>
  <value>thrift://hadoop102:9083</value>
</property>

坑 2:CREATE CATALOG IF NOT EXISTS 语法错误

现象

text

复制代码
ParseException: Encountered "NOT" at line 2, column 19.

原因 :Flink 1.17 的 CREATE CATALOG 语法不支持 IF NOT EXISTS

解决:直接使用:

sql

复制代码
CREATE CATALOG myhive WITH (...);

坑 3:初始化脚本中包含 SHOW TABLES 导致失败

现象

text

复制代码
UnsupportedOperationException: Unsupported statement for configuring session: SHOW TABLES;

原因init.sql 初始化脚本只支持 DDL 语句,不支持查询语句。

解决 :将 init.sql 限制为仅包含必要的 DDL:

sql

复制代码
CREATE CATALOG myhive WITH (...);
USE CATALOG myhive;
USE flink_demo;

坑 4:HDFS 未启动导致创建数据库失败

现象

text

复制代码
MetaException: Got exception: java.net.ConnectException: Call From hadoop102 to hadoop102:8020 failed...

原因:Hive 创建数据库时需要在 HDFS 上创建目录,但 HDFS 服务未启动。

解决

bash

复制代码
start-dfs.sh

坑 5:Hive Metastore 未启动

现象

text

复制代码
java.net.ConnectException: Connection refused: hadoop102/192.168.102.102:9083

原因:Hive Metastore 服务没有启动。

解决

bash

复制代码
cd /opt/module/hive
nohup bin/hive --service metastore &
netstat -tlnp | grep 9083  # 确认端口已监听

十、总结

对比项 内存 Catalog(默认) Hive Catalog
表定义生命周期 随会话结束而消失 永久存储
多会话共享 ❌ 不支持 ✅ 支持
跨集群共享 ❌ 不支持 ✅ 支持(共享 Metastore)
每次启动 需重建所有表 -i init.sql 一键加载
适用场景 临时测试 生产开发、团队协作

通过将 Flink 元数据持久化到 Hive Metastore,我们可以:

  1. 一次创建,永久使用:表定义不会因重启而丢失

  2. 团队共享:多个开发者可共享同一套表定义

  3. 开发效率提升:告别重复的建表语句,专注于业务逻辑开发

附录:相关命令速查

bash

复制代码
# 启动 Hive Metastore
cd /opt/module/hive
nohup bin/hive --service metastore &

# 检查 Metastore 状态
jps | grep RunJar
netstat -tlnp | grep 9083

# 同步文件到集群所有节点
xsync /opt/module/flink-1.17.0/lib/
xsync /opt/module/flink-1.17.0/conf/hive-site.xml

# 启动 Flink SQL Client(带初始化脚本)
cd /opt/module/flink-1.17.0
./bin/sql-client.sh -i init.sql

# 查看持久化的表
USE CATALOG myhive;
USE flink_demo;
SHOW TABLES;

# 重启 Flink 集群
./bin/stop-cluster.sh && ./bin/start-cluster.sh
相关推荐
泰克教育官方账号2 小时前
泰涨知识 | Hive集群环境部署
数据仓库·hive·hadoop
kali-Myon14 小时前
某校园门禁系统高危 SQL 注入漏洞挖掘复盘
数据库·sql·安全·web安全
龙石数据16 小时前
MySQL 全量同步到 Hive 怎么做?三步配置教程
数据库·hive·mysql·数据治理·数据中台
心中有国也有家19 小时前
E-Brufen 技术选型全景:Flutter + 鸿蒙 + Hive CE
hive·hadoop·学习·flutter·华为·harmonyos
白露与泡影20 小时前
慢 SQL 不一定是 SQL 慢:一次 MySQL 连接池耗尽的故障定位
数据库·sql·mysql
ruxshui21 小时前
微服务下单跨服务数据不一致问题分析笔记
sql·微服务·架构
阿坤带你走近大数据1 天前
Oracle新老SQL写法对比
数据库·sql·oracle
HackTwoHub1 天前
某单位 CMS 完整渗透链、SQL 注入→后台拿权→绕过宝塔 Waf 上线 shell
数据库·人工智能·sql·安全·网络安全·系统安全·安全架构