三节点Doris集群Docker Compose部署实践与避坑指南
2026/9/20 23:14:06 网站建设 项目流程

先交代一下背景:上周帮项目组把一套 Doris 测试集群从手工部署迁移到 Docker Compose 管理,拓扑是 1 个 FE + 3 个 BE,跑在三台虚拟机里,期间踩了网络、权限、元数据好几个坑。这篇文章不是官方文档的复述,而是把我实际操作下来的 compose 编排、参数取舍、问题排查全部摊开写一遍,给准备用 Docker Compose 部署三节点 Doris 集群的同学做个参考。文章会覆盖从架构原理、镜像选择、compose 文件细节到验证、巡检的完整链路,尽量让你照着做就能把集群拉起来。

1. 部署前想清楚的三件事:架构、选型与资源规划

1.1 一分钟看懂 Doris 架构里的 FE 和 BE

Doris 的核心组件就两个:FE(Frontend)和 BE(Backend)。FE 负责 SQL 解析、查询规划、元数据管理、事务协调,它本身不存数据;BE 负责数据存储、查询执行、副本复制,以及后台的 Compaction 合并工作。还有一个可选组件叫 Broker,主要用来对接外部数据源做导入导出,本文先不展开。

理解这个分工非常重要,因为很多部署问题都出在“不知道哪个组件该管什么事”。比如建表失败要去 FE 日志里查,数据写入慢但查询正常,问题大概率在 BE 侧;FE 挂了但没有备用 FE,整个集群就失去了元数据服务,连登录都不行,这就是为什么生产环境必须配 3 个 FE 做高可用,而测试环境可以先用 1 个 FE 顶着。

这里说的三节点集群,我建议这样理解:一台宿主机上用 docker compose 同时拉起 1 个 FE 容器 + 3 个 BE 容器,模拟出 3 个数据节点的逻辑拓扑。如果你正好手上有三台机器,也可以把 3 个 BE 容器分散部署到三台不同的机器,FE 放在第一台上,原理完全一样,只是网络规划要额外注意,后面会专门讲。

先看一个推荐的角色规划表格:

节点角色职责建议数量三节点测试环境方案
FE Master元数据、查询协调1(测试)/3(生产)容器 doris-fe-1
BE 节点数据存储与计算3 起步容器 doris-be-1 / be-2 / be-3
Broker(可选)外部数据源对接按需一般测试环境不需要

Doris 的副本机制决定了 BE 数量至少是 3 个起步才比较稳。默认副本数replication_num是 3,意味着每个分片有 3 份拷贝,分别落在 3 个不同的 BE 上,任何一个 BE 宕机,数据副本还能满足多数派写入要求,集群不会立即不可用。如果你只起 1 个 BE,把副本数强行设成 3,建表就会直接报alive replica insufficient

1.2 为什么是 Docker Compose,而不是裸机或 K8s

很多人一上来就问:Doris 不是有官方二进制包吗,直接解压装不就行了,为什么还要套一层 Docker Compose?我的回答是:如果你想快速搭一套测试环境、验证 SQL 和工具链,Compose 的性价比确实最高。

裸机部署 Doris 的痛点很现实:要准备 JDK 环境,要手工编辑fe.confbe.conf,要检查ulimitvm.max_map_count,FE 和 BE 的启动顺序还得自己盯着,中间任何一个环节出错都得重新排查。尤其当你需要反复推倒重来做实验时,手工部署的清理成本很高,一不小心就把系统环境搞脏了。

K8s 当然适合生产环境,但对大多数人来说,为了一个测试集群去搞 PVC、Service、StatefulSet,学习成本已经超出了部署本身。Docker Compose 的优势在于:项目文件就是配置本身,一条命令拉起,一条命令停止,目录删掉就是彻底清理。配置文件写好后,换一台机器也能快速复现同样的环境。

不过我得说明白,Docker Compose 更适合单机编排。如果你是三台独立机器组成的跨主机集群,Compose 不是最好的选择,它没有跨主机容器通信的原生能力,需要靠extra_hosts或者 Docker Swarm 这种额外方案去补,复杂度反而上去了。本文以单台机器模拟三节点为主,跨主机的差异点会在网络那一节单独说明。

1.3 端口、存储与资源规划:不然后面要返工

部署前把端口和存储规划好,后面能省很多事。Doris 有几个核心端口必须清楚:

端口所属组件用途是否建议映射到宿主机
8030FEWeb UI 和 HTTP API
9030FEMySQL 协议端口,所有 SQL 客户端都连它
9020FEFE 内部 RPC 通信容器内通信即可
8040BEBE 的 HTTP 服务按需
9050BE心跳上报端口,BE 用它与 FE 通信容器内通信即可
9060BEBE 的 Thrift RPC 服务容器内通信即可

如果你用单机模拟三节点,容器之间通过自定义 bridge 网络互通,905090609020这些端口不需要暴露到宿主机。对外只需要暴露 FE 的80309030,以及可选的 BE8040端口用于调试。

存储规划上,最重要的两件事是:FE 的元数据目录和 BE 的数据目录必须做成宿主机目录挂载。FE 元数据在容器里默认路径是/opt/apache-doris/fe/doris-meta,BE 数据目录默认是/opt/apache-doris/be/storage。不挂载的话,容器一删,集群就没了;挂载后,即使容器重建,元数据和数据都还在。另外给 FE 至少预留 10G 空间存元数据快照和日志,BE 的存储空间要按三副本计算,比如你有 100G 的业务数据,在 BE 上占用的其实是 300G,这个容易被人忽略。

内存方面,我建议:FE 容器至少 4G,BE 容器至少 6G,宿主机总内存 16G 以上才跑得比较舒服。如果机器资源紧张,BE 至少也得 4G,再低就会出现大查询 OOM 或者 JVM 之外的进程崩溃,排查起来非常痛苦。

2. 环境准备与镜像选择,避开 Version 坑

2.1 Docker 与 Docker Compose 的安装思路

我自己用的宿主机是 CentOS 7.9,内核 3.10,Docker 24.x,Compose v2.26.1。如果你的环境是 Ubuntu 或者其他发行版,安装方式大同小异,核心是两条:装好 Docker 引擎,装好 compose 插件。

很多老教程还在讲docker-compose这个独立二进制,但现在 Docker 官方主推的是 compose v2 插件,命令是docker compose,中间有空格。安装 compose 插件最直接的方式就是把二进制放到~/.docker/cli-plugins/目录下:

# 安装 Docker 引擎(Linux 环境) curl -fsSL https://get.docker.com | bash systemctl enable --now docker # 创建 compose 插件目录 mkdir -p ~/.docker/cli-plugins # 下载 compose 二进制并赋执行权限 curl -SL "https://github.com/docker/compose/releases/download/v2.26.1/docker-compose-$(uname -s)-$(uname -m)" \ -o ~/.docker/cli-plugins/docker-compose chmod +x ~/.docker/cli-plugins/docker-compose # 验证 docker compose version

这里有个细节:如果下载速度不理想,可以考虑用镜像站下载,或者在一台有网络的机器上先下载好,再拷贝到目标服务器。拷贝过去后记得执行chmod +x,否则会提示 Permission denied。离线环境更稳妥的做法是直接把 Docker 的离线安装包、Compose 二进制、Doris 镜像文件一起打包带过去,Docker 镜像用docker save导出,目标机上再用docker load导入,整个过程不需要外网。

2.2 镜像选型:统一镜像和分角色镜像的区别

Doris 的官方 Docker 镜像发展分两个阶段,选型时一定要看清楚版本,不要凭经验乱猜。

早期版本(2.x 及以前)的镜像是按角色拆开的,比如apache/doris-fe:2.1.7apache/doris-be:2.1.7,你 FE 拉 FE 镜像,BE 拉 BE 镜像。从 3.0 开始,官方提供了统一镜像apache/doris:3.0.x,一个镜像同时包含 FE、BE、Broker 组件,通过环境变量来指定容器角色,比如FE_MASTER=true表示这个容器是 FE 主节点,BE=true表示这个容器充当 BE。

本文以apache/doris:3.0.4为例,因为这个版本目前的容器化部署方案比较成熟,官方也在推。你如果用的是 2.1 版本,部署逻辑其实一样,只是镜像要拆成两个,compose 文件里 image 字段不一样,环境变量名也可能有差异,以官方文档为准。

这里有一个很容易踩的坑:镜像 tag 不要用latest。Doris 迭代速度很快,latest指不定哪天就成了一个不兼容的版本,你的 compose 文件可能上一秒还能用,下一秒拉完镜像后起不来了。部署前先把版本定死,拉取成功后记录镜像 digest,这样可复现性最好。

2.3 宿主机内核参数与 ulimit

Doris 对操作系统有几个隐性要求,不提前设置到位,后面启动大概率会出问题。

第一个是vm.max_map_count,这是进程能拥有的内存映射区域数量上限。Doris 的存储引擎和内存分配对这个参数敏感,官方建议调大一些。我参考官方文档的做法,在宿主机上执行:

sysctl -w vm.max_map_count=2000000

如果只是临时测试,这样就可以了;如果想持久化,就写入/etc/sysctl.conf,然后执行sysctl -p生效。

第二个是文件句柄数限制。BE 在运行时会打开大量文件,默认的ulimit -n 1024完全不够,建议至少 65535:

ulimit -n 65535

这个也是临时生效,长期设置要改/etc/security/limits.conf。在容器里,可以通过 compose 的sysctlsulimits字段来设置,不过很多情况下宿主机设好了,容器内也能继承大半,实际操作中以容器日志报错为准,缺什么补什么。

3. docker-compose.yml 逐段拆解:每个配置为什么这么写

3.1 一个可直接用的三节点 compose 文件

下面这个 compose 文件是我在单台宿主机上模拟三节点 Doris 集群的最终版本,1 个 FE + 3 个 BE。目录结构建议先建好:

mkdir -p doris-cluster/{fe-1/{doris-meta,log},be-1/{storage,log},be-2/{storage,log},be-3/{storage,log}} chmod -R 777 doris-cluster

然后创建docker-compose.yml

services: doris-fe-1: image: apache/doris:3.0.4 container_name: doris-fe-1 hostname: doris-fe-1 networks: - doris-net ports: - "8030:8030" - "9030:9030" environment: - FE_MASTER=true - JAVA_OPTS=-Xmx2g -Xms2g volumes: - ./fe-1/doris-meta:/opt/apache-doris/fe/doris-meta - ./fe-1/log:/opt/apache-doris/fe/log mem_limit: 4g restart: always doris-be-1: image: apache/doris:3.0.4 container_name: doris-be-1 hostname: doris-be-1 networks: - doris-net ports: - "8040:8040" environment: - BE=true - BE_MEM_LIMIT=4g volumes: - ./be-1/storage:/opt/apache-doris/be/storage - ./be-1/log:/opt/apache-doris/be/log depends_on: - doris-fe-1 mem_limit: 6g restart: always doris-be-2: image: apache/doris:3.0.4 container_name: doris-be-2 hostname: doris-be-2 networks: - doris-net ports: - "8041:8040" environment: - BE=true - BE_MEM_LIMIT=4g volumes: - ./be-2/storage:/opt/apache-doris/be/storage - ./be-2/log:/opt/apache-doris/be/log depends_on: - doris-fe-1 mem_limit: 6g restart: always doris-be-3: image: apache/doris:3.0.4 container_name: doris-be-3 hostname: doris-be-3 networks: - doris-net ports: - "8042:8040" environment: - BE=true - BE_MEM_LIMIT=4g volumes: - ./be-3/storage:/opt/apache-doris/be/storage - ./be-3/log:/opt/apache-doris/be/log depends_on: - doris-fe-1 mem_limit: 6g restart: always networks: doris-net: driver: bridge

文件中省略了version字段。Compose v2 已经不建议写version,写了反而会看到一个弃用警告,所以直接不写更干净。三个 BE 的ports我映射了不同的宿主机端口,804080418042,避免本机端口冲突,这是单机模拟多容器时容易忽略的细节。

3.2 FE 配置:JAVA_OPTS 与元数据卷

FE 是 Java 进程,堆内存通过JAVA_OPTS控制。我给的是-Xmx2g -Xms2g,容器mem_limit给了 4g,堆外还要留一部分给线程、元数据缓存和 JVM 自身的 overhead。很多人喜欢把堆设成 3g、4g,看着是物尽其用,实际上容器内存上限一压,直接 OOM。比例大致控制在容器内存的 50% 左右比较稳妥。

FE_MASTER=true是 3.0 统一镜像里识别 FE 主节点的办法。生产环境需要 3 个 FE 做高可用时,第一个 FE 设FE_MASTER=true,后面两个 FE 设FE=true,并且要额外配置它们加入已有集群的地址。这里的三节点测试环境,一个 FE 就够。

FE 元数据目录/opt/apache-doris/fe/doris-meta一定要挂载到宿主机。FE 的元数据是所有库表结构、用户权限、副本分布信息的最终归宿,一旦容器删除后信息丢失,整个集群等于从零开始。bind mount 之后还有个好处是排查问题方便,直接看宿主机上的fe.logaudit.log,不用每次docker logs

挂载目录的权限问题很常见。官方镜像里的进程不一定是 root 用户运行,如果你拉起来发现 FE 一直报Permission denied,大概率是./fe-1目录的所有者不是容器内用户。我的处理办法是初始化目录后直接chmod -R 777 doris-cluster,测试环境图省事没问题,生产环境还是建议查一下镜像里实际的 uid,然后用user字段指定匹配的 uid,避免权限放开过大。

3.3 BE 配置:存储路径、内存上限、心跳端口

BE 是 C++ 实现,内存管理方式和 FE 完全不同。我用BE_MEM_LIMIT=4g这个环境变量限制 BE 进程能使用的最大内存,容器mem_limit给了 6g,留 2g 给操作系统的 page cache 和其他辅助进程。如果不设BE_MEM_LIMIT,BE 会尽量占用宿主机空闲内存,单机模拟三节点时三个 BE 很可能把机器内存吃穿。

BE 的数据目录/opt/apache-doris/be/storage同样必须挂载。这里有一个隐含逻辑:BE 内部默认的storage_root_path就是/opt/apache-doris/be/storage,所以我们 bind mount 这个目录,不需要额外改be.conf里的存储路径。如果你的宿主机有多块数据盘,想给 BE 挂多个存储路径,就得自定义be.conf,用分号分隔多个路径,比如:

storage_root_path = /data1/storage;/data2/storage

BE 启动后会自动向 FE 上报心跳,默认通过9050端口。compose 默认把所有容器放在同一个自定义网络里,BE 往 FE 上报时使用的地址是容器 IP 和容器 hostname,所以只要 FE 和 BE 在同一个网络,SHOW BACKENDS里看到的地址就是容器 IP,这是正常的,不需要把9050映射到宿主机。如果你映射了反而容易出问题,比如多个 BE 都映射同一个 9050 端口到宿主机,端口冲突是必然的。

3.4 为什么自定义网络而不是 host 模式

容器网络模式选择上,我推荐自定义 bridge 网络,而不是network_mode: host。host 模式看似简单,容器直接共享宿主机网络栈,FE 和 BE 用127.0.0.1就能互通,但代价是端口管理极其混乱,三个 BE 的端口全挤在宿主机上,稍微一多就冲突,而且 Doris 的高可用和后续迁移都会受影响。

自定义 bridge 网络有两个直接好处:第一,容器之间可以用 hostname 互相访问,doris-be-1doris-fe-1这种名字在配置和日志里清晰直观;第二,容器网络和宿主机网络隔离,端口冲突范围小,只需要把真正需要对外提供服务的端口映射出来就行。

不过要明确一点:单机 Compose 的自定义 bridge 网络只在本机有效。如果你要跨三台宿主机部署真实的三节点集群,bridge 网络是走不通的,需要给每个容器的/etc/hosts注入其他宿主机的 IP 映射,或者改用 Docker Swarm 模式。最简单的方式是在每个 compose 服务里加extra_hosts,把所有节点的主机名和宿主机 IP 对应起来,例如:

extra_hosts: - "doris-fe-1:192.168.1.10" - "doris-be-1:192.168.1.10" - "doris-be-2:192.168.1.11" - "doris-be-3:192.168.1.12"

这种方式能用,但每个容器都要写一份完整的映射,维护起来比较烦。所以如果你一开始就规划跨主机,我更建议直接用 K8s 或者至少用 Swarm,别让 Compose 干它不擅长的事。

4. 三节点 Doris 集群一键拉起与验证

4.1 启动顺序:先 FE,再 BE

compose 文件里我写了depends_on,但这里必须说清楚:depends_on只能保证 FE 容器先启动,不能保证 FE 进程已经完全可用。BE 容器启动后要立刻和 FE 通信,如果 FE 的 9030 端口还没监听,BE 会不断重试,通常过一会儿能自己连上,但不是每次都那么顺利。

我实际操作时习惯分两步走:

# 第一步:先启动 FE docker compose up -d doris-fe-1 # 第二步:等 FE 日志出现 ready 标记 docker compose logs -f doris-fe-1

看到类似Frontend service is readythrift server started的日志后,再启动 BE:

docker compose up -d doris-be-1 doris-be-2 doris-be-3

如果你懒得等,也可以一条命令全部拉起,然后去日志里确认。实在不放心就写个 shell 循环,每隔两秒检测一下 FE 端口是否通,通了再拉后面的服务,这个脚本网上很多,不展开。

restart: always一定要加。测试环境经常遇到宿主机重启或者 Docker 服务重启的情况,有了它,容器会自动拉起来,Doris 集群也能恢复在线状态,省去手动docker compose start的麻烦。

4.2 用 MySQL 客户端完成集群初始化和注册

FE 起来后,用 MySQL 客户端连 FE 的 9030 端口,注意这里不是连 BE,是连 FE:

docker exec -it doris-fe-1 mysql -uroot -P9030 -h127.0.0.1

进入 MySQL 命令行后,第一件事是确认 FE 状态:

SHOW FRONTENDS;

如果那一行数据里JointrueAlivetrue,说明 FE 正常。接下来看 BE:

SHOW BACKENDS;

刚启动完 BE 后,SHOW BACKENDS可能会有两种情况:一种是你发现 3 个 BE 已经在列表里,说明统一镜像的启动脚本自动注册了;另一种是列表为空,需要手动把 BE 加进集群。后者更常见一些,做法是:

ALTER SYSTEM ADD BACKEND "doris-be-1:9050"; ALTER SYSTEM ADD BACKEND "doris-be-2:9050"; ALTER SYSTEM ADD BACKEND "doris-be-3:9050";

这里必须重点提醒:doris-be-1这个 hostname 能不能解析,取决于容器是否在同一个 compose 网络里,以及你在容器内执行命令时是否找得到这个域名。如果你在宿主机上直接执行mysql而不是docker exec,那doris-be-1是无法解析的,必须写映射到宿主机的 IP。这也是我推荐用docker exec进 FE 容器执行 SQL 的原因,省去一堆网络解析问题。

添加成功后,重新执行:

SHOW BACKENDS;

表格里应该有 3 行数据,每一行的Alive字段都是true。如果有false,说明 BE 的注册链路出了问题,最常见的两个原因我在第 5 章会细说。

4.3 建表、写入、查询的完整链路验证

集群已经注册好了,接下来建一张表验证副本和数据链路。Doris 支持多种表模型,测试环境用最简单的 DUPLICATE KEY 模型就行:

CREATE DATABASE test; USE test; CREATE TABLE tbl_demo ( id INT, name VARCHAR(50), ts DATETIME ) ENGINE=OLAP DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 3 PROPERTIES ( "replication_num" = "3" );

这里两个参数很值得解读。DISTRIBUTED BY HASH(id) BUCKETS 3表示把数据按 id 的哈希值分成 3 个分桶,每个分桶是一个 Tablet;replication_num = 3表示每个 Tablet 在 3 个 BE 上各存一份,正好对应我们的三节点拓扑。如果SHOW BACKENDS里有三个 Alive 的 BE,这张表建出来就是 3 个分桶、共 9 个 Tablet 副本。

然后插入几条测试数据:

INSERT INTO tbl_demo VALUES (1, '张三', '2025-01-01 10:00:00'), (2, '李四', '2025-01-01 11:30:00'), (3, '王五', '2025-01-02 09:15:00'); SELECT * FROM tbl_demo;

能查到数据,说明 FE 的查询计划、BE 的存储和副本读取已经打通。到这里,一个基本可用的三节点 Doris 集群就算部署完成了。此时浏览器打开http://宿主机IP:8030,用 root 账号也能登录 Web UI,界面里能看到 3 个 BE 节点和它们的状态、磁盘使用量。

4.4 数据目录验证与重启持久化

部署完成后,顺手验证一下数据持久化。执行docker compose restart重启所有容器,等一两分钟后再进 FE 执行:

SHOW BACKENDS; SHOW TABLES;

如果 BE 仍然全部 Alive,表还在,数据也能查询,说明 Volume 挂载和重启策略都配置正确。这个验证必须做,因为很多人部署时能启动,一重启就发现 BE 注册信息丢失或者 FE 元数据损坏,问题几乎都出在目录权限和 hostname 漂移上。

这里再补一个细节:宿主机./be-1/storage目录下应该能看到每个 BE 的data目录,里面是按照 tablet id 组织的数据文件。如果你发现某个 BE 的 storage 目录是空的,但SHOW BACKENDS显示 Alive,别慌,可能是新集群还没有触发数据均衡,写入少量数据后不会立即在所有 BE 上平均分布,Doris 后台会自动做迁移,属于正常现象。

5. 部署完成后最常见的 6 个问题与处理实录

5.1 FE 启动失败:元数据目录权限与损坏

现象:FE 容器一直重启,日志里出现Permission denied或者Failed to read image之类的错误。

原因基本是 bind mount 的宿主机目录权限不对。容器内 FE 进程要往/opt/apache-doris/fe/doris-meta写数据,但宿主机./fe-1/doris-meta的所有者对不上容器内用户,写不进去,FE 自然起不来。

解决方式很简单:

chmod -R 777 doris-cluster

然后重启 FE。如果之前已经因为权限问题把元数据目录写坏了,那就更麻烦一些。需要先把损坏的doris-meta目录改名备份,再创建一个空目录并赋予权限,最后重新启动 FE,让 FE 重新初始化元数据。注意这样会导致已有库表信息丢失,所以只适合测试环境,生产环境必须先确认备份。

5.2 BE 注册不上:priority_networks 配置错误

现象:SHOW BACKENDS里 BE 一直是Alive=false,BE 日志里有heartbeat failed或者backend ip is not match

这是容器化部署 Doris 时最常见的问题,没有之一。BE 启动时需要向 FE 上报自己的 IP,如果宿主机上有多个网卡,BE 可能选了一个 FE 无法访问的网卡 IP,比如 docker0 网桥的172.x地址,或者内网之外的虚拟网卡地址。FE 收到心跳发现 IP 不对,直接判定 BE 不可用。

解决办法是强制指定 BE 的网络。创建be.conf文件,放到./be-1目录下,内容加上:

priority_networks = 192.168.1.0/24

然后挂载到容器内的/opt/apache-doris/be/conf/be.conf,重启 BE。这里网段要换成你宿主机实际所在的网段,别照抄。FE 侧如果也有多网卡问题,同样可以在fe.conf里加priority_networks,原理一样。我第一次在虚拟机里部署时就被这个问题卡了两小时,三个 BE 全是 Alive=false,加完配置后瞬间全绿。

5.3 建表失败:alive replica insufficient

现象:执行CREATE TABLE报错alive replica insufficient,表建不出来。

原因有两种:一是SHOW BACKENDS里 Alive 的 BE 数量小于你设置的replication_num;二是虽然 BE 是 Alive,但很多 Tablet 副本还没有成功分配,短时间内建表请求被拒绝。

检查顺序:先看SHOW BACKENDS确认 Alive 数量,再确认建表语句里的replication_num不超过活着的 BE 数。如果你只是测试,只有 1 个 BE 活着,那建表时把replication_num改成 1 就能建出来,但这不是长久的解决办法,本质上还是要让所有 BE 正常注册。

另外可以关注一下SHOW PROC '/cluster_balance'里的均衡信息,如果因为数据均衡触发了节奏有异常,等一会再重试通常能恢复。

5.4 容器重启后 IP 漂移导致集群异常

现象:重启 Docker 或容器后,SHOW BACKENDS里的 BE 还显示旧 IP,实际容器已经换了新 IP,FE 找不到 BE。

compose 的自定义网络会给容器分配 IP,但 Docker 服务重启后,容器 IP 可能变化。FE 元数据里记录的是 BE 的 IP 和 hostname,如果 IP 变了,旧记录就失效了。

解决办法是尽量固定 hostname,并确保priority_networks配置正确。如果是容器重建导致的 IP 变化,可以通过:

ALTER SYSTEM DROP BACKEND "192.168.x.x:9050"; ALTER SYSTEM ADD BACKEND "新hostname:9050";

来更新 FE 对 BE 的认知。drop 掉副本时会触发 Doris 把该 BE 上的数据副本迁移到其他 BE,如果只是临时测试,直接 drop 再 add 问题不大;生产环境要谨慎,最好在业务低峰期操作。

5.5 BE OOM 被宿主机 Kill

现象:docker inspect里看到容器的OOMKilled字段为true,或者 BE 进程无故消失,BE 日志里报了Out Of Memory

原因基本都是内存分配没限制好。BE 默认会尽量使用宿主机内存,单机模拟三节点时,每个 BE 如果不限定内存,三个 BE 能把几十 G 内存吃光,宿主机 OOM Killer 直接把进程杀掉。

解决方式就是前面说的:compose 里给每个 BE 设置mem_limit,同时通过BE_MEM_LIMIT限制 BE 进程自身的内存。另外检查宿主机是否有被其他服务占满内存,Doris 建议给 BE 预留物理内存的 80% 上限,剩下的留给 page cache 和系统。

5.6 宿主机端口被占用导致容器启动失败

现象:docker compose upport is already allocated或者bind: address already in use

测试环境最容易出现这种问题,因为大家习惯默认端口。比如 9030 可能被本机已有的 MySQL 占了,8030 可能被别的 Web 服务占了。解决办法最直接的就是换端口映射,比如:

ports: - "9031:9030"

然后所有客户端连接用 9031。注意如果这样改,第 4 节里mysql -h127.0.0.1 -P9030也要改成-P9031。这个坑看起来很小,但真发生的时候很容易让人怀疑 Doris 配置有问题,排查一圈发现是端口冲突,浪费不少时间。

问题现象大概率原因处理方式
FE 一直重启bind mount 权限错误chmod -R 777 目录
BE Alive=falsepriority_networks 选错网卡指定priority_networks
建表失败副本数大于 BE 数调整 replication_num
重启后 BE 失联容器 IP 漂移DROP 后重新 ADD BACKEND
BE 被 OOM kill内存未限制设置 mem_limit 和 BE_MEM_LIMIT
端口启动冲突宿主机端口被占换映射端口

6. 从部署到运维:还有哪些值得做的事

6.1 集群健康巡检三板斧

集群部署完不是终点,Doris 在运行过程中需要持续关注状态。我每次看集群健康,基本就是三板斧。

第一板斧是 Web UI。浏览器打开http://宿主机IP:8030,登录后首页能看到 FE、BE 节点数量,BE 的磁盘使用率、内存使用率、tablet 数量。这个界面比命令行直观,适合快速看一眼有没有异常。

第二板斧是 SQL 巡检。通过 FE 的 9030 端口执行:

SHOW FRONTENDS; SHOW BACKENDS;

重点看Alive字段是否为true。如果某个 BE 长时间false,就要去那个 BE 的日志里找原因。再看一下磁盘容量:

SHOW PROC '/backends';

里面有每个 BE 的DataUsedCapacityDiskCapacity等信息,能快速判断存储水位。

第三板斧是日志巡检。FE 日志主要看/opt/apache-doris/fe/log/fe.logfe.audit.log,BE 日志主要看/opt/apache-doris/be/log/be.INFObe.out。容器环境里如果挂载了日志目录,直接在宿主机上就能查:

tail -n 200 ./fe-1/log/fe.log | grep -i error tail -n 200 ./be-1/log/be.INFO | grep -i error

重点看有没有ERROR级别的堆栈,以及OutOfMemoryRealtime write fail这类关键词。

6.2 建完集群就该顺手设置的几个参数

部署只是开始,有些参数我建议在集群跑起来后尽快设置,不然后面数据量大了会吃亏。

第一个是priority_networks,前面已经说过,必须在集群刚建好时配置,否则 BE 注册到 FE 的 IP 可能是错的,后面纠正的成本很大。

第二个是 BE 的mem_limit,除了容器内存限制,Doris 自身也有一套内存管理机制。可以在be.conf里设mem_limit = 4g,或者用环境变量BE_MEM_LIMIT控制。不要在配置和 compose 环境变量里同时设,以实际生效的那个为准。

第三个是 FE 的max_java_heap_size,这个参数主要影响 FE JVM 堆大小。容器化部署时直接用JAVA_OPTS=-Xmx2g -Xms2g来控制更直接。调大堆内存不是免费的,堆越大,GC 停顿越明显,Doris FE 在小集群下 2G 够用,数据量大了再按需调整。

第四个和日常运维关系密切:Doris 会把 BE 上的小文件不断合并成大文件,这个过程叫 Compaction,默认是自动处理的。如果你在测试中想手动触发某个表的合并,可以这样操作:

ALTER TABLE tbl_demo COMPACT;

这在验证数据可见性和清理版本时很有用,比如频繁更新同一行导致表有大量历史版本,手动合并一下能明显加快查询速度,这也是很多 Doris 调优资料里常提到的“手动触发对表的合并”。

6.3 后续扩容与工具链衔接

Doris 扩容是它的一大优势,不需要停机。加一个新的 BE 节点时,只要部署一个 BE 容器,启动后执行:

ALTER SYSTEM ADD BACKEND "new-be-hostname:9050";

Doris 后台会自动把部分 tablet 的副本迁移到新 BE 上,不需要人工搬数据。扩容的 BE 越多,集群的查询和写入吞吐能力越强,存储空间也随之扩大。

加 FE 节点也类似,高可用场景下再起一个容器,设置FE=true,然后在当前集群中执行:

ALTER SYSTEM ADD FOLLOWER "new-fe-hostname:9010";

新 FE 会从主 FE 同步元数据,完成后即可承担查询协调任务。生产环境建议 3 个 FE 起步,节点角色里有一个是 Master,另外两个是 Follower。

工具链衔接方面,Doris 生态已经比较丰富。Flink SQL 写入 Doris 是现在很常见的实时数仓链路,通过 Flink Doris Connector 就可以直接写Unique Key模型表,写入时需要注意 sequence 列设置和merge_on_write相关参数。数据同步场景还可以用 Doris CCR Sync 做库表级别的准实时复制。

6.4 备份与恢复的底线

最后聊聊备份。很多人以为 Doris 有三副本就不需要备份了,这是误区。三副本解决的是硬件故障问题,解决不了误删表、误更新数据的问题。一旦执行了DROP TABLE,所有 BE 上的副本都会在后台被清理,想恢复只能靠备份。

FE 元数据的备份非常重要,它保存了所有表结构、分区、副本分布。最简单的方式就是定期把挂载的元数据目录打包:

tar zcvf fe_meta_$(date +%F).tar.gz ./fe-1/doris-meta

BE 的数据副本一般不建议直接备份文件,因为 Doris 会自己维护副本一致性,你手工拷贝的数据容易被当成不一致副本处理。真正的数据级备份应该用 Doris 的BACKUP命令导出到远端存储,恢复时再用RESTORE命令。对于测试环境,做好 FE 元数据备份,再保持三副本稳定运行,已经能覆盖绝大多数场景。

我个人在实际操作中的体会是,Doris 部署的难点从来不在“把容器拉起来”,而在网络规划和元数据生命周期管理。网络层面把priority_networks和 hostname 钉死,多数集群问题能提前规避一半;元数据层面把 FE 的目录挂载和权限处理好,重启、迁移、重建都不会慌。另外一个小建议:所有个性化配置尽量沉淀成 compose 文件里的环境变量或挂载的 conf 文件,不要嫌麻烦登录进容器手动改,改完容器一删就全丢。把环境代码化,才能做到推倒重来也就一条命令的事。希望这篇内容能帮你少踩几个坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询