EMR集群配置外部metastore后理解Spark与Hive元数据配置

在 EMR 集群中创建时通过 hive-site classification 配置了 external metastore(外部 MySQL),但发现 Spark 配置目录下也存在 hive-site.xml,且内容与 Hive 侧不完全一致。本文分析两者的配置差异及 Spark 访问 Hive Metastore 的实际链路。

Hive 侧配置 (/etc/hive/conf/hive-site.xml)

<property>
    <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:mysql://172.31.14.46:3306/hive_metastore?createDatabaseIfNotExist=true</value>
</property>
<property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>org.mariadb.jdbc.Driver</value>
</property>
<property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>hive</value>
</property>
<property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>hive</value>
</property>

Spark 侧配置 (/etc/spark/conf/hive-site.xml)

<property>
    <name>hive.metastore.uris</name>
    <value>thrift://ip-192-168-24-10.cn-north-1.compute.internal:9083</value>
</property>
<property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>hive</value>
</property>
<property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>hive</value>
</property>
<property>
    <name>hive.server2.thrift.url</name>
    <value>jdbc:hive2://ip-192-168-24-10.cn-north-1.compute.internal:10000</value>
</property>
<property>
    <name>hive.metastore.connect.retries</name>
    <value>15</value>
</property>

Spark 侧缺少 ConnectionURL 和 ConnectionDriverName,因此无法直接连接 MySQL 数据库。Spark 真正依赖的是 hive.metastore.uris,通过 Thrift 协议连接 Hive Metastore 服务。

访问链路如下

  • Spark 通过 hive.metastore.uris 连接本地 master 节点上的 Hive Metastore Thrift 服务(端口 9083)
  • Hive Metastore 服务通过自身的 hive-site.xml 中的 ConnectionURL 连接外部 MySQL
Spark → (thrift:9083) → Hive Metastore Service → (jdbc:3306) → MySQL (外部数据库)

EMR 在集群配置阶段,会将用户通过 hive-site classification 传入的参数同时分发到 Hive 和 Spark 的 conf 目录,但会做裁剪:

  • ConnectionURL 和 Driver 被有意从 Spark 侧去掉(避免 Spark 绕过 Metastore 服务直接连数据库)

Spark 启动时会自动加载 $SPARK_CONF_DIR(即 /etc/spark/conf/)下的 hive-site.xml。只要 classpath 中存在该文件,SparkSession 在启用 enableHiveSupport() 时就会读取其中的配置。

Hive 和 Spark 建表插入数据

分别用 Hive 和 Spark 在 test_db 中创建表并插入数据,然后检查 MySQL metastore 和 HDFS 的变化。

# Hive 建表插入
sudo -u hadoop hive -e "
CREATE DATABASE IF NOT EXISTS test_db;
CREATE TABLE test_db.hive_test_table (id INT, name STRING, created_at STRING)
  ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
INSERT INTO test_db.hive_test_table VALUES (1,'alice','2026-03-24'),(2,'bob','2026-03-24'),(3,'charlie','2026-03-24');
"

# Spark 建表插入
sudo -u hadoop spark-sql -e "
CREATE TABLE test_db.spark_test_table (id INT, name STRING, created_at STRING)
  USING hive OPTIONS (fileFormat 'textfile', fieldDelim ',');
INSERT INTO test_db.spark_test_table VALUES (4,'dave','2026-03-24'),(5,'eve','2026-03-24'),(6,'frank','2026-03-24');
"

建表后查询 MySQL,可以看到两张表的元数据都写入了同一个 metastore:

DBS 表:新增 test_db

DB_ID NAME LOCATION
1 default hdfs://.../user/hive/warehouse
2 test_db hdfs://.../user/hive/warehouse/test_db.db

TBLS 表:Hive 和 Spark 各创建了一张表

TBL_ID DB 表名 类型 创建时间 创建者
2 test_db hive_test_table MANAGED_TABLE 06:29:30 Hive
3 test_db spark_test_table MANAGED_TABLE 06:30:13 Spark

COLUMNS_V2 表:两张表各 3 列 (id INT, name STRING, created_at STRING)

SDS 表(存储描述):两张表都存储在 HDFS,格式均为 TextInputFormat

MySQL metastore 只存元数据(表名、列定义、存储位置等),真正的数据存在 HDFS 上:

/user/hive/warehouse/test_db.db/
├── hive_test_table/
│   └── 000000_0                  # Hive(Tez) 写入,单个文件
└── spark_test_table/
    ├── part-00000-ae729811-...   # Spark 写入的 partition 0
    └── part-00001-ae729811-...   # Spark 写入的 partition 1

文件内容都是纯文本 CSV:

# hive_test_table/000000_0
1,alice,2026-03-24
2,bob,2026-03-24
3,charlie,2026-03-24

# spark_test_table/part-00000-*
4,dave,2026-03-24

# spark_test_table/part-00001-*
5,eve,2026-03-24
6,frank,2026-03-24

Hive vs Spark 写入差异

对比项 Hive (Tez) Spark
文件命名 000000_0 part-NNNNN-<uuid>
文件数量 1 个(单 reducer) 2 个(多 partition)
数据格式 相同(CSV 文本) 相同(CSV 文本)
元数据存储 同一个 MySQL metastore 同一个 MySQL metastore

这验证了 Hive 和 Spark 通过同一个 external metastore(MySQL)管理元数据,两者创建的表互相可见、共享同一个元数据存储,实际数据都存放在 HDFS 的 /user/hive/warehouse/ 下。

posted @ 2026-03-24 16:34  zhaojie10  阅读(52)  评论(0)    收藏  举报