
1. 为什么要在Docker里折腾Doris存算分离第一次接触Doris存算分离架构是在一个日志分析项目里。当时数据量每天新增大概两三百GB原始的三副本存算一体集群磁盘水位一直告警扩容就得整节点加机器成本压不住。后来看到Doris 2.1版本之后对存算分离的支持逐渐成熟就动了把计算层和存储层拆开的念头。拆开之后最直接的好处是计算节点变成无状态的扩缩容只影响算力数据统一放在对象存储或者共享存储上副本管理交给存储层去做整体成本能降下来不少。但问题也来了——存算分离的部署比存算一体复杂得多。它需要额外的元数据服务Meta Service、共享存储比如S3兼容的对象存储或者HDFS、以及计算节点Compute Node和存储节点Storage Node的配合。如果直接在生产环境上试错代价太高。所以我的做法是先用Docker在本地或者测试机上把整套存算分离集群跑起来验证配置、跑通读写、观察元数据同步逻辑确认没问题再往生产迁移。这篇内容就是把我用Docker部署Doris存算分离的完整过程整理出来。包括镜像选择、网络规划、Meta Service配置、存储后端对接、Compute Node和Storage Node的启动参数、常见报错排查以及我踩过的几个坑。适合已经对Doris有基本了解、想尝试存算分离架构的运维或者后端开发同学。如果你还没接触过Doris建议先拿存算一体模式练手再来搞这套。提示存算分离在Doris中属于进阶部署模式涉及组件较多建议在测试环境充分验证后再考虑生产落地。2. 部署前的整体设计与组件拆解2.1 存算分离架构到底拆了什么存算一体模式下Doris的BE节点既管数据存储又管计算。存算分离之后这两个职责被拆成两个角色Compute Node负责查询执行和计算本身不持久化数据Storage Node负责数据持久化但也可以参与部分计算。元数据方面存算一体靠FE的BDBJE做元数据高可用存算分离则引入了一个独立的Meta Service专门管理元数据和事务日志。用生活化的类比存算一体就像一家小餐馆厨师既炒菜又管仓库存算分离则是把仓库独立出去厨师只管炒菜需要食材的时候去仓库取。仓库可以很大、很专业厨师可以按客流灵活增减互不影响。在Docker环境里这意味着我们需要至少启动以下几类容器FE容器负责SQL解析、查询规划、元数据管理入口Meta Service容器负责元数据持久化和事务协调Storage Node容器负责数据实际存储Compute Node容器负责查询计算共享存储可以是MinIOS3兼容、或者挂载的共享卷2.2 为什么选Docker而不是直接物理机部署有人会问存算分离本来就是为大规模集群设计的用Docker是不是有点“杀鸡用牛刀”我的实际体会是Docker在这里的价值不是性能而是环境隔离和快速复现。存算分离涉及多个组件的版本匹配、配置文件联动、网络端口规划如果直接在物理机上装一旦某个组件版本不对清理起来很麻烦。Docker可以做到“一键销毁、一键重建”特别适合前期验证阶段。另外Docker Compose可以把所有组件的依赖关系、网络配置、卷挂载写在一个文件里团队里任何人拿到这个文件都能快速拉起一套一模一样的环境。这对于后续写部署文档、做CI测试都非常友好。当然Docker也有它的局限。比如网络性能不如host模式存储卷的IOPS可能成为瓶颈。所以我的建议是用Docker做验证和开发环境生产环境还是用物理机或者K8s编排。这篇内容聚焦在Docker验证环境的搭建。2.3 版本选择和镜像来源Doris的存算分离功能在2.1版本之后才比较稳定我实测用的是apache/doris:2.1.6这个官方镜像。Meta Service在官方镜像里已经包含不需要单独找镜像。MinIO用minio/minio:latest就行但建议固定一个具体版本比如minio/minio:RELEASE.2024-01-16T16-07-38Z避免latest更新导致兼容性问题。注意Doris存算分离对Meta Service和FE的版本一致性要求很高不要混用不同小版本的镜像。网络方面我创建了一个自定义bridge网络doris-net所有容器都接入这个网络容器之间用容器名互相访问。这样比用IP更稳定重启容器后IP变了也不影响配置。3. 核心组件配置与实操要点3.1 Meta Service的配置细节Meta Service是存算分离的“大脑”它负责管理元数据、事务日志和集群成员信息。在Docker里启动Meta Service关键配置项有几个meta_service_endpointMeta Service的访问地址格式是IP:PORT默认端口5000meta_service_rpc_portRPC通信端口默认也是5000meta_service_http_portHTTP接口端口默认5001我用的启动命令大概是这样docker run -d --name doris-meta \ --network doris-net \ -p 5000:5000 \ -p 5001:5001 \ -v /data/doris/meta:/opt/apache-doris/meta \ apache/doris:2.1.6 \ bash -c /opt/apache-doris/meta_service/bin/start_meta_service.sh这里有个细节Meta Service的数据目录必须挂载出来否则容器重启后元数据丢失整个集群就废了。我一开始没挂载结果重启容器后FE连不上Meta Service报meta service not found排查了半天才发现是数据没持久化。3.2 FE对接Meta Service的关键参数FE的配置在fe.conf里存算分离模式下需要额外加几个参数# 开启存算分离模式 cloud_mode true # Meta Service地址 meta_service_endpoint doris-meta:5000 # 是否让FE参与计算存算分离下FE只做规划 enable_fe_compute falsecloud_mode true这个开关是核心不开的话FE还是按存算一体模式启动根本不会去找Meta Service。我第一次部署时忘了加这个FE日志里一直报failed to connect to meta service后来翻官方文档才发现是这个参数没开。另外FE的元数据目录也要挂载因为FE本身还是需要存一些本地元数据缓存的。3.3 Storage Node和Compute Node的启动差异Storage Node和Compute Node在Docker里的启动方式类似但配置参数不同。Storage Node的核心配置# 存储后端类型支持S3、HDFS等 storage_backend s3 # S3兼容存储的配置 s3_endpoint http://minio:9000 s3_access_key minioadmin s3_secret_key minioadmin s3_bucket doris-data s3_region us-east-1Compute Node的核心配置# 指定Meta Service地址 meta_service_endpoint doris-meta:5000 # 计算节点的本地缓存目录 compute_node_cache_dir /opt/apache-doris/compute_node/cacheCompute Node本身不持久化数据但会有本地缓存来加速查询。这个缓存目录建议挂载出来不然每次重启都要重新拉数据查询性能会受影响。实操心得Storage Node和Compute Node的be.conf里都有一个node_role参数Storage Node设为storageCompute Node设为compute。这个参数如果设错节点会以错误的角色注册到集群导致数据写入失败。3.4 MinIO作为共享存储的配置MinIO的部署相对简单docker run -d --name minio \ --network doris-net \ -p 9000:9000 \ -p 9001:9001 \ -e MINIO_ROOT_USERminioadmin \ -e MINIO_ROOT_PASSWORDminioadmin \ -v /data/minio:/data \ minio/minio:RELEASE.2024-01-16T16-07-38Z \ server /data --console-address :9001启动后需要手动创建一个bucket名字和be.conf里的s3_bucket保持一致。我建议用mc客户端或者MinIO控制台创建不要指望Doris自动创建bucket实测下来Doris不会自动建bucket会直接报bucket not found。4. 完整部署流程与关键环节实现4.1 环境准备和网络规划先确认Docker和Docker Compose已经装好。我用的是Ubuntu 22.04Docker版本24.0.7Compose版本2.23.0。如果你的环境是Windows或者MacDocker Desktop也可以但要注意文件挂载路径的写法不同。创建自定义网络docker network create doris-net规划好各容器的端口映射组件容器内端口宿主机端口用途FE80308030HTTP访问FE90309030MySQL协议Meta Service50005000RPC通信Meta Service50015001HTTP接口MinIO90009000S3 APIMinIO90019001控制台Storage Node90609060BE通信Compute Node90609061BE通信Compute Node和Storage Node的BE通信端口默认都是9060如果跑在同一台宿主机上需要把其中一个映射到不同端口否则会冲突。4.2 启动顺序和依赖关系存算分离的启动顺序很重要我踩过坑如果先启动FE再启动Meta ServiceFE会一直重试连接日志刷得飞快。正确的顺序是先启动MinIO创建bucket启动Meta Service确认5000端口可访问启动FE检查日志确认连上Meta Service启动Storage Node确认注册成功启动Compute Node确认注册成功验证Meta Service是否正常curl http://localhost:5001/health返回OK就说明Meta Service起来了。验证FE是否连上Meta Service可以进FE的MySQL客户端mysql -h 127.0.0.1 -P 9030 -uroot然后执行SHOW FRONTENDS;如果看到FE的状态是ALIVE说明FE本身没问题。再执行SHOW BACKENDS;这里应该能看到Storage Node和Compute Node都注册上来了。如果SHOW BACKENDS为空说明BE节点没注册成功需要去BE日志里找原因。4.3 建表和写入验证集群起来之后建一个测试表验证存算分离是否真正生效CREATE DATABASE test_db; CREATE TABLE test_db.t1 ( k1 INT, v1 VARCHAR(100) ) DUPLICATE KEY(k1) DISTRIBUTED BY HASH(k1) BUCKETS 4 PROPERTIES ( replication_num 1 );存算分离模式下replication_num可以设为1因为数据可靠性由共享存储保证不需要多副本。这也是存算分离的一个优势——省存储成本。插入几条数据INSERT INTO test_db.t1 VALUES (1, hello), (2, doris), (3, cloud);然后查询SELECT * FROM test_db.t1;如果能正常查到数据说明整个链路是通的。这时候可以去MinIO的控制台看看doris-data这个bucket下面应该出现了对应的数据文件。我实测下来数据文件会按tablet ID分目录存储结构比较清晰。4.4 参数计算与资源规划在Docker环境里跑存算分离资源规划不能太随意。我一开始给每个容器只分配了2GB内存结果Compute Node跑复杂查询时直接OOM。后来调整成FE4GB内存2核CPUMeta Service2GB内存1核CPUStorage Node4GB内存2核CPUCompute Node8GB内存4核CPUMinIO2GB内存1核CPU这个配置能支撑大概千万级数据的测试查询。如果数据量更大Compute Node的内存需要相应增加因为Doris的查询执行是内存密集型的。Docker Compose里可以用deploy.resources来限制deploy: resources: limits: memory: 8G cpus: 4注意Docker Compose的deploy字段在非Swarm模式下默认不生效需要用docker compose --compatibility up来启动或者直接用mem_limit和cpus参数。5. 常见问题与排查技巧实录5.1 FE启动报错“meta service not found”这是最常见的问题原因通常有三个Meta Service没启动、网络不通、或者cloud_mode没开。排查步骤确认Meta Service容器在运行docker ps | grep doris-meta进FE容器测试网络docker exec -it doris-fe ping doris-meta检查fe.conf里cloud_mode true和meta_service_endpoint是否正确我遇到过一次是meta_service_endpoint写成了localhost:5000但在容器里localhost指向的是FE自己不是Meta Service。改成容器名doris-meta:5000就好了。5.2 Storage Node注册失败Storage Node注册失败通常和S3配置有关。如果MinIO的bucket没创建、或者access key不对Storage Node启动时会报错但不会退出只是注册不上。去Storage Node的日志里搜register关键字能看到具体原因。另一个常见原因是node_role设错了。Storage Node的be.conf里必须设node_role storage如果没设或者设成compute它会以Compute Node的身份注册导致集群里没有Storage Node建表时会报no storage node available。5.3 查询报错“no compute node available”这个报错说明Compute Node没注册上。检查Compute Node的日志常见原因有meta_service_endpoint配置错误Compute Node的端口和Storage Node冲突Compute Node的内存不足启动过程中被OOM Killer干掉了我遇到过一次是Compute Node和Storage Node都映射了9060端口到宿主机结果第二个启动的容器端口冲突直接退出。后来把Compute Node映射到9061就好了。5.4 数据写入慢或者超时存算分离模式下数据写入需要经过Meta Service协调再写到共享存储链路比存算一体长。如果写入慢可以从这几个方面排查问题现象可能原因排查方法写入超时MinIO性能瓶颈检查MinIO容器CPU和磁盘IO写入报错bucket权限不足用mc客户端测试读写写入慢网络延迟高检查容器间网络延迟事务冲突Meta Service负载高查看Meta Service日志我实测下来MinIO如果跑在机械硬盘上写入性能会明显下降。建议MinIO的数据目录挂载到SSD上哪怕是用Docker volume也要确保底层存储是SSD。5.5 容器重启后集群状态异常Docker环境里容器重启是常事但存算分离集群对启动顺序敏感。如果Meta Service还没完全启动FE就起来了FE会进入重试状态。我的做法是写一个启动脚本按顺序启动并等待健康检查通过#!/bin/bash docker start doris-meta until curl -s http://localhost:5001/health | grep -q OK; do sleep 2 done docker start doris-fe sleep 10 docker start doris-storage docker start doris-compute这个脚本虽然简单但能避免大部分启动顺序导致的问题。实操心得建议把Meta Service的数据目录和MinIO的数据目录做定期备份。存算分离模式下Meta Service挂了整个集群就不可用了元数据比数据本身更关键。6. 性能调优和后续扩展方向6.1 Docker环境下的性能调优Docker默认的网络和存储驱动会带来一定性能损耗。如果对查询延迟敏感可以考虑使用host网络模式减少NAT开销把Compute Node的缓存目录挂载到tmpfs加速缓存读写调整Doris的parallel_fragment_exec_instance_num参数充分利用CPU不过host网络模式下端口冲突会更频繁需要提前规划好。我一般只在性能测试时用host模式日常开发还是用bridge网络。6.2 从Docker验证到生产部署的迁移路径Docker环境验证通过后往生产迁移时需要注意生产环境建议用K8s部署Doris官方有Operator支持共享存储从MinIO换成生产级对象存储或者HDFSMeta Service需要做高可用至少三个节点网络规划要重新做生产环境通常跨机房我自己的迁移路径是Docker验证配置和SQL兼容性然后在一台测试物理机上用二进制包部署一套最后再上生产集群。每一步都验证一遍虽然慢但稳。6.3 存算分离适合什么场景不是所有场景都适合存算分离。根据我的经验适合数据量大、查询并发高、存储成本敏感、需要弹性扩缩容的场景不适合数据量小、查询延迟要求极低、运维团队对Doris不熟悉的场景存算分离的架构复杂度比存算一体高不少如果团队没有足够的运维能力强行上存算分离可能会带来更多问题。我见过一个团队数据量才几百GB就上了存算分离结果Meta Service的运维成本比省下来的存储成本还高。最后分享一个小技巧在Docker环境里验证存算分离时可以先把replication_num设为1减少数据写入量加快验证速度。等确认整个链路通了再调整副本策略。这样能省不少等待时间。