一、背景与痛点
在使用 Flink SQL Client 进行实时计算开发时,你是否遇到过这样的场景:
-
花费大量时间创建好
orders_source、products_source、category_sales_sink等表定义 -
调试好一个窗口聚合任务,成功运行并验证结果
-
第二天重启 Flink SQL Client,准备继续开发时,发现所有表定义都消失了
-
不得不重新执行一大段
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
3.3 下载 Flink Hive Connector Jar 包
根据 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
六、在 Flink SQL Client 中使用 Hive Catalog
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 TABLES、SELECT),只支持 DDL 语句(CREATE TABLE、USE CATALOG、USE 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,我们可以:
-
一次创建,永久使用:表定义不会因重启而丢失
-
团队共享:多个开发者可共享同一套表定义
-
开发效率提升:告别重复的建表语句,专注于业务逻辑开发
附录:相关命令速查
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