概述与架构
https://doris.apache.org/zh-CN/download wget https://apache-doris-releases.oss-accelerate.aliyuncs.com/apache-doris-3.1.4-bin-x64.tar.gz wget https://apache-doris-releases.oss-accelerate.aliyuncs.com/apache-doris-4.1.3-bin-x64.tar.gz **Apache Doris** 是高性能实时分析数据库(MPP 架构),亚秒级查询、高并发,兼容 MySQL 协议(`mysql` 客户端直连 9030)。 - 适用场景:报表分析、实时数仓、交互式查询、日志分析 - 版本约定:**3.x 必须 JDK 17**;2.1(含)之前用 JDK 8 - 本文环境:Ubuntu 20.04(WSL2)/ 28 核 31G / Doris 3.1.4 单机版 - 安装目标:`/opt/app/doris`(fe/be/jdk/mysql 全部在该目录)
| 组件 | 端口 | 用途 | |------|------|------| | FE | 9010 | edit_log(元数据同步)| | FE | 9020 | rpc | | FE | **9030** | **mysql 查询协议(客户端连接)** | | FE | 8030 | http(Web UI / health API)| | BE | 9050 | **heartbeat(FE 心跳 BE)** | | BE | 9060 | thrift(BE 主服务)| | BE | 8040 | webserver(BE http)| 检查端口占用:`ss -tln | grep -E ":(9010|9020|9030|8030|9050|9060|8040)"`
**两种架构**: - **存算一体**(默认):数据存 BE 本地盘,部署简单性能优,适合大多数场景 - **存算分离**:数据存共享存储(对象存储),计算弹性伸缩 **FE 角色**:Follower(参与选主)/ Observer(只同步元数据)。生产建议 ≥3 Follower。 **BE 数量**:生产 3 副本建议 ≥3 BE;**开发测试单机 1 FE + 1 BE 即可**(本文场景)。 官方文档: - 部署前准备 https://doris.apache.org/zh-CN/docs/dev/install/preparation/env-checking - 手动部署 https://doris.apache.org/zh-CN/docs/dev/install/deploy-manually/integrated-storage-compute-deploy-manually
部署前准备
| 检查项 | 要求 | 检查命令 | |--------|------|---------| | CPU 指令集 | 支持 AVX2(否则用 no-AVX2 包)| `cat /proc/cpuinfo \| grep avx2` | | 内存 | 建议 CPU 核数 ×2 以上(8核16G 起)| `free -h` | | 磁盘 | FE 预留 100G+;BE 按 数据量×3副本×1.4 | `df -h /opt` | | 文件系统 | EXT4 或 XFS | `df -T /opt` | | 网络 | 建议万兆网卡;多网卡做链路聚合 | `ethtool eth0` |
- [ ] 关闭 swap 分区 - [ ] 关闭透明大页(THP = madvise) - [ ] 虚拟内存区域 vm.max_map_count ≥ 2000000 - [ ] CPU 不用省电模式(performance) - [ ] TCP 溢出自动重置 net.ipv4.tcp_abort_on_overflow = 1 - [ ] Doris 相关端口畅通 / 防火墙放行 - [ ] 文件句柄 nofile ≥ 1000000 - [ ] 集群机器 NTP 时钟同步(误差 < 5000ms)
**三个安装包**(本机存放在 `/mnt/d/tmp/doris/`): | 包 | 说明 | 大小 | |----|------|------| | apache-doris-3.1.4-bin-x64.tar.gz | Doris 主程序(fe/be/ms/extensions/tools)| 3.2G | | openjdk-17_linux-x64_bin.tar.gz | JDK 17(Doris 3.x 必需)| 187M | | mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz | MySQL 客户端(仅用 mysql 命令,不必装服务)| 832M | **要点**:JDK 与 MySQL 客户端只需解压 + 配环境变量即可使用,无需真正"安装"。 参考实例:`ssh xt@101.43.140.244:/opt/app/doris/`(可正常运行的环境,可对照排障)
系统配置
```bash # 1. 关闭 swap(临时;永久关闭需注释 /etc/fstab 中 swap 行后重启) sudo swapoff -a # 2. 透明大页 → madvise(临时 + rc.local 持久化) echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/enabled echo madvise | sudo tee /sys/kernel/mm/transparent_hugepage/defrag # 3. 虚拟内存区域(永久 + 立即生效) echo "vm.max_map_count = 2000000" | sudo tee -a /etc/sysctl.conf sudo sysctl -w vm.max_map_count=2000000 # 4. TCP 溢出自动重置(永久 + 立即生效) echo "net.ipv4.tcp_abort_on_overflow = 1" | sudo tee -a /etc/sysctl.conf sudo sysctl -w net.ipv4.tcp_abort_on_overflow=1 sudo sysctl -p # 全部生效 ```
```bash # /etc/security/limits.conf 追加(重启会话生效) * soft nofile 1000000 * hard nofile 1000000 # 验证当前值 ulimit -n # 应 ≥ 1000000 # CPU 省电模式 → performance(可选,不支持则跳过) echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor ```
```bash # 防火墙(开发环境直接关闭;生产放行 Doris 端口) sudo systemctl stop firewalld.service 2>/dev/null sudo systemctl disable firewalld.service 2>/dev/null # Ubuntu/WSL 一般无 firewalld,用 ufw status 确认 # NTP 时钟同步(多节点集群必须;单机可跳过) sudo apt install -y ntp sudo systemctl restart ntp timedatectl status ```
软件安装
**目录结构**(fe/be/ms/extensions/tools + jdk-17 + mysql 全在 `/opt/app/doris`): ```bash mkdir -p /opt/app/doris && cd /opt/app/doris # JDK 17(只需解压) tar -xzf /mnt/d/tmp/doris/openjdk-17_linux-x64_bin.tar.gz # MySQL 客户端(解压 + 重命名,只用到 bin/mysql) tar -xJf /mnt/d/tmp/doris/mysql-8.4.11-linux-glibc2.28-x86_64.tar.xz mv mysql-8.4.11-linux-glibc2.28-x86_64 mysql # Doris 主程序(3.2G,耗时几分钟;解压后拍平到 /opt/app/doris) tar -xzf /mnt/d/tmp/doris/apache-doris-3.1.4-bin-x64.tar.gz mv apache-doris-3.1.4-bin-x64/* . && rmdir apache-doris-3.1.4-bin-x64 ``` 解压完成验证:`ls /opt/app/doris` 应有 `fe be ms extensions tools jdk-17 mysql`
追加到 `~/.bashrc`: ```bash # ===== Doris 环境 ===== export DORIS_HOME=/opt/app/doris export JAVA_HOME=/opt/app/doris/jdk-17 export PATH=$JAVA_HOME:/opt/app/doris/mysql/bin:$PATH ``` 生效并验证: ```bash source ~/.bashrc java -version # openjdk version "17" mysql --version # Ver 8.4.11 ```
测试集群可用 docker 快速拉起多节点(`--privileged` 特权 + 自定义网络): ```bash docker network create --subnet=192.168.73.0/24 mydk docker run -itd --privileged --name ds1 -h ds1 --net mydk --ip 192.168.73.11 \ -v /opt:/opt -v /mnt:/mnt ubuntu18:1.0 bash # ds2~ds6 同理(IP .12~.16) docker start ds1 ds2 ds3 ds4 ds5 ds6 ``` 节点内建 doris 用户与 ssh:`adduser doris`、安装 openssh-server、配 NTP。
配置修改
修改 `fe/conf/fe.conf`(先备份:`cp fe/conf/fe.conf fe/conf/fe.conf.orig`),追加: ```properties JAVA_HOME = /opt/app/doris/jdk-17 priority_networks = 172.26.112.0/20 lower_case_table_names = 1 ``` **堆内存**:修改 `JAVA_OPTS_FOR_JDK_17` 行的 `-Xmx/-Xms`(默认 8G,按物理内存调): | 物理内存 | FE -Xmx | |---------|---------| | 8G | 1024m | | 16G | 2048m | | 31G | 4096m |
修改 `be/conf/be.conf`,追加: ```properties JAVA_HOME = /opt/app/doris/jdk-17 priority_networks = 172.26.112.0/20 mem_limit = 8G ``` **mem_limit 参照**:8G 物理内存给 1536m;16G 给 4G;31G 给 8G。
**不配 priority_networks 会选错网卡**(如 docker0 的 172.17.0.1),导致 FE/BE 通信失败。必须匹配 eth0 实际网段,且 **WSL2 重启后 IP 会漂移,重装时要重新探测**: ```bash # 取 eth0 IP(含掩码后缀,如 172.26.114.122/20) NIC_IP=$(ip -4 addr show eth0 | awk '/inet /{print $2}' | head -1) # 换算网段 → 填入 fe.conf / be.conf 的 priority_networks python3 -c "import ipaddress;print(ipaddress.ip_network('$NIC_IP', strict=False))" # 输出示例: 172.26.112.0/20 ```
启动与验证
**顺序:启动 FE → 注册 BE → 启动 BE**(BE 必须先在 FE 注册才能加入集群) ```bash # 1. 启动 FE(root 默认无密码) cd /opt/app/doris/fe && ./bin/start_fe.sh --daemon # 等待 9030 监听(约 10 秒),失败看 log/fe.out # 2. 注册 BE —— 必须用 eth0 实际 IP,不能用 127.0.0.1(心跳会失败) mysql -uroot -P9030 -h127.0.0.1 -e "ALTER SYSTEM ADD BACKEND '172.26.114.122:9050';" # 3. 启动 BE cd /opt/app/doris/be && ./bin/start_be.sh --daemon ``` **停止顺序相反**:先 `be/bin/stop_be.sh` 再 `fe/bin/stop_fe.sh`。
```bash # FE 状态:Alive=true, IsMaster=true, Join=true mysql -uroot -pAa123456 -P9030 -h127.0.0.1 -e "SHOW FRONTENDS\G" | grep -E 'Alive|IsMaster|Join' # BE 状态:Alive 必须 true mysql -uroot -pAa123456 -P9030 -h127.0.0.1 -e "SHOW BACKENDS\G" | grep -E 'Alive|Heartbeat' # 健康检查 API(online_backend_num=1 正常) curl http://127.0.0.1:8030/api/health # {"msg":"success","code":0,"data":{"online_backend_num":1,"total_backend_num":1}} # 建表冒烟测试 mysql -udba -pAa123456 -P9030 -h127.0.0.1 -e " CREATE DATABASE IF NOT EXISTS test_db; USE test_db; CREATE TABLE t1(id INT, name VARCHAR(50)) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES('replication_num'='1'); INSERT INTO t1 VALUES(1,'alice'); SELECT * FROM t1; DROP DATABASE test_db;" ```
```bash # 进程 ps aux | grep -E 'DorisFE|doris_be' | grep -v grep # 端口(FE: 9010/9020/9030/8030,BE: 9050/9060/8040) ss -tln | grep -E ':(9010|9020|9030|8030|9050|9060|8040)' # 日志位置 tail -100 /opt/app/doris/fe/log/fe.out tail -100 /opt/app/doris/be/log/be.out grep -i error /opt/app/doris/be/log/be.INFO | tail -20 ```
用户与权限
连接 FE 后执行(Doris 3.x 语法,注意与 MySQL 的差异): ```sql -- 连接: mysql -uroot -P9030 -h127.0.0.1(首次 root 无密码) SET PASSWORD = PASSWORD('Aa123456'); CREATE USER 'dba'@'%' IDENTIFIED BY 'Aa123456'; -- 全局权限必须用 *.*.*(三段式,用 *.* 报 errCode=2) GRANT ADMIN_PRIV ON *.*.* TO 'dba'@'%'; GRANT GRANT_PRIV ON *.*.* TO 'dba'@'%'; -- 资源权限只能跟 *(*.* 或 *.*.* 都是语法错) GRANT USAGE_PRIV ON RESOURCE * TO 'dba'@'%'; ```
```sql CREATE DATABASE IF NOT EXISTS aisql; GRANT ALL ON aisql.* TO 'dba'@'%'; ``` 使用 dba 连接验证: ```bash mysql -udba -pAa123456 -P9030 -h127.0.0.1 ``` ```sql SELECT USER(); -- 'dba'@'127.0.0.1' SHOW DATABASES; -- 应能看到 aisql SHOW GRANTS; -- GlobalPrivs 含 Admin_priv,Grant_priv;ResourcePrivs 含 Usage_priv ```
| 语句 | 错误写法 | 正确写法(Doris 3.x)| |------|---------|---------------------| | 管理员授权 | `GRANT ADMIN_PRIV ON *.*` | `GRANT ADMIN_PRIV ON *.*.*` | | 授权权限 | `GRANT GRANT_PRIV ON *.*` | `GRANT GRANT_PRIV ON *.*.*` | | 资源权限 | `GRANT USAGE_PRIV ON RESOURCE *.*` | `GRANT USAGE_PRIV ON RESOURCE *` | | 库级授权 | — | `GRANT ALL ON aisql.*`(库级仍用两段)| **报错特征**: - `errCode = 2, ADMIN_PRIV ... *.*.*` → 用了 `*.*` - `mismatched input '.' expecting 'TO'` → RESOURCE 后跟了 `*.*`
数据迁移
从源 Doris(如 `101.43.140.244:9030`,dba/Aa123456,库 aisql)导出: ```bash ssh xt@101.43.140.244 "/opt/app/mysql/bin/mysqldump -udba -pAa123456 -P9030 \ -h127.0.0.1 --no-tablespaces --skip-lock-tables \ aisql test_accounts test_transactions" > aisql_dump.sql ``` **注意**:Doris 的 DDL(DUPLICATE KEY/DISTRIBUTED BY/PROPERTIES)会被 mysqldump 原样带出,目标也是 Doris 时可直接回放。
mysqldump 的 `/*!40101 SET ...*/` 条件注释与 `SET` 语句 Doris 不认,导入前必须清洗: ```bash python3 -c " lines = [l for l in open('aisql_dump.sql').read().split(' ') if not (l.strip().startswith('/*!') or l.strip().startswith('--') or l.strip().startswith('SET ') or l.strip()=='')] open('aisql_clean.sql','w').write(' '.join(lines)+' ')" mysql -udba -pAa123456 -P9030 -h127.0.0.1 -D aisql < aisql_clean.sql ```
**行数 + 聚合值 + 抽样** 三重比对,源库与目标库一致才算迁移成功: ```sql -- 两边执行,结果应完全相同 SELECT COUNT(*), SUM(balance), MIN(account_id), MAX(account_id) FROM test_accounts; -- 期望: 100 | 4867898.19 | 10001 | 10100 SELECT COUNT(*), SUM(amount) FROM test_transactions; -- 期望: 579 | 1260460.88 ``` 抽样比对含中文/时间的行: ```sql SELECT * FROM test_accounts ORDER BY account_id LIMIT 3; ```
日常运维
`/opt/app/doris/start_doris.sh` 与 `stop_doris.sh`(来自参考服务器,已本地化路径): ```bash cd /opt/app/doris ./start_doris.sh # 系统设置→检查目录→启动FE→启动BE→注册检查→状态汇总 ./stop_doris.sh # BE→FE 优雅停止(官方脚本),超时自动强杀兜底 ./stop_doris.sh --force # 直接按端口强杀全部进程 ``` 脚本要点: - 启动前检查:目录/配置/JAVA_HOME/已有进程/swap/文件句柄 - 停止按端口找进程(FE 9030/8030/9020/9010,BE 9050/9060/8040) - 停止后清理 `.lck` 锁文件
```bash # 完整重启(数据不丢) /opt/app/doris/stop_doris.sh && /opt/app/doris/start_doris.sh # 验证重启后数据仍在 mysql -udba -pAa123456 -P9030 -h127.0.0.1 -Daisql \ -e "SELECT COUNT(*) FROM test_accounts; SELECT COUNT(*) FROM test_transactions;" ``` **连接方式**: ```bash mysql -udba -pAa123456 -P9030 -h127.0.0.1 # dba(日常使用) mysql -uroot -pAa123456 -P9030 -h127.0.0.1 # root mysql -udba -pAa123456 -P9030 -h<服务器IP> # 远程连接(dba@'%' 已放开) ``` **Web UI**:`http://<IP>:8030`(默认 root,首次无密码)
```sql SHOW FRONTENDS; -- FE 存活/角色 SHOW BACKENDS; -- BE 存活/心跳/磁盘 SHOW PROC '/backends'; -- BE 明细(另一种形式) SHOW VARIABLES LIKE 'version'; -- 版本 SHOW DATABASES; -- 库列表 SHOW GRANTS; -- 当前用户权限 ``` ```bash curl http://127.0.0.1:8030/api/health # JSON 健康检查 ss -tlnp | grep -E '9030|9050' # 端口监听 ```
问题排查
| # | 现象/坑 | 规避 | |---|---------|------| | P1 | `GRANT ADMIN_PRIV ON *.*` 报 errCode=2 | Doris 3.x 用 `ON *.*.*` | | P2 | `ON RESOURCE *.*` 语法错 | 用 `ON RESOURCE *` | | P3 | FE/BE 绑到 docker0 IP(172.17.0.1)| 配 priority_networks 匹配 eth0 | | P4 | `ADD BACKEND '127.0.0.1:9050'` 心跳失败 | 用 eth0 实际 IP 注册 | | P5 | WSL2 重启后 eth0 IP 漂移 | 重装/重启前重新探测网段 | | P6 | mysqldump 产物导入报错 | 清洗 `/*!...*/` 与 SET 行 | | P7 | 堆内存不当(OOM 或浪费)| 按物理内存调 -Xmx / mem_limit | | P8 | BE 启动失败/Too many open files | max_map_count≥200万 + nofile≥100万 |
**FE 起不来(9030 不监听)**: ```bash tail -50 /opt/app/doris/fe/log/fe.out tail -50 /opt/app/doris/fe/log/fe.log | grep -i error ``` | 症状 | 处理 | |------|------| | JAVA_HOME not found | fe.conf 补 `JAVA_HOME = /opt/app/doris/jdk-17` | | 端口占用 | `ss -tlnp \| grep 9030` 杀残留进程,清 `.lck` | | 元数据损坏 | 删 `fe/doris-meta` 重装(丢数据,仅开发环境)| **BE 不 Alive**: ```bash grep -i 'error\|fail' /opt/app/doris/be/log/be.INFO | tail -20 mysql -udba -pAa123456 -P9030 -h127.0.0.1 -e "SHOW BACKENDS\G" # 看 HeartbeatFailureErrMsg ``` 按 P3/P4/P8 逐项排查;改过配置先 DROP 旧 BACKEND 再用正确 IP 重加。
| 位置 | 内容 | |------|------| | `fe/log/fe.out` | FE 标准输出(启动失败先看)| | `fe/log/fe.log` | FE 主日志 | | `be/log/be.out` | BE 标准输出 | | `be/log/be.INFO` | BE 主日志 | | `fe/doris-meta/` | FE 元数据(损坏可删,丢元数据)| | `be/storage/` | BE 数据目录 | ```bash ps aux | grep -E 'DorisFE|doris_be' | grep -v grep # 进程 ss -tlnp | grep -E ':(9010|9020|9030|8030|9050|9060|8040)' # 端口归属 ```
实战沉淀
| 轮次 | 方式 | 结果 | 耗时 | |------|------|------|------| | 第1次 | 手动逐步安装(发现 P1/P2/P6 坑)| ✅ 全过 | ~40min | | 第2次 | db_doris_install 智能体执行 | ✅ 16项全绿 | 1m43s | | 第3次 | dbmng skill 一键脚本 | ✅ 16项全绿 | 1m52s | 结论:脚本化后重装约 **2 分钟**(主要耗时 3.2G 解压),且零人工干预、零踩坑。
沉淀位置:`/home/xt/wks/.config/skills/dbmng/` ```bash SKILL=/home/xt/wks/.config/skills/dbmng bash $SKILL/scripts/install_doris.sh # 一键安装(8步全流程,幂等) bash $SKILL/scripts/verify_doris.sh # 16项验证(全绿 exit 0) bash $SKILL/scripts/uninstall_doris.sh --yes # 卸载(停进程+删目录+清环境变量) ``` 安装脚本内置:预检→系统配置→解压→动态探测网段配置→FE 启动→BE 注册(eth0 IP)→用户初始化(正确授权语法)→种子数据(清洗后导入)→验证。
**dbmng skill**(`.config/skills/dbmng/`)注册两个智能体: | 智能体 | 位置 | 职责 | |--------|------|------| | `db_doris_install` | `.config/agent/db_doris_install/` | 安装/卸载/验证/重装/排障(含坑点 P1-P8 与检查清单)| | `db_qianyi` | `.config/agent/db_qianyi/` | 数据迁移/异构迁移/测试数据制造(八大功能)| **种子数据**:`dbmng/seeds/aisql_seed.sql`(test_accounts 100 行 + test_transactions 579 行,幂等 DROP/CREATE) **安装总结文档**:`dbmng/reference/20260830_doris_install_summary.md`(九章完整实战记录)
参考
    官方·部署前准备
    官方·安装部署