
1. 为什么要在Docker里折腾Doris存算分离第一次接触Doris存算分离架构是在一个日志分析项目里。当时数据量每天新增大概两三百GB原始的三副本存算一体集群磁盘水位一直告警扩容就得整节点加机器成本压不下来。后来把冷数据迁到对象存储计算节点只保留本地缓存磁盘用量直接砍掉六成以上查询性能在缓存命中场景下几乎没有衰减。这就是存算分离最直接的收益存储和计算各自独立扩缩容存储层用廉价对象存储兜底计算层按查询负载弹性伸缩。Doris从2.1版本开始正式支持存算分离模式核心思路是把BE节点的数据文件从本地磁盘搬到远端共享存储HDFS或S3兼容对象存储BE本地只保留缓存和元数据。计算节点变成无状态可以随时拉起或销毁。这个架构特别适合两类场景一是存储成本敏感、数据量持续增长的分析平台二是查询负载波动大、需要快速扩缩计算资源的业务。那为什么用Docker来部署原因很实际。存算分离涉及FE、BE、MSMeta Service、远端存储等多个组件手工在物理机或虚拟机上装一遍光是配置文件和依赖就能耗掉大半天。Docker把每个组件的运行环境打包好用compose编排起来一条命令就能拉起整套集群环境一致性也有保障。对于想快速验证存算分离效果、或者做本地开发的场景Docker是最省事的路径。这篇文章面向的是有一定Doris基础、想动手试存算分离的运维和开发人员。我会从架构选型讲到compose文件编写再到启动验证和踩坑排查把整套流程拆开揉碎讲清楚。你不需要有存算分离的经验但至少要熟悉Docker的基本操作和Doris的常规部署方式。提示存算分离模式下MSMeta Service是新增的核心组件负责管理元数据和事务FE和BE都依赖它。很多人第一次部署失败就是因为漏了MS或者MS配置不对。2. 存算分离架构拆解与Docker部署方案选型2.1 存算分离到底分离了什么先把概念理清楚。传统Doris集群里FE负责元数据和查询规划BE负责数据存储和计算。数据以tablet为单位存在BE本地磁盘上三副本机制保证可靠性。存算分离之后BE不再持久化数据到本地而是把数据写到远端共享存储本地磁盘只做缓存。这样BE变成无状态节点挂掉一个不影响数据完整性重新拉起就能继续服务。具体来说存算分离模式下有几个关键变化。第一BE的存储层抽象成了远端存储加本地缓存两层远端存储可以是HDFS也可以是S3兼容的对象存储。第二新增了MS组件它承担了原来FE里跟存储相关的那部分元数据管理职责比如tablet的元信息、事务状态等。第三FE和BE之间的交互逻辑有调整FE不再直接管理tablet的副本分布而是通过MS来协调。这个架构的好处很直接存储层用对象存储成本比本地SSD低一个数量级计算层可以按需扩缩查询高峰多加几个BE低谷再减掉不用像存算一体那样担心数据重平衡。代价是引入了网络开销缓存未命中时查询延迟会上升所以缓存策略和远端存储的带宽很关键。2.2 为什么选Docker Compose而不是K8s部署存算分离Doris生产环境一般上K8s用Operator管理。但如果你只是想快速验证、做本地开发、或者在小规模环境里跑Docker Compose是更轻的选择。K8s那套东西光是集群本身就要维护再加上Doris Operator的配置学习曲线陡。Compose的好处是配置文件直观一条docker compose up就能拉起整套资源占用也小。当然Compose有它的局限。它不适合大规模集群没有自动故障转移扩缩容要手动改配置。但对于单机验证存算分离的核心流程这些都不是问题。我的建议是先用Compose把架构跑通理解各组件怎么交互再决定要不要上K8s。选型上还有几个点要考虑。远端存储用什么本地验证的话MinIO是最方便的选择S3兼容Docker拉起也快。如果已经有HDFS集群直接连HDFS也行。MS组件Doris官方提供了镜像直接用就行。FE和BE的镜像版本要跟MS匹配建议统一用同一个版本号比如都用2.1.x。2.3 组件清单与资源规划一套最小的存算分离Doris集群需要这些组件组件作用最小实例数建议资源FE查询规划、元数据管理12C4GBE数据计算、缓存14C8GMS元数据服务12C4GMinIO远端对象存储12C4GMySQLFE元数据存储11C2GFE自己也需要一个元数据存储存算分离模式下还是用MySQL。MinIO用来模拟S3对象存储。整体算下来一台16G内存的机器就能跑起来当然生产环境要按数据量和查询负载来规划。网络方面所有组件要在同一个Docker网络里互相能通。端口规划上FE的HTTP端口8030、RPC端口9020BE的HTTP端口8040、心跳端口9050MS的端口5000MinIO的9000和9001MySQL的3306。这些端口在compose文件里要映射出来方便本地访问。注意BE的本地缓存目录要挂载出来否则容器重启缓存就丢了查询性能会受影响。缓存目录大小根据本地磁盘空间来定建议至少留50GB。3. Docker Compose编排文件逐段拆解3.1 基础环境与网络配置先建一个工作目录比如doris-disaggregated所有配置文件都放这里。compose文件用3.8版本定义一个自定义网络让所有容器在同一个网段里。version: 3.8 networks: doris-net: driver: bridge ipam: config: - subnet: 172.20.0.0/16指定子网是为了让容器IP固定方便配置文件里写死地址。虽然Docker的DNS也能解析服务名但Doris有些配置项对IP更友好固定IP能少踩坑。MySQL用官方镜像挂载初始化脚本建好FE需要的数据库和用户。MinIO也用官方镜像启动时自动创建bucket。services: mysql: image: mysql:8.0 container_name: doris-mysql environment: MYSQL_ROOT_PASSWORD: doris123 MYSQL_DATABASE: doris_fe volumes: - ./mysql-data:/var/lib/mysql networks: doris-net: ipv4_address: 172.20.0.10 ports: - 3306:3306MySQL的初始化脚本里要建好doris_fe库FE启动时会自动建表。密码用简单的就行本地验证不用太复杂。MinIO的配置类似重点是启动命令里指定好access key和secret key后面BE和MS连对象存储要用。minio: image: minio/minio:latest container_name: doris-minio command: server /data --console-address :9001 environment: MINIO_ROOT_USER: dorisadmin MINIO_ROOT_PASSWORD: dorisadmin123 volumes: - ./minio-data:/data networks: doris-net: ipv4_address: 172.20.0.11 ports: - 9000:9000 - 9001:9001MinIO起来之后要手动建一个bucket比如叫doris-data。可以用mc客户端建也可以登录控制台建。这个bucket就是BE写数据的远端存储位置。3.2 MS组件配置要点MS是存算分离的新增组件配置相对简单但有几个参数必须对。它需要连MySQL存元数据需要连对象存储存实际数据。doris-ms: image: apache/doris:ms-2.1.0 container_name: doris-ms environment: - MS_CONFIGmeta_service volumes: - ./ms-config:/opt/apache-doris/ms/conf networks: doris-net: ipv4_address: 172.20.0.12 ports: - 5000:5000 depends_on: - mysql - minioMS的配置文件meta_service.conf里重点配这几项# MySQL连接 mysql_host 172.20.0.10 mysql_port 3306 mysql_user root mysql_password doris123 mysql_db doris_meta # 对象存储配置 s3_endpoint http://172.20.0.11:9000 s3_access_key dorisadmin s3_secret_key dorisadmin123 s3_bucket doris-data s3_region us-east-1 # 服务端口 brpc_port 5000s3_region这个参数容易被忽略MinIO虽然不校验region但SDK要求必须填随便填一个就行。s3_endpoint要带http://前缀不带的话连接会失败。3.3 FE节点配置与启动参数FE的配置跟常规部署差不多但要多配一个MS的地址。FE启动时要指定meta_service_endpoint指向MS的地址。doris-fe: image: apache/doris:fe-2.1.0 container_name: doris-fe environment: - FE_CONFIGfe volumes: - ./fe-config:/opt/apache-doris/fe/conf - ./fe-data:/opt/apache-doris/fe/doris-meta networks: doris-net: ipv4_address: 172.20.0.13 ports: - 8030:8030 - 9020:9020 - 9030:9030 depends_on: - mysql - doris-msFE的fe.conf里关键配置# MySQL元数据 meta_dir /opt/apache-doris/fe/doris-meta priority_networks 172.20.0.0/16 # MS地址 meta_service_endpoint 172.20.0.12:5000 # 存算分离模式 cloud_unique_id 1cloud_unique_id是存算分离模式的标识每个集群要唯一。priority_networks指定FE用哪个网段的IP多网卡环境下必须配不然FE可能选错IP导致BE连不上。FE启动后用MySQL客户端连9030端口执行SHOW FRONTENDS能看到FE状态。存算分离模式下FE的元数据操作会转发给MS所以MS必须先起来。3.4 BE节点配置与缓存策略BE是存算分离里变化最大的组件。它不再持久化数据本地磁盘只做缓存。配置上要指定MS地址、对象存储信息、缓存路径和缓存大小。doris-be: image: apache/doris:be-2.1.0 container_name: doris-be environment: - BE_CONFIGbe volumes: - ./be-config:/opt/apache-doris/be/conf - ./be-storage:/opt/apache-doris/be/storage - ./be-cache:/opt/apache-doris/be/cache networks: doris-net: ipv4_address: 172.20.0.14 ports: - 8040:8040 - 9050:9050 depends_on: - doris-fe - doris-msBE的be.conf关键配置# MS地址 meta_service_endpoint 172.20.0.12:5000 # 缓存配置 storage_root_path /opt/apache-doris/be/storage file_cache_path /opt/apache-doris/be/cache file_cache_size 50GB # 对象存储 s3_endpoint http://172.20.0.11:9000 s3_access_key dorisadmin s3_secret_key dorisadmin123 s3_bucket doris-data s3_region us-east-1 # 计算资源 be_port 9060 webserver_port 8040 heartbeat_service_port 9050 brpc_port 8060file_cache_size是本地缓存的上限超过这个值会淘汰旧缓存。这个值设太小会导致频繁回源查询变慢设太大又占磁盘。建议按本地磁盘空间的60%到70%来设。storage_root_path在存算分离模式下只存元数据和临时文件不存实际数据所以不用太大。BE启动后在FE里执行SHOW BACKENDS能看到BE状态是Alive就说明注册成功了。如果BE一直不出现先检查MS地址和网络连通性。提示BE的缓存目录和存储目录要分开挂载缓存目录用SSD性能更好。如果本地磁盘有限缓存可以设小一点但要做好查询变慢的心理准备。4. 启动验证与核心操作流程4.1 按依赖顺序启动集群Compose的depends_on只保证启动顺序不保证服务就绪。所以启动要分步来每步确认服务正常再继续。第一步拉起MySQL和MinIOdocker compose up -d mysql minio等MySQL日志出现ready for connectionsMinIO控制台能访问再进下一步。MinIO控制台地址是http://localhost:9001用配置的账号密码登录手动建一个doris-data的bucket。第二步拉起MSdocker compose up -d doris-msMS启动后检查日志有没有报错。重点看MySQL连接和S3连接是否正常。如果日志里有connect to mysql failed检查MySQL的IP和密码如果有s3 connection error检查MinIO的endpoint和bucket是否存在。第三步拉起FEdocker compose up -d doris-feFE启动比较慢要等它完成元数据初始化。用docker logs -f doris-fe观察日志看到FE started successfully就差不多了。然后用MySQL客户端连上去mysql -h 127.0.0.1 -P 9030 -uroot执行SHOW FRONTENDS状态是JOINED就正常。第四步拉起BEdocker compose up -d doris-beBE启动后在FE里执行SHOW BACKENDS等状态变成Alive。这个过程可能要一两分钟BE要向FE和MS注册。4.2 建表验证存算分离效果集群起来之后建一个测试表验证数据是不是真的写到了MinIO。CREATE DATABASE test_db; USE test_db; CREATE TABLE test_table ( id INT, name VARCHAR(50), create_time DATETIME ) DUPLICATE KEY(id) DISTRIBUTED BY HASH(id) BUCKETS 3 PROPERTIES ( replication_num 1 );存算分离模式下replication_num设1就行因为数据在远端存储已经有冗余了本地不需要多副本。插入几条数据INSERT INTO test_table VALUES (1, test1, NOW()), (2, test2, NOW());然后去MinIO控制台看doris-data这个bucket应该能看到多出来的目录和文件。这些就是BE写上去的数据文件。如果bucket里是空的说明BE没往远端写检查BE的S3配置。再查一下数据SELECT * FROM test_table;能查到就说明读写链路都通了。这时候可以做个实验把BE容器停掉再拉起来数据还在因为数据在MinIO上BE本地只是缓存。这就是存算分离的核心价值。4.3 缓存命中与性能观察存算分离模式下第一次查询要回源到MinIO拉数据延迟会高一些。第二次查询如果缓存命中了就跟本地读差不多。可以这样验证-- 第一次查询观察耗时 SELECT COUNT(*) FROM test_table; -- 第二次查询应该快很多 SELECT COUNT(*) FROM test_table;BE的缓存命中情况可以在BE的Web界面看地址是http://localhost:8040里面有缓存统计。file_cache_hit_rate这个指标能直观反映缓存效果。如果命中率一直很低要么是缓存太小要么是查询模式太随机。实际生产里缓存策略要结合查询模式来调。如果查询集中在最近几天的数据可以把缓存设大一点让热数据常驻。如果查询很分散缓存收益就有限这时候要考虑远端存储的带宽和延迟。注意存算分离模式下BE的本地磁盘IO不再是瓶颈网络带宽和对象存储的吞吐才是。MinIO单机性能有限生产环境要用真正的分布式对象存储。5. 常见问题排查与避坑经验5.1 启动阶段的高频报错部署存算分离Doris启动阶段最容易出问题。我整理了几个高频报错和排查思路报错信息可能原因排查方法MS启动失败日志报MySQL连接超时MySQL没就绪或IP不对检查MySQL容器状态确认IP是172.20.0.10FE启动后BE一直不注册MS地址配错或网络不通在BE容器里ping MS的IP检查meta_service_endpointBE日志报S3连接失败endpoint格式不对或bucket不存在确认endpoint带http://前缀bucket已创建FE查询报missing meta serviceMS没起来或FE的cloud_unique_id没配检查MS状态确认FE配置里有cloud_unique_id有一个坑我踩过MinIO的bucket如果没提前建好BE写数据时会报bucket not found但错误信息不明显容易以为是权限问题。所以启动MinIO之后第一件事就是建bucket。还有一个是网络问题。Docker默认的bridge网络里容器之间用服务名也能通但Doris有些组件对IP更敏感。我建议统一用固定IP在compose里指定ipv4_address配置文件里也写IP这样最稳。5.2 运行阶段的性能问题集群跑起来之后常见的性能问题集中在缓存和远端存储上。缓存命中率低是最常见的。表现是查询延迟忽高忽低BE的缓存统计里命中率不到50%。原因可能是file_cache_size设太小或者查询的数据量远超缓存容量。解决办法是加大缓存或者优化查询让热数据更集中。远端存储带宽不足是另一个问题。MinIO单机跑在Docker里网络吞吐有限如果BE并发回源带宽很容易打满。表现是查询排队BE的RPC队列积压。这种时候要么换更强的对象存储要么限制并发查询数。还有一个容易被忽略的点BE的本地磁盘如果IO性能差缓存读写也会成为瓶颈。缓存目录建议放在SSD上不要跟系统盘混用。5.3 数据一致性与恢复验证存算分离模式下数据一致性靠MS和远端存储保证。验证方法很简单停掉BE删掉BE的本地缓存目录再拉起BE数据应该还能查到。如果查不到说明数据没真正写到远端或者MS的元数据有问题。# 停BE docker compose stop doris-be # 删缓存 rm -rf ./be-cache/* # 重新拉起 docker compose start doris-be等BE状态恢复Alive再查数据。能查到就说明存算分离生效了。这个验证很有必要能提前发现配置问题。MS的数据也存在MySQL里如果MySQL挂了整个集群的元数据就丢了。所以MySQL的数据目录要持久化最好定期备份。生产环境MySQL也要做高可用单点风险太大。提示存算分离模式下BE的本地数据可以随时丢弃但MS的MySQL数据不能丢。备份策略上MySQL的备份优先级最高。6. 从验证环境到生产落地的扩展思路Docker Compose跑通之后下一步就是往生产环境迁移。生产环境一般用K8s部署Doris官方有Operator能管理存算分离集群的生命周期。迁移的时候配置项基本一致主要是把compose里的服务定义翻译成K8s的CRD。远端存储方面MinIO可以换成真正的S3兼容对象存储或者HDFS。Doris对S3和HDFS都支持配置上改一下endpoint和认证信息就行。对象存储的选型要考虑吞吐、延迟和成本冷数据用低频存储能进一步降成本。计算节点的扩缩容在存算分离下变得很简单。加BE就是多拉一个容器注册到FE就行不用像存算一体那样等数据重平衡。缩容也一样直接停掉BE数据不受影响。这个弹性能力是存算分离最大的卖点。监控方面FE和BE都暴露了Prometheus格式的指标可以接Grafana看板。重点关注的指标包括BE的缓存命中率、远端存储的读写延迟、FE的查询队列长度。这些指标能提前发现性能瓶颈。最后说一个实际体会存算分离不是银弹它适合存储成本敏感、查询负载波动的场景。如果数据量不大、查询很频繁存算一体的本地SSD性能还是更好。选架构要看业务特点不要为了分离而分离。