随着业务数据的飞速积累,数仓存储成本往往成为企业 IT 预算中的"隐形杀手"。面对海量历史数据,直接删除可惜,保留又太贵。最优雅的解决方案是将 3 年前的"冷数据"归档至低成本的对象存储(如 S3),并利用 Trino 实现即席查询。本文将手把手带你搭建一套基于 Hive Metastore (HMS) 和 Trino 的轻量级数据湖查询引擎,实现本地 S3 数据的无缝查询与联邦分析。

架构蓝图:为何选择 Trino + HMS
在查询 S3 数据时,Trino 并不直接读取文件的物理结构,而是依赖元数据服务(Metastore)来获取表结构、分区信息及文件路径。
- 对象存储(S3/MinIO):作为数据湖的存储层,存放 Parquet、ORC 或 JSON 格式的冷数据。
- Hive Metastore (HMS):作为元数据层,相当于数据的"目录",记录表与 S3 路径的映射关系。
- Trino:作为计算层,通过连接器读取 HMS 元数据,并行扫描 S3 数据进行计算。
第一步:构建元数据中枢(HMS 安装与配置)
虽然 Trino 支持直接配置,但为了兼容性和扩展性,部署一个独立的 HMS 是生产环境的最佳实践。这里我们使用 MySQL 存储元数据,并配合 Docker 快速启动 HMS。
1. 准备 MySQL 元数据库
首先,在 MySQL 中创建 HMS 所需的库和用户:
sql
CREATE DATABASE hive_metastore;
CREATE USER 'hive'@'%' IDENTIFIED BY 'hive_password';
GRANT ALL PRIVILEGES ON hive_metastore.* TO 'hive'@'%';
FLUSH PRIVILEGES;
2. 配置 HMS 环境
HMS 需要知道数据库连接信息以及 S3 的访问凭证。创建 hive-site.xml 配置文件:
xml
<configuration>
<!-- 数据库连接配置 -->
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://mysql-host:3306/hive_metastore?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>hive</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>hive_password</value>
</property>
<!-- S3 访问凭证(如果是本地 MinIO,需配置 Endpoint) -->
<property>
<name>fs.s3a.access.key</name>
<value>YOUR_ACCESS_KEY</value>
</property>
<property>
<name>fs.s3a.secret.key</name>
<value>YOUR_SECRET_KEY</value>
</property>
<!-- 若使用 MinIO,需指定 Endpoint -->
<property>
<name>fs.s3a.endpoint</name>
<value>http://minio-host:9000</value>
</property>
<property>
<name>fs.s3a.path.style.access</name>
<value>true</value>
</property>
</configuration>
3. 启动 HMS 服务
使用官方 Docker 镜像启动 HMS 服务,并挂载配置文件:
bash
docker run -d \
--name hive-metastore \
-p 9083:9083 \
-v $(pwd)/hive-site.xml:/opt/hive/conf/hive-site.xml \
apache/hive:3.1.3 \
hive --service metastore
服务启动后,HMS 将监听 9083 端口,等待 Trino 的连接。
第二步:配置 Trino 计算引擎
Trino 的配置非常模块化,我们只需在 etc/catalog 目录下创建一个 hive.properties 文件,即可将 S3 数据源接入。
properties
connector.name=hive
hive.metastore.uri=thrift://hive-metastore-host:9083
# S3 配置(Trino 也需要知道 S3 凭证)
hive.s3.endpoint=http://minio-host:9000
hive.s3.path-style-access=true
hive.s3.aws-access-key=YOUR_ACCESS_KEY
hive.s3.aws-secret-key=YOUR_SECRET_KEY
# 性能优化:开启并行读取
hive.parquet.use-column-names=true
hive.recursive-directories=true
重启 Trino 服务后,你将在 Trino CLI 中看到名为 hive 的 Catalog。
第三步:实战演练------冷数据归档与查询
假设我们有一个电商订单表 orders,现在需要将 2023 年之前的数据归档到 S3。
1. 数据归档(模拟)
在实际生产中,你可以使用 Spark 或 DistCp 将 HDFS 上的历史分区数据移动到 S3。假设我们已经将数据移动到了 s3://archive-bucket/orders/year=2022/,且文件格式为 Parquet。
2. 在 Trino 中创建映射表
我们不需要重新加载数据,只需在 Trino 中创建一张外表指向该路径:
sql
CREATE TABLE hive.archive.orders_2022 (
order_id VARCHAR,
user_id VARCHAR,
amount DOUBLE,
order_date DATE
)
WITH (
format = 'PARQUET',
external_location = 's3://archive-bucket/orders/year=2022/'
);
3. 查询 S3 冷数据
现在,你可以像查询普通数据库一样查询 S3 上的文件:
sql
-- 统计 2022 年归档数据的总金额
SELECT sum(amount) FROM hive.archive.orders_2022;
进阶场景:联邦查询(Hot + Cold Data)
最强大的功能在于联邦查询。假设你的 MySQL 中存有 2024 年的热数据,S3 上有 2022-2023 年的冷数据,Trino 可以一键打通:
sql
-- 跨源联合分析:计算近三年的用户总消费
SELECT
user_id,
sum(total_amount) as lifetime_value
FROM (
-- 热数据:来自 MySQL
SELECT user_id, amount as total_amount FROM mysql.shop.orders_2024
UNION ALL
-- 冷数据:来自 S3
SELECT user_id, amount as total_amount FROM hive.archive.orders_2022
UNION ALL
SELECT user_id, amount as total_amount FROM hive.archive.orders_2023
)
GROUP BY user_id
ORDER BY lifetime_value DESC
LIMIT 10;
总结
通过 Trino + HMS 的组合,我们不仅解决了冷数据存储成本高的问题,还打破了数据孤岛。这种架构让 S3 真正成为了"数据湖",而非"数据沼泽"。对于团队而言,这意味着无需迁移数据即可对历史归档进行即时分析,极大地释放了数据的潜在价值。