|
| 1 | +<!-- |
| 2 | +Licensed to the Apache Software Foundation (ASF) under one |
| 3 | +or more contributor license agreements. See the NOTICE file |
| 4 | +distributed with this work for additional information |
| 5 | +regarding copyright ownership. The ASF licenses this file |
| 6 | +to you under the Apache License, Version 2.0 (the |
| 7 | +"License"); you may not use this file except in compliance |
| 8 | +with the License. You may obtain a copy of the License at |
| 9 | +
|
| 10 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | +
|
| 12 | +Unless required by applicable law or agreed to in writing, |
| 13 | +software distributed under the License is distributed on an |
| 14 | +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | +KIND, either implied. See the License for the specific |
| 16 | +language governing permissions and limitations |
| 17 | +under the License. |
| 18 | +--> |
| 19 | + |
| 20 | +# Hive Docker 环境 |
| 21 | + |
| 22 | +Doris thirdparty 回归测试使用的 Hive2/Hive3 Docker Compose 模板与引导脚本。 |
| 23 | + |
| 24 | +英文版: [README.md](README.md) |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## 架构 |
| 29 | + |
| 30 | +Hive 启动被拆分为三层互相独立的抽象: |
| 31 | + |
| 32 | +### Layer 1 — Docker 服务 |
| 33 | + |
| 34 | +所有服务均使用 `network_mode: host`,端口直接暴露在宿主机上。 |
| 35 | + |
| 36 | +| 服务 | 职责 | Hive3 端口 | Hive2 端口 | |
| 37 | +|---|---|---|---| |
| 38 | +| `hive-server` | HiveServer2 (SQL/JDBC 入口) | `13000` | `10000` | |
| 39 | +| `hive-metastore` | Hive Metastore (HMS) | `9383` | `9083` | |
| 40 | +| `hive-metastore-postgresql` | Metastore 元数据库 | `5732` | `5432` | |
| 41 | +| `namenode` | HDFS NameNode | `8320` | `8020` | |
| 42 | +| `datanode` | HDFS DataNode | — | — | |
| 43 | + |
| 44 | +容器名前缀由 `CONTAINER_UID`(定义在 `custom_settings.env`)指定。 |
| 45 | +例如 `CONTAINER_UID=doris-jack-` → 容器名为 `doris-jack-hive3-server`。 |
| 46 | + |
| 47 | +### Layer 2 — 刷新模块(`--hive-modules`) |
| 48 | + |
| 49 | +每个模块对应 `scripts/data/` 下的一个目录或一组专用脚本。 |
| 50 | +模块是**增量刷新**的:只有内容 SHA 发生变化的模块才会被重新执行。 |
| 51 | + |
| 52 | +| 模块 | 源路径 | 内容 | |
| 53 | +|---|---|---| |
| 54 | +| `default` | `scripts/data/default/` | `default` 库中的基础外部表 | |
| 55 | +| `multi_catalog` | `scripts/data/multi_catalog/` | 多格式、多路径的外部表用例 | |
| 56 | +| `partition_type` | `scripts/data/partition_type/` | 各类分区类型覆盖(int、string、date 等)| |
| 57 | +| `statistics` | `scripts/data/statistics/` | 表统计与空表统计相关用例 | |
| 58 | +| `tvf` | `scripts/data/tvf/` | TVF 测试数据(上传到 HDFS)| |
| 59 | +| `regression` | `scripts/data/regression/` | 特殊回归数据集(serde、分隔符等)| |
| 60 | +| `test` | `scripts/data/test/` | 轻量级冒烟测试数据 | |
| 61 | +| `preinstalled_hql` | `scripts/create_preinstalled_scripts/*.hql` | 约 77 个 HQL 文件,通过 `xargs -P` 并行执行 | |
| 62 | +| `view` | `scripts/create_view_scripts/create_view.hql` | View 定义 | |
| 63 | + |
| 64 | +### Layer 3 — Bootstrap 组(`HIVE_BOOTSTRAP_GROUPS`) |
| 65 | + |
| 66 | +控制模块内哪些文件会被纳入刷新范围。 |
| 67 | + |
| 68 | +| 组 | 含义 | |
| 69 | +|---|---| |
| 70 | +| `common` | Hive2 与 Hive3 共用 | |
| 71 | +| `hive2_only` | 仅 Hive2 使用的文件(列在 `bootstrap/hive2_only.*.list`)| |
| 72 | +| `hive3_only` | 仅 Hive3 使用的文件(列在 `bootstrap/hive3_only.*.list`)| |
| 73 | +| `all` | 以上所有(未指定时的默认值)| |
| 74 | + |
| 75 | +各版本默认的 bootstrap 组: |
| 76 | +- Hive2:`common,hive2_only` |
| 77 | +- Hive3:`common,hive3_only` |
| 78 | + |
| 79 | +--- |
| 80 | + |
| 81 | +## 状态存储:Docker 命名卷 + OSS Baseline |
| 82 | + |
| 83 | +Hive 运行态(HDFS 数据、Postgres Metastore、模块 SHA 记录)存放在**每个版本 4 个 Docker 命名卷**中,不再使用宿主机 bind mount: |
| 84 | + |
| 85 | +| 卷 | 挂载位置 | |
| 86 | +|---|---| |
| 87 | +| `<CONTAINER_UID><hive_version>-namenode` | NameNode 元数据 | |
| 88 | +| `<CONTAINER_UID><hive_version>-datanode` | DataNode 数据块 | |
| 89 | +| `<CONTAINER_UID><hive_version>-pgdata` | Hive Metastore Postgres 数据 | |
| 90 | +| `<CONTAINER_UID><hive_version>-state` | `/mnt/state` — baseline 版本号 + 各模块 SHA 文件 | |
| 91 | + |
| 92 | +生命周期: |
| 93 | +- `--hive-mode fast` / `refresh`:卷在多次运行间保留。 |
| 94 | +- `--hive-mode rebuild`:卷被删除(`docker volume rm`)后重建为空。 |
| 95 | + |
| 96 | +### 首次启动:Baseline 恢复 |
| 97 | + |
| 98 | +当卷为空时(全新 CI 主机,或执行过 `rebuild`),脚本不会从零完整 bootstrap,而是从预先构建的 baseline tarball 恢复: |
| 99 | + |
| 100 | +1. 先在 `${HIVE_BASELINE_TARBALL_CACHE:-/tmp/hive-baseline-cache}/<hive_version>-baseline.tar.gz` 查找本地缓存。 |
| 101 | +2. 未命中缓存时,从 `${HIVE_BASELINE_URL_PREFIX}/<hive_version>-baseline-<version>-<arch>.tar.gz` 下载。默认前缀为 `https://doris-thirdparty.oss-cn-beijing.aliyuncs.com/thirdparties/hive-baseline`。可通过 `HIVE_BASELINE_TARBALL_URL` 强制覆盖完整 URL。 |
| 102 | +3. 使用单个 `alpine tar` 容器同时挂载 4 个卷解包 —— tar 流直接写入卷的挂载点。 |
| 103 | + |
| 104 | +相关环境变量: |
| 105 | + |
| 106 | +| 变量 | 默认值 | 作用 | |
| 107 | +|---|---|---| |
| 108 | +| `HIVE_BASELINE_URL_PREFIX` | `https://doris-thirdparty.oss-cn-beijing.aliyuncs.com/thirdparties/hive-baseline` | baseline tarball 下载的基础 URL | |
| 109 | +| `HIVE_BASELINE_TARBALL_URL` | *(空)* | 完整 URL,优先级高于按前缀拼接 | |
| 110 | +| `HIVE_BASELINE_TARBALL_CACHE` | `/tmp/hive-baseline-cache` | 下载 tarball 的本地缓存目录 | |
| 111 | +| `HIVE_BASELINE_VERSION` | `20260415` | 写入 `/mnt/state/baseline.version`;不一致时强制重建 baseline | |
| 112 | + |
| 113 | +### 生成新的 baseline tarball |
| 114 | + |
| 115 | +在一次完整 bootstrap 成功后,停止容器并运行: |
| 116 | + |
| 117 | +```bash |
| 118 | +sudo docker compose -p "${CONTAINER_UID}hive3" \ |
| 119 | + -f docker/thirdparties/docker-compose/hive/hive-3x.yaml down |
| 120 | + |
| 121 | +bash docker/thirdparties/docker-compose/hive/scripts/snapshot-hive-baseline.sh \ |
| 122 | + "${CONTAINER_UID}hive3" /tmp/hive3-baseline.tar.gz |
| 123 | +``` |
| 124 | + |
| 125 | +然后把得到的 tarball 上传到 `<HIVE_BASELINE_URL_PREFIX>/hive3-baseline-<version>-<arch>.tar.gz`(`hive2` 同理)。 |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +## 使用方式 |
| 130 | + |
| 131 | +### 启动 / 停止 |
| 132 | + |
| 133 | +```bash |
| 134 | +# 启动 Hive3(默认为 refresh 模式) |
| 135 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 |
| 136 | + |
| 137 | +# 启动 Hive2 |
| 138 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive2 |
| 139 | + |
| 140 | +# 同时启动两者 |
| 141 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive2,hive3 |
| 142 | + |
| 143 | +# 停止 Hive3 |
| 144 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 --stop |
| 145 | +``` |
| 146 | + |
| 147 | +### 启动模式(`--hive-mode`) |
| 148 | + |
| 149 | +| 模式 | 行为 | |
| 150 | +|---|---| |
| 151 | +| `fast` | 若 stack 已 healthy 则跳过 compose up;完全跳过数据刷新 | |
| 152 | +| `refresh` | stack healthy 时跳过 compose up;只重跑 SHA 发生变化的模块/HQL 文件 *(默认)* | |
| 153 | +| `rebuild` | 拆掉 stack,清空所有卷,冷启动 | |
| 154 | + |
| 155 | +```bash |
| 156 | +# fast:数据没变,只需要保证 stack 在跑 |
| 157 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 --hive-mode fast |
| 158 | + |
| 159 | +# refresh:不拆 stack,增量拾取 HQL/脚本变化(默认) |
| 160 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 --hive-mode refresh |
| 161 | + |
| 162 | +# rebuild:从零开始 |
| 163 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 --hive-mode rebuild |
| 164 | +``` |
| 165 | + |
| 166 | +### 按模块限定刷新范围(`--hive-modules`) |
| 167 | + |
| 168 | +只刷新关心的模块: |
| 169 | + |
| 170 | +```bash |
| 171 | +# 只重跑变化的 preinstalled HQL 文件(并行) |
| 172 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 \ |
| 173 | + --hive-mode refresh --hive-modules preinstalled_hql |
| 174 | + |
| 175 | +# 刷新两个特定模块 |
| 176 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 \ |
| 177 | + --hive-mode refresh --hive-modules default,multi_catalog |
| 178 | + |
| 179 | +# 显式刷新所有模块 |
| 180 | +./docker/thirdparties/run-thirdparties-docker.sh -c hive3 \ |
| 181 | + --hive-mode refresh --hive-modules all |
| 182 | +``` |
| 183 | + |
| 184 | +--- |
| 185 | + |
| 186 | +## 开发者指南 |
| 187 | + |
| 188 | +### 如何添加测试数据 |
| 189 | + |
| 190 | +按数据存放方式,有两种模式。 |
| 191 | + |
| 192 | +#### 模式 A — `run.sh`(HDFS 数据 + DDL) |
| 193 | + |
| 194 | +当测试数据文件需要上传到 HDFS 时使用这种模式。 |
| 195 | + |
| 196 | +1. 在合适的模块下新建目录: |
| 197 | + ``` |
| 198 | + scripts/data/<module>/<your_dataset>/ |
| 199 | + ├── run.sh # 必需:模块刷新时被执行 |
| 200 | + └── <data files> # csv、parquet、orc 等 |
| 201 | + ``` |
| 202 | + |
| 203 | +2. `run.sh` 必须是**幂等的**(反复运行不出问题): |
| 204 | + ```bash |
| 205 | + #!/bin/bash |
| 206 | + set -x |
| 207 | + CUR_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" |
| 208 | + |
| 209 | + # 仅在 HDFS 上不存在时才上传 |
| 210 | + hadoop fs -mkdir -p /user/doris/preinstalled_data/your_dataset |
| 211 | + if [[ -z "$(hadoop fs -ls /user/doris/preinstalled_data/your_dataset 2>/dev/null)" ]]; then |
| 212 | + hadoop fs -put "${CUR_DIR}"/data/* /user/doris/preinstalled_data/your_dataset/ |
| 213 | + fi |
| 214 | + |
| 215 | + # 建表(drop 后再 create,保证幂等) |
| 216 | + hive -e " |
| 217 | + DROP TABLE IF EXISTS your_table; |
| 218 | + CREATE EXTERNAL TABLE your_table (...) |
| 219 | + STORED AS PARQUET |
| 220 | + LOCATION '/user/doris/preinstalled_data/your_dataset'; |
| 221 | + " |
| 222 | + ``` |
| 223 | + |
| 224 | +3. 若仅供 Hive2 或 Hive3 使用,把 `run.sh` 的相对路径加入对应清单: |
| 225 | + ``` |
| 226 | + bootstrap/hive2_only.run_sh.list |
| 227 | + bootstrap/hive3_only.run_sh.list |
| 228 | + ``` |
| 229 | + |
| 230 | +#### 模式 B — `create_preinstalled_scripts/`(仅 HQL) |
| 231 | + |
| 232 | +适用于不需要上传 HDFS 文件的场景(指向已有 HDFS 数据的外部表,或通过 INSERT VALUES 写入内部表)。 |
| 233 | + |
| 234 | +1. 新建 `scripts/create_preinstalled_scripts/runNN.hql`: |
| 235 | + ```sql |
| 236 | + use default; |
| 237 | + |
| 238 | + DROP TABLE IF EXISTS `your_new_table`; |
| 239 | + CREATE EXTERNAL TABLE `your_new_table` ( |
| 240 | + id INT, |
| 241 | + name STRING |
| 242 | + ) |
| 243 | + STORED AS PARQUET |
| 244 | + LOCATION '/user/doris/preinstalled_data/existing_path'; |
| 245 | + ``` |
| 246 | + |
| 247 | +2. 约定: |
| 248 | + - 始终先 `DROP TABLE IF EXISTS` 再 `CREATE` —— 不要只写 `CREATE IF NOT EXISTS` |
| 249 | + - 用下一个未占用的 `runNN` 编号 |
| 250 | + - 仅 Hive2/Hive3 使用时,把相对路径加入 `bootstrap/hive2_only.preinstalled_hql.list` 或 `bootstrap/hive3_only.preinstalled_hql.list` |
| 251 | + - 若与 TPCH 相关,加入 `bootstrap/tpch.preinstalled_hql.list` |
| 252 | + |
| 253 | +3. 触发一次刷新让它生效: |
| 254 | + ```bash |
| 255 | + ./docker/thirdparties/run-thirdparties-docker.sh -c hive3 \ |
| 256 | + --hive-mode refresh --hive-modules preinstalled_hql |
| 257 | + ``` |
| 258 | + |
| 259 | +--- |
| 260 | + |
| 261 | +### 如何接入 HiveServer2 进行调试 |
| 262 | + |
| 263 | +所有容器都是 `network_mode: host`,端口在宿主机上可直接访问。 |
| 264 | + |
| 265 | +#### 容器内使用 beeline |
| 266 | + |
| 267 | +```bash |
| 268 | +# 进入 hive-server 容器 |
| 269 | +docker exec -it ${CONTAINER_UID}hive3-server bash |
| 270 | + |
| 271 | +# 通过 beeline 连接(PATH 里的 hive shim 会自动走这里) |
| 272 | +beeline -u "jdbc:hive2://localhost:13000/default" -n root |
| 273 | + |
| 274 | +# 也可以直接用 hive 别名 |
| 275 | +hive -e "show databases;" |
| 276 | +hive -e "show tables in default;" |
| 277 | +hive -f /path/to/your.hql |
| 278 | +``` |
| 279 | + |
| 280 | +#### 宿主机上使用 beeline |
| 281 | + |
| 282 | +```bash |
| 283 | +# 宿主机上的 beeline 已在 PATH 中;使用本地回环地址即可 |
| 284 | +beeline -u "jdbc:hive2://127.0.0.1:13000/default" -n root |
| 285 | +``` |
| 286 | + |
| 287 | +#### 在容器外执行临时 HQL |
| 288 | + |
| 289 | +```bash |
| 290 | +# 执行单条查询 |
| 291 | +docker exec ${CONTAINER_UID}hive3-server \ |
| 292 | + beeline -u "jdbc:hive2://localhost:13000/default" -n root \ |
| 293 | + -e "SELECT * FROM default.your_table LIMIT 10;" |
| 294 | + |
| 295 | +# 执行 HQL 文件(文件需在容器内或已挂载的路径下) |
| 296 | +docker exec ${CONTAINER_UID}hive3-server \ |
| 297 | + hive -f /mnt/scripts/create_preinstalled_scripts/run02.hql |
| 298 | +``` |
| 299 | + |
| 300 | +#### 查看 HDFS |
| 301 | + |
| 302 | +```bash |
| 303 | +# 列出 HDFS 顶层目录 |
| 304 | +docker exec ${CONTAINER_UID}hadoop3-namenode \ |
| 305 | + hadoop fs -ls /user/doris/ |
| 306 | + |
| 307 | +# 检查指定路径是否存在 |
| 308 | +docker exec ${CONTAINER_UID}hadoop3-namenode \ |
| 309 | + hadoop fs -ls /user/doris/preinstalled_data/your_dataset/ |
| 310 | +``` |
| 311 | + |
| 312 | +#### 直连 Metastore PostgreSQL |
| 313 | + |
| 314 | +```bash |
| 315 | +# 直接连接 metastore 库(Hive3 是 5732 端口) |
| 316 | +psql -h 127.0.0.1 -p 5732 -U postgres -d metastore \ |
| 317 | + -c "SELECT TBL_NAME, DB_ID FROM TBLS LIMIT 20;" |
| 318 | +``` |
| 319 | + |
| 320 | +--- |
| 321 | + |
| 322 | +## 日志与调试 |
| 323 | + |
| 324 | +| 日志文件 | 内容 | |
| 325 | +|---|---| |
| 326 | +| `docker/thirdparties/logs/start_hive3.log` | Hive3 完整启动日志 | |
| 327 | +| `docker/thirdparties/logs/start_hive2.log` | Hive2 完整启动日志 | |
| 328 | + |
| 329 | +开启详细 xtrace: |
| 330 | + |
| 331 | +```bash |
| 332 | +HIVE_DEBUG=1 ./docker/thirdparties/run-thirdparties-docker.sh -c hive3 --hive-mode refresh |
| 333 | +``` |
| 334 | + |
| 335 | +每个阶段结束时会打印耗时: |
| 336 | +``` |
| 337 | +[14:02:31] [hive3] compose up done took=18s |
| 338 | +[14:02:49] [hive3] init-hive-baseline begin |
| 339 | +[14:03:11] [hive3] init-hive-baseline done took=22s |
| 340 | +[14:03:11] [hive3] refresh-hive-modules begin (mode=refresh modules=all) |
| 341 | +[14:05:44] [hive3] refresh-hive-modules done took=153s |
| 342 | +``` |
| 343 | + |
| 344 | +--- |
| 345 | + |
| 346 | +## 故障排查 |
| 347 | + |
| 348 | +**Metastore 健康检查失败** |
| 349 | +- 确认 `${CONTAINER_UID}hive3-metastore-postgresql` 已 healthy:`docker ps` |
| 350 | +- 查看启动日志:`tail -100 docker/thirdparties/logs/start_hive3.log` |
| 351 | + |
| 352 | +**HiveServer2 连不上** |
| 353 | +- 检查容器是否在运行:`docker ps | grep hive3-server` |
| 354 | +- 测试端口:`nc -z 127.0.0.1 13000` |
| 355 | +- 查看容器内 HS2 日志:`docker exec ${CONTAINER_UID}hive3-server tail -50 /tmp/hive-server2.log` |
| 356 | + |
| 357 | +**JuiceFS format/init 失败** |
| 358 | +- 确认 `JFS_CLUSTER_META` 可达(默认为 `mysql://root:123456@(127.0.0.1:3316)/juicefs_meta`) |
| 359 | +- 视需要 override:`export JFS_CLUSTER_META=<your_uri>` |
| 360 | + |
| 361 | +**Refresh 明显变慢** |
| 362 | +- 看是哪些模块被重跑;若全都在跑,说明 SHA 不匹配,走了完整刷新 |
| 363 | +- 收窄范围:`--hive-modules preinstalled_hql` |
| 364 | +- 结合上面的耗时日志定位慢阶段 |
| 365 | + |
| 366 | +**容器被硬杀后状态残留** |
| 367 | +- state 目录可能写了一半;使用 `--hive-mode rebuild` 重置干净 |
| 368 | + |
| 369 | +**Baseline 下载慢或失败** |
| 370 | +- 确认能访问 `HIVE_BASELINE_URL_PREFIX`(默认是阿里云 OSS) |
| 371 | +- 手动把 tarball 放到 `${HIVE_BASELINE_TARBALL_CACHE:-/tmp/hive-baseline-cache}/<hive_version>-baseline.tar.gz` 即可跳过下载 |
| 372 | +- 改用镜像源:`export HIVE_BASELINE_URL_PREFIX=https://your-mirror/path` |
| 373 | +- 完全关闭 baseline 恢复:`export HIVE_BASELINE_URL_PREFIX=`(卷会从零完整 bootstrap) |
| 374 | + |
| 375 | +**手动查看或删除卷** |
| 376 | +```bash |
| 377 | +# 列出某个版本的 4 个卷 |
| 378 | +docker volume ls | grep "${CONTAINER_UID}hive3-" |
| 379 | + |
| 380 | +# 删除全部 4 个(等价于 --hive-mode rebuild 的清理步骤) |
| 381 | +for s in namenode datanode pgdata state; do |
| 382 | + docker volume rm -f "${CONTAINER_UID}hive3-${s}" |
| 383 | +done |
| 384 | +``` |
0 commit comments