【大数据Doris】生产环境,Doris主键模型全表7000万数据更新写入为什么那么慢?

公司在 Apache Doris 的生产实践中,发现在做数据需求时候,遇到这样一个"致命"问题:

复制代码
"一张 7000 万行的主键模型账单表,执行全表 INSERT 时,不仅写入慢得像蜗牛,还把整个 BE 节点拖到 CPU 100%、IO 打满,集群几乎瘫痪。"

今天这篇文章用来记录下这个问题,且做详细剖析,并给出一套可落地、高性价比的优化方案。

首先,我从Doris官网了解到,这并非Doris的缺陷,而是主键模型(Unique Key / Primary Key)的写入机制与全量导入场景天然不匹配。以下是进行问题分析和问题解决。

一、为什么主键模型 INSERT 这么慢?------ 根本原因

Doris 的主键模型(特别是 Merge-on-Write 实现)在写入时必须保证数据唯一性,因此采用 "读-改-写"(Read-Modify-Write) 机制:

python 复制代码
INSERT INTO t_bill_center VALUES (id=1001, ewb_no ='010010101099')
        ↓
1. 查找 id=1001 是否已存在(需扫描主键索引)
2. 若存在 → 在 delete_bitmap 中标记旧记录为"删除"
3. 再将新记录写入 MemTable

关键性能瓶颈:

瓶颈点 技术细节 影响
delete_bitmap 维护 每次更新都要修改位图(tablet_meta.cpp:763) 内存压力大,频繁 GC
MemTable 冲突 多线程写同一 tablet 时锁竞争(tablet.cpp:363) 并发写入吞吐骤降
无批量合并 默认每条 INSERT 独立提交 网络 + 日志开销爆炸
Compaction 压力 高频写入触发大量 Delta Compaction IO 打满,查询变慢

一句话总结:

主键模型是为"实时更新"设计的,不是为"全量覆盖"准备的。

二、核心优化方案:启用 Group Commit(攒批提交)

Doris 从 1.2 版本 开始引入 Group Commit 功能,专为解决高频小写入场景的性能问题。它能将多个 INSERT 请求自动攒批、合并提交,大幅降低事务开销。

启用方式(两种)

方式 1:建表时指定(推荐)

python 复制代码
CREATE TABLE t_bill_center (
    user_id BIGINT,
    ewb_no VARCHAR(100),
    email VARCHAR(100)
) ENGINE=OLAP
UNIQUE KEY(user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 64
PROPERTIES (
    "group_commit_interval_ms" = "10000",      -- 每 10 秒提交一批
    "group_commit_data_bytes" = "134217728"   -- 或累计 128MB 提交
);

方式 2:全局 FE 配置(fe.conf)

python 复制代码
# 默认值(Config.java:646-652)
group_commit_interval_ms = 10000
group_commit_data_bytes = 134217728  # 128MB

原理:

Group Commit 在 BE 端维护一个内存队列(group_commit_queue_mem_limit),当达到时间或大小阈值时,一次性将多条 INSERT 合并为一个事务提交,减少 WAL 写入和锁竞争。

三、BE 层关键参数调优(be.conf)

主键模型对内存和 IO 极其敏感,以下配置可显著提升稳定性:

python 复制代码
# 1. 增大写缓冲(默认 200MB,5000 万数据建议 ≥ 500MB)
write_buffer_size = 536870912  # 512MB

# 2. 启用自适应缓冲(根据负载动态调整)
enable_adaptive_write_buffer_size = true

# 3. 控制并行 flush 任务数(避免 IO 打满)
memtable_flush_running_count_limit = 2

# 4. Group Commit 队列内存(默认 64MB)
group_commit_queue_mem_limit = 268435456  # 256MB

# 5. Group Commit 处理线程(根据 CPU 核数调整)
group_commit_insert_threads = 8

# 6. WAL 磁盘限制(防止日志占满磁盘)
group_commit_wal_max_disk_limit = 10%

注意:

复制代码
write_buffer_size 过大会导致 OOM,建议不超过 BE 节点内存的 20%。

四、终极建议:换用更高效的导入方式

对于 7000 万级全量数据,绝对不要用 INSERT INTO ... VALUES (...)!这是性能灾难的根源。

推荐方案:Stream Load + 分批导入

步骤 1:将数据拆分为多个文件(如每份 200 万行)

python 复制代码
split -l 2000000 full_data.csv chunk_
# 生成 chunk_aa, chunk_ab, ...

步骤 2:使用 Stream Load 并行导入

python 复制代码
# 示例:导入一个分片
curl --location-trusted -u user:passwd \
    -H "label:load_20240601_aa" \
    -H "column_separator:, " \
    -T chunk_aa \
    http://fe_host:8030/api/lbdb/t_bill_center/_stream_load

优势:

复制代码
性能提升 5~10 倍(Stream Load 专为批量设计)
自动重试 + 断点续传
不占用 MySQL 协议连接池

对比:

    INSERT:单连接,逐条解析,事务开销大
    Stream Load:HTTP 并行,批量解析,零事务开销

五、如果必须用 INSERT?------ 安全分批策略

若因架构限制只能用 INSERT,请务必分批 + 限流:

python 复制代码
-- 错误示范(直接全量插入)
INSERT INTO t_bill_center SELECT * FROM temp_table;

-- 正确做法:循环分页插入
INSERT INTO t_bill_center
SELECT * FROM temp_table 
ORDER BY user_id 
LIMIT 100000 OFFSET 0;   -- 第1批

INSERT INTO t_bill_center
SELECT * FROM temp_table 
ORDER BY user_id 
LIMIT 100000 OFFSET 100000; -- 第2批
-- ... 循环直到完成

同时配合:

复制代码
    应用层加 sleep(1s) 避免压垮 BE
    监控 show proc '/backends' 内存使用

六、监控与诊断:如何判断优化是否生效?

关键监控命令:

python 复制代码
-- 1. 查看 BE 节点状态(重点关注 Mem、IO)
SHOW PROC '/backends';

-- 2. 查看 Compaction 任务是否堆积
SHOW PROC '/compaction';

-- 3. 查看 Group Commit 队列(Doris 2.0+)
SHOW PROC '/group_commit';

七、架构升级建议:Doris 2.0+ 用户必看

如果你使用的是 Doris 2.0 或更高版本,强烈建议:

复制代码
迁移到 Primary Key 模型(非 Unique Key)
    新主键模型使用 Memory + RocksDB 存储索引
    写入性能比旧版提升 3~5 倍
    支持 Partial Update(只更新部分列)

开启 Light Schema Change
    避免 ALTER TABLE 锁表

八、总结:优化 checklist

优化项 操作 预期效果
启用 Group Commit 建表加 PROPERTIES 写入吞吐 +200%
调大 write_buffer_size be.conf 配置 减少 flush 频率
换用 Stream Load 分批 HTTP 导入 避免集群卡死
分批 INSERT LIMIT + OFFSET 降低瞬时压力
升级 Doris 2.0+ 使用 Primary Key 根本性性能提升

最后说明:

"主键模型 ≠ 全量导入工具"。

用对场景(实时更新),才能发挥 Doris 的真正威力。

相关推荐
sevenez2 小时前
Vibe Coding 实战笔记:从“修好了C坏了AB”到企业级数据库架构重构
c语言·笔记·数据库架构
智嵌电子2 小时前
【笔记篇】【硬件基础篇】模拟电子技术基础 (童诗白) 第10章 模拟电子电路读图
笔记·单片机·嵌入式硬件
2301_800050992 小时前
mysql
数据库·笔记·mysql
武子康2 小时前
大数据-197 K折交叉验证实战:sklearn 看均值/方差,选更稳的 KNN 超参
大数据·后端·机器学习
数据皮皮侠2 小时前
2m气温数据集(1940-2024)
大数据·数据库·人工智能·制造·微信开放平台
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之mmove命令(实操篇)
linux·服务器·前端·chrome·笔记
不会学习?3 小时前
markdown笔记分享
经验分享·笔记
MaximusCoder3 小时前
Linux信息收集Command
运维·服务器·经验分享
QT 小鲜肉3 小时前
【Linux命令大全】001.文件管理之mdel命令(实操篇)
linux·运维·服务器·chrome·笔记