Docker环境下Doris存算分离架构部署与验证实战
2026/9/24 6:58:11 网站建设 项目流程

1. 为什么要在Docker里折腾Doris存算分离

第一次接触Doris存算分离架构的人,脑子里大概率会冒出一个疑问:明明官方推荐用物理机或者Kubernetes部署,为什么还要费劲把它塞进Docker里?这个问题我在两年前也纠结过,后来在一个需要频繁做版本验证和架构演示的场景里,Docker方案反而成了最省事的选择。

先说清楚Doris存算分离到底解决了什么问题。传统Doris架构里,BE节点既负责数据存储又负责计算,扩容的时候存储和计算必须一起扩,这就导致一个尴尬的局面:你明明只是想在月底跑报表的时候多要一点算力,结果不得不顺带买一堆磁盘。存算分离把这两件事拆开了,数据放在共享存储层(比如S3兼容对象存储或者HDFS),计算节点变成无状态的,可以随用随起、用完就释放。这个思路和Snowflake、Databricks那套逻辑是一致的,本质上是为了让资源弹性更细粒度。

那Docker在这里扮演什么角色?我的实际体会是,Docker最适合做三件事:第一,快速搭建验证环境,验证存算分离配置是否正确;第二,在单机上模拟多节点拓扑,方便理解FE、BE、MS(Meta Service)之间的交互关系;第三,给团队做架构培训时,一套compose文件就能把整个集群拉起来,比让每个人装虚拟机高效得多。

但必须提前说清楚边界:Docker方案不适合直接上生产。原因后面会详细展开,核心问题是网络和存储的性能损耗,以及容器编排带来的运维复杂度。如果你是想找一个能跑通存算分离全流程、能理解各组件职责、能验证配置参数的环境,那这篇内容就是为你准备的。

我见过太多人一上来就照着官方文档复制粘贴,结果卡在MS服务起不来、BE注册不上、S3配置报错这些地方。下面我会按照实际搭建的顺序,把每个环节的坑和背后的逻辑都讲透。

2. 存算分离架构里每个组件到底在干什么

在动手写compose文件之前,必须先把架构图在脑子里画清楚。很多人部署失败的根本原因不是命令敲错了,而是根本没搞明白每个容器之间是怎么通信的。

2.1 FE、BE、MS三者的职责边界

Doris存算分离版本里,FE(Frontend)的角色和存算一体时基本一致,负责元数据管理、查询解析和调度。但有一个关键变化:FE不再直接管理数据副本的位置信息,这部分职责交给了MS(Meta Service)。MS是一个独立的服务,它维护着"哪个数据分片在对象存储的哪个路径下"这张映射表。

BE(Backend)在存算分离模式下变成了纯计算节点。它启动的时候会向FE注册,但实际读取数据时,是先从MS拿到数据位置,然后直接去对象存储拉数据。这意味着BE本地不需要挂载大容量磁盘,只需要一块小盘做缓存和临时文件就够了。

这里有个容易混淆的点:很多人以为存算分离后BE就不需要本地存储了,实际上BE还是需要本地磁盘做两件事——一是缓存热数据,二是存放计算过程中的临时文件。我建议至少给BE分配20GB以上的本地空间,否则复杂查询很容易因为临时空间不足而失败。

2.2 对象存储选型:MinIO还是直接上云

在Docker环境里验证存算分离,最方便的对象存储当然是MinIO。它本身就是S3兼容的,一个容器就能跑起来,配置也简单。但如果你手头有云厂商的对象存储账号,直接连云上的S3也行,只是要注意网络延迟会直接影响查询性能。

我一般会在compose里加一个MinIO容器,原因很简单:所有组件都在本地网络里,调试的时候抓包、看日志都方便。用云存储的话,一旦出现权限或者路径问题,排查链路会拉得很长。

MinIO的配置有几个关键参数需要提前想好。首先是bucket名称,建议用doris-data这种一看就懂的命名。其次是access key和secret key,在Docker环境里可以用简单的字符串,但要注意这些值需要同时配置在MS和BE的配置文件里,任何一处不一致都会导致数据写入失败。

2.3 网络模式的选择:host还是bridge

这是Docker部署Doris时第一个要做的关键决策。Doris的组件之间通信非常频繁,FE和BE之间、BE和MS之间、BE和对象存储之间都有大量网络交互。如果用默认的bridge网络,容器之间通过端口映射通信,会引入额外的NAT开销,而且BE注册到FE时上报的IP地址容易出问题。

我的建议是直接用host网络模式。这样每个容器都共享宿主机的网络栈,IP地址就是宿主机的IP,端口也不会冲突(只要提前规划好)。缺点是端口不能重复,所以FE的8030、9030,BE的8040、9060,MS的5000,MinIO的9000和9001,这些端口都要确保宿主机上没有其他程序占用。

如果非要用bridge模式,那必须在BE的配置里显式指定be_addr为宿主机的IP,而不是容器内部的IP。否则FE拿到的是容器IP,其他组件根本访问不到。这个坑我踩过不止一次,表现就是BE显示存活但查询一直报超时。

3. 手把手写一份能跑通的compose文件

网上能找到的Doris存算分离Docker示例不多,而且很多都是存算一体时代的配置改了个名字,根本跑不起来。下面这份compose文件是我在实际环境中反复调试后稳定运行的版本,每个参数都有存在的理由。

3.1 基础镜像与版本选择

Doris的存算分离功能在2.1版本之后才比较稳定,我建议直接用3.x的镜像。官方在Docker Hub上提供了apache/doris仓库,但存算分离相关的镜像标签需要仔细找。FE用apache/doris:fe-3.0.x,BE用apache/doris:be-3.0.x,MS用apache/doris:ms-3.0.x

这里有个细节:三个组件的版本号必须完全一致,小版本号都不能差。我曾经用fe-3.0.1配be-3.0.2,结果BE注册时协议不兼容,日志里报了一堆protobuf解析错误。统一版本是最基本的要求。

MinIO用minio/minio:latest就行,它足够稳定。但要注意MinIO的默认端口是9000(API)和9001(控制台),如果宿主机上已经有其他服务占了这两个端口,需要提前改掉。

3.2 完整compose配置与逐行解读

version: '3.8' services: minio: image: minio/minio:latest network_mode: host environment: MINIO_ROOT_USER: dorisadmin MINIO_ROOT_PASSWORD: dorisadmin123 command: server /data --console-address ":9001" volumes: - ./minio-data:/data doris-ms: image: apache/doris:ms-3.0.3 network_mode: host environment: MS_CONFIG_FILE: /opt/apache-doris/ms/conf/doris_cloud.conf volumes: - ./ms-conf:/opt/apache-doris/ms/conf - ./ms-log:/opt/apache-doris/ms/log depends_on: - minio doris-fe: image: apache/doris:fe-3.0.3 network_mode: host environment: FE_CONFIG_FILE: /opt/apache-doris/fe/conf/fe.conf volumes: - ./fe-conf:/opt/apache-doris/fe/conf - ./fe-log:/opt/apache-doris/fe/log - ./fe-meta:/opt/apache-doris/fe/doris-meta depends_on: - doris-ms doris-be: image: apache/doris:be-3.0.3 network_mode: host environment: BE_CONFIG_FILE: /opt/apache-doris/be/conf/be.conf volumes: - ./be-conf:/opt/apache-doris/be/conf - ./be-log:/opt/apache-doris/be/log - ./be-storage:/opt/apache-doris/be/storage depends_on: - doris-fe

这份配置看起来简单,但每个挂载点都有讲究。FE的doris-meta目录必须持久化,否则每次重启FE都要重新初始化元数据,之前建的库和表全没了。BE的storage目录虽然存算分离后数据不在本地,但缓存和临时文件还在里面,持久化能避免重启后缓存全部失效。

MS的配置文件doris_cloud.conf是整个部署里最关键的文件,它需要告诉MS对象存储的地址和凭证。下面是一个最小可用的配置示例:

# MS服务监听地址 host = 0.0.0.0 port = 5000 # 对象存储配置 storage_type = S3 s3_endpoint = http://127.0.0.1:9000 s3_region = us-east-1 s3_access_key = dorisadmin s3_secret_key = dorisadmin123 s3_bucket = doris-data s3_prefix = doris-cluster

注意s3_endpoint这里用的是127.0.0.1,因为host网络模式下MS容器直接访问宿主机的9000端口。如果你用的是bridge模式,这里要改成MinIO容器的名称或者对应的IP。

3.3 FE和BE的关键配置项

FE的fe.conf里需要加上存算分离的开关:

# 启用存算分离模式 cloud_mode = true # MS服务地址 cloud_meta_service_endpoint = 127.0.0.1:5000 # 元数据目录 meta_dir = /opt/apache-doris/fe/doris-meta

BE的be.conf配置稍微多一点:

# 启用存算分离 cloud_mode = true # MS服务地址 cloud_meta_service_endpoint = 127.0.0.1:5000 # BE自身地址,host模式下就是宿主机IP be_addr = 127.0.0.1 # 本地存储路径,用于缓存和临时文件 storage_root_path = /opt/apache-doris/be/storage # 缓存大小限制,根据宿主机内存调整 file_cache_size = 10737418240

file_cache_size这个参数值得单独说一下。存算分离后,每次查询都要从对象存储拉数据,如果本地没有缓存,性能会非常差。我一般会把它设置为宿主机可用内存的30%左右。比如宿主机有32GB内存,给BE分配10GB缓存是比较合理的。太小了缓存命中率低,太大了容易和FE、MS抢内存。

4. 启动顺序与初始化过程中的真实坑

配置文件写好了不代表就能跑起来。Doris存算分离的启动有严格的顺序要求,而且初始化过程中有几个非常隐蔽的坑,官方文档里要么没写,要么一笔带过。

4.1 为什么MS必须最先启动

MS是整个集群的元数据中枢,FE和BE启动时都会尝试连接MS。如果MS没起来,FE会一直重试并最终报错退出,BE则会卡在注册阶段。所以启动顺序必须是:MinIO → MS → FE → BE。

但这里有个问题:MS启动后需要几秒钟初始化内部状态,如果FE紧接着启动,可能会因为MS还没准备好而连接失败。我的做法是在compose里给FE加一个健康检查依赖,或者干脆手动分步启动。手动启动虽然麻烦一点,但排查问题的时候更清晰。

启动MS后,第一件事是看日志确认它是否成功连接到了MinIO。日志里会打印类似Successfully connected to S3 storage的信息。如果看到Access Denied,说明access key或者secret key配错了。如果看到Bucket not found,说明bucket还没创建,需要先去MinIO控制台建一个。

4.2 FE首次启动的元数据初始化

FE第一次启动时会自动初始化元数据,这个过程大概需要10到30秒。日志里会看到Initialize metadata finished的字样。如果卡在这里超过一分钟,大概率是cloud_meta_service_endpoint配置有问题,FE连不上MS。

初始化完成后,需要用MySQL客户端连接FE的9030端口,执行一条命令来确认存算分离模式是否生效:

SHOW FRONTENDS;

如果返回结果里CloudMode字段是true,说明FE已经正确识别了存算分离模式。如果是false,那就要检查fe.conf里的cloud_mode配置是否被正确加载了。有时候配置文件挂载路径不对,容器里读的还是默认配置,这个坑很隐蔽。

4.3 BE注册失败的三种典型表现

BE注册失败是最常见的问题,表现有三种:

第一种是BE进程直接退出,日志里报Failed to connect to meta service。这通常是MS地址配错了,或者MS根本没起来。

第二种是BE进程活着,但FE里SHOW BACKENDS看不到它。这种情况一般是be_addr配置有问题,BE上报了一个FE访问不到的IP。在host网络模式下,be_addr应该是宿主机的实际IP,而不是127.0.0.1。我一开始图省事写了127.0.0.1,结果FE和BE虽然在同一个宿主机上,但FE是通过容器内部回环地址去连的,根本连不上。

第三种是BE显示存活但状态是offline。这通常是BE和MS之间的通信有问题,需要检查BE日志里有没有Failed to get storage info from MS之类的错误。

排查BE注册问题的时候,我习惯先在BE容器里手动curl一下MS的健康检查接口:

curl http://127.0.0.1:5000/health

如果返回OK,说明网络是通的,问题在配置上。如果连不上,那就是网络或者MS本身的问题。

5. 验证存算分离是否真正生效

环境跑起来只是第一步,更重要的是验证存算分离架构是否真的在工作。很多人部署完了,建了个表,插了几条数据,查询能出结果,就以为大功告成了。但实际上,如果配置不对,Doris可能悄悄退化成了存算一体模式,数据还是写在BE本地。

5.1 建表时指定存储策略

在存算分离模式下建表,需要显式指定存储策略。Doris 3.x里可以通过STORAGE POLICY来指定数据存放在哪个对象存储路径下。最简单的验证方法是建一张表,插入数据,然后去MinIO的控制台看bucket里有没有对应的文件生成。

CREATE TABLE test_table ( id INT, name VARCHAR(50) ) ENGINE=OLAP DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES ( "replication_num" = "1" );

建完表后插入几条数据:

INSERT INTO test_table VALUES (1, 'test1'), (2, 'test2');

然后登录MinIO控制台,进入doris-data这个bucket,应该能看到类似doris-cluster/xxx/yyy的路径结构,里面存放着数据文件。如果bucket里空空如也,那说明数据还是写在BE本地了,存算分离没有真正生效。

5.2 通过BE日志确认数据流向

另一个验证方法是看BE的日志。当BE从对象存储读取数据时,日志里会有Read from S3或者Download from remote storage之类的记录。如果日志里全是Read from local disk,那就要回头检查配置了。

我一般会在插入数据后,手动触发一次查询,然后tail BE的日志:

tail -f ./be-log/be.INFO | grep -i "s3\|remote"

如果能看到从S3读取的记录,说明存算分离链路是通的。

5.3 模拟BE节点故障后的数据可访问性

存算分离最大的价值就是BE无状态,节点挂了数据也不丢。验证方法很简单:把BE容器停掉,然后重新启动一个新的BE容器,看数据是否还能正常查询。

docker stop doris-be docker start doris-be

等BE重新注册成功后,再执行SELECT * FROM test_table,如果数据还在,说明数据确实存在对象存储里,BE本地没有保留副本。这个验证虽然简单,但能直观地证明存算分离架构在正常工作。

6. 性能调优与日常运维的实操心得

Docker环境下的Doris存算分离,性能肯定比不上物理机部署,但通过一些调优手段,可以把它调整到"能用"的水平。下面这些参数是我在实际使用中反复调整后觉得比较有效的。

6.1 缓存策略对查询性能的影响

存算分离后,查询性能的瓶颈往往在对象存储的读取速度上。本地缓存的大小和淘汰策略直接决定了查询的响应时间。BE的file_cache_size前面已经提过,这里补充一个file_cache_evict_policy参数,可以设置为LRU或者LFU。对于报表类查询,LFU(最不经常使用)通常效果更好,因为热门数据会被频繁访问,LFU能保证它们留在缓存里。

另外,MinIO本身也可以做缓存优化。如果宿主机内存充足,可以给MinIO容器分配更大的内存,让它在内存里缓存热点对象。MinIO的--cache参数可以配置本地缓存目录和大小,不过这个配置在Docker环境下需要额外挂载卷,稍微麻烦一点。

6.2 容器资源限制的合理设置

Docker默认不限制容器资源,这意味着BE可能会把宿主机的内存吃光。我建议在compose里给每个容器加上资源限制:

deploy: resources: limits: memory: 16G reservations: memory: 8G

FE和MS的内存需求相对小一些,8GB足够。BE是内存大户,建议至少给16GB,如果宿主机内存充裕,给32GB更好。注意file_cache_size不能超过BE容器的内存限制,否则容器会被OOM Killer干掉。

6.3 日志轮转与磁盘空间管理

Docker环境下磁盘空间是最容易出问题的地方。FE和BE的日志增长很快,如果不做轮转,几天就能把磁盘写满。我的做法是在宿主机上配置logrotate,定期清理挂载出来的日志目录。另外,BE的storage目录里会有缓存文件,虽然可以自动淘汰,但偶尔也会出现缓存文件堆积的情况,需要定期检查。

还有一个容易被忽略的点:Docker的镜像和容器层也会占用大量空间。Doris的镜像本身就有好几个GB,加上运行时的写入层,磁盘占用会持续增长。建议定期执行docker system prune清理无用的镜像和停止的容器。

6.4 常见故障的快速排查清单

最后整理一份我在实际运维中总结的排查清单,遇到问题的时候可以按顺序检查:

故障现象可能原因排查方法
FE启动后立即退出MS未启动或地址错误检查MS日志和FE的cloud_meta_service_endpoint配置
BE注册不上be_addr配置错误在BE容器内curl FE的8030端口
查询报S3权限错误access key或secret key不匹配对比MS和MinIO的配置
查询速度极慢缓存未生效或缓存太小检查file_cache_size和BE日志中的缓存命中率
数据写入失败bucket不存在或路径无权限登录MinIO控制台确认bucket和路径
BE频繁OOM内存限制太小或缓存配置过大调整容器内存限制和file_cache_size

这份清单不能覆盖所有情况,但能解决80%以上的常见问题。剩下的20%通常需要看具体日志,Doris的日志信息还算详细,耐心读一般都能找到线索。

我在多次搭建Doris存算分离Docker环境的过程中,最大的体会是:配置文件的正确性只占成功因素的一半,另一半是对组件之间通信关系的理解。知道FE为什么要连MS、BE为什么要上报自己的地址、数据为什么要经过MS中转,这些底层逻辑清楚了,遇到问题才能快速定位。Docker只是一个载体,真正有价值的是对存算分离架构本身的掌握。

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

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

立即咨询