首页 / 资讯中心 / 文章详情

OceanBase旁路导入:PB级数据秒级落盘与在线交易共存之道

OceanBase旁路导入:PB级数据秒级落盘与在线交易共存之道 ★ FEATURED ARTICLE
1. 旁路导入到底在解决什么问题先说一个真实场景。我之前帮一个电商系统做分布式数据库选型的时候客户反复问一个问题一张已经在 OceanBase 上跑高并发交易的表能不能在不中断业务的前提下把几十 TB 甚至 PB 级的存量数据导进去这个问题在几年前基本无解因为传统导入方式意味着连夜的插入风暴、日志暴涨、和在线交易抢内存。直到把 OceanBase 的旁路导入真正用起来才发现一条路让导入数据不经过 SQL 层和事务链路直接批量落成数据文件这才真正做到一张表既扛高并发交易又能快速吞下 PB 级数据。先把这个概念说透。旁路导入英文叫 Direct Load核心思路就是不走常规 DML 的完整链路直接把外部数据文件变成数据库底层的存储文件。很多人第一反应是“这不就是批量导入吗LOAD DATA 不也能导大数据”其实差别非常大。LOAD DATA 虽然语法上是一条语句但底层仍然一条一条写数据仍然要过事务、写日志、进内存。旁路导入相当于绕开了整条“生产线”从源头就把数据封装成数据库可以直接挂载的文件格式。这也是它能在导入海量数据的同时对在线交易影响较小的根本原因。这篇文章适合谁看如果你正在做数据迁移、大表初始化、离线批量同步或者只是被“导大表导到半夜还没完”折磨过那直接往下看。我会从底层原理讲到实操命令再讲我踩过的坑尽量让你少走弯路。1.1 传统导入方式为什么顶不住常规的导入方式本质上是把源文件里的每一行数据当成一条 DML 语句来处理。哪怕你用多线程并发插入也只是把并行的压力往后端堆瓶颈并没有消失。一次插入在数据库内部要经历什么语法解析、生成执行计划、走事务引擎分配事务 ID、写 redo 日志、写 undo 信息、更新索引最后数据落到内存里的写缓冲区。等缓冲区到了一定阈值还要触发转储把增量数据合并到 SSTable 里。这套机制在正常业务写入下非常成熟但拿来导入 PB 级数据时就显得太“重”了。我打个比方。常规插入像你雇了一万个搬运工每个人手里拎着一个文件袋从大门口一趟一趟往档案室送。即使你把门口拓宽、把搬运工数量加多档案室里的登记流程仍然一道都不能少每个人都要签收、归档、登记。旁路导入则是直接叫了一辆卡车把一整车已经整理好的档案箱拉到档案室门口管理员只检查箱子编号然后整箱上架。你说哪个快还有一点容易被忽略传统导入的每一行数据都会产生 redo 日志和 undo 信息。PB 级的数据量意味着日志量也接近 PB 级磁盘 IO 会被日志写放大严重拖累。更麻烦的是导入期间这些日志还要参与高可用同步每个副本都要应用一遍。很多人导数据导到半夜发现日志目录满了就是这个问题。1.2 旁路导入的快快在哪里旁路导入的快不是单纯的“并发高”而是链路短。它把大批数据文件按分区、按主键范围拆成多个分片每个分片由独立的导入线程处理数据直接经过解析、类型转换、排序、校验然后在各节点上直接生成存储层的数据文件。这个过程不产生 redo不经过内存写缓冲区也不参与常规事务的锁竞争所以 CPU、内存和磁盘 IO 的开销比传统插入低很多。举一个直观的例子。同样导一张 5 TB 的表常规并发导入可能需要十几个小时而且期间业务写入明显变慢偶尔还会出现锁等待。旁路导入如果并发设置合理可能压缩到一两个小时同时在线业务的 p99 延迟波动也小得多。这个差距不是靠硬件堆出来的而是路径不同带来的结构性优势。不过要提醒一句旁路导入并不是“万能加速器”。它对数据质量、文件格式、目标表结构都有要求。你不能拿一个格式混乱的 CSV 指望导入速度起飞也不能在主键冲突严重的数据上指望它自动帮你清洗。后续我会专门讲这些坑。2. 一张表既扛交易又能吞下PB级导入底层靠什么很多人不理解为什么同一张表一边高并发交易在写一边还能大批量导入两者不打架吗要回答这个问题得先看懂 OceanBase 底层是怎么存数据的。2.1 先说存储引擎的LSM-TreeOceanBase 的存储引擎是 LSM-Tree 架构和传统的 B 树存储引擎思路完全不同。传统 B 树是“就地更新”数据写在页面上更新的时候直接改磁盘上的数据页。LSM-Tree 则是“先写内存再批量落盘”所有写入先落到内存里的写缓冲区也就是 MemStore达到阈值后冻结再通过转储生成磁盘上的 SSTable后续再通过合并把多个 SSTable 归并成大文件。这套设计最明显的好处是写路径短。随机写变成了顺序写内存累积一批后一次性落盘所以高并发交易场景下写入吞吐很猛这也是 OceanBase 能扛超高并发写入的底气。但代价就是读取路径变长查一条数据可能先在内存里查查不到再去磁盘上的分层文件里查如果多个 SSTable 都有旧版本数据还得做多版本合并。LSM-Tree 架构里最贵的一步是数据合并。因为平时写入产生的增量数据是零散的不合并的话读取时要翻太多文件。所以系统会在后台不断做转储和合并把数据整理成更紧凑的文件。这也是 LSM-Tree 数据库在写入量大时经常出现“合并风暴”的原因。2.2 旁路导入如何绕开事务路径既然 LSM-Tree 最贵的是合并那如果能跳过“先写内存再转储再合并”这条链路直接把外部数据生成好现成的 SSTable是不是就意味着导入过程不再需要合并的算力旁路导入就是这么干的。它把数据文件在外部直接切分、排序然后生成完整的 SSTable 文件再把这些文件挂到目标表上。整个过程中数据不需要进 MemStore不需要等待转储也不会成为后台合并的对象。等于别人要花很久才能完成的数据整理你在导入阶段就已经完成了。而且因为数据文件是直接生成的导入时的 CPU 消耗主要是解析外部文件、做类型转换、排序和校验。这些操作很多可以并行而且不依赖事务并发控制。所以把并行度拉高导入速度可以接近磁盘和网络的物理上限。实测下来在千兆网络加多节点分布式集群的配置下吞吐量可以从每秒几万行跳到每秒百万行以上这个差距是数量级的。2.3 导入和在线交易在同一张表里怎么共存这里要解释一个关键技术点可见性。旁路导入生成的数据文件在一开始是不可见的它并不属于当前活跃事务的快照范围。只有当导入任务提交之后这批数据文件才在某个全局版本号下变为可见。也就是说正在跑的交易不会看到半截导入的数据这也避免了“读到导入一半的脏数据”这种问题。同时因为导入不产生 redo 日志也就不会占用事务日志的同步带宽。在线交易的高频写入照样走它自己的链路旁路导入走的是另一条数据通路。它们共享的是底层的 CPU、内存、磁盘和网络所以资源冲突仍然存在但没有锁竞争和日志竞争这种强冲突。实际操作时可以通过控制导入并行度、限定 IO 带宽或者干脆选择在业务低峰期导入把资源冲突降到最低。不过还有一点要坦白旁路导入本身通常需要拿到表级或分区级的锁才能安全地把数据文件挂载上去。所以它更适合“初始化导入”“存量迁移”这类场景而不是让外部系统每秒钟持续往里灌数据。如果你的诉求是持续高频同步那还是走正常写入更合适或者把增量攒成一个批次定时用旁路导入批量合并。3. 实操从数据文件到一张大表的完整导入流程理论说再多不如直接把命令跑一遍。下面我从导入前的检查、导入姿势、导入后的校验三个阶段完整还原我在项目中用旁路导入做大表初始化的过程。3.1 导入前的检查清单少一项都容易翻车先说最容易翻车的地方磁盘空间。旁路导入不是把数据读进内存再写进数据库而是直接生成一份完整的数据文件落盘这期间不仅要存原始数据文件还要存生成的临时文件。加上导入过程中如果启用了校验和索引构建空间占用会更高。我一般建议预留目标表最终大小的 1.5 到 2 倍空闲磁盘。别小看这一点生产环境磁盘快满的时候导入大概率导到一半报错。然后是文件格式和切分。源文件如果是 CSV建议提前确认分隔符、转义符、字符集尤其是字段里包含换行和逗号时一定要做转义处理。另外文件最好按逻辑拆成多个大小相近的分片比如每个分片 1 GB 到 4 GB这样导入并行度才能拉开。单一大文件即使设了高并行读取端也容易成为瓶颈效果会大打折扣。还要检查目标表结构。如果你要导入的表有唯一索引或者主键数据里绝不能有大量重复键否则导入过程中做唯一性校验时会抛错。一个可行的办法是先用外部工具对源数据按主键排序并去重再启动导入。这个预处理看起来多了一步实际上能省下后面排查的无数时间。权限也不要漏导入账号至少需要目标表的 INSERT 权限如果涉及建临时文件还需要对应的目录写权限。3.2 两种直连旁路导入的姿势我常用的第一种方式是用官方命令行工具。工具的大致调用方式如下obloader -h 127.0.0.1 -P 2881 -u roottest -p your_password -D test \ --table orders --csv --direct \ --parallel 8 \ --file-path /data/orders_split/参数的含义很直白--direct打开旁路导入模式--parallel控制并发线程数--file-path指向分片文件的目录。看起来简单但这里有几个细节值得说一下。第一并行度不是越大越好。我遇到过一个案例把--parallel调到 32结果导入端 CPU 全部打满磁盘 IO 也高达 99%可目标库所在宿主机的业务 CPU 被打到告警。后来降到 8总耗时只多了不到 20%在线业务的延迟却恢复正常。所以不要盲目追求大并行而是要看整体资源余量。一般先从 4 到 8 开始观察一两个文件跑完后的耗时和资源占用再逐步上调。第二目录里的文件切片大小要有策略。文件太小比如几十 MB 一个导入线程的调度开销会吃掉不少性能文件太大比如 100 GB 一个单线程处理时间过长一旦失败重试代价很大。我习惯把源数据切成 2 GB 左右的分片既方便并行也方便失败后只重跑部分分片。第二种方式是直接在 SQL 里用LOAD DATA加直导提示词LOAD DATA /* DIRECT(true, parallel 8) */ INFILE /data/orders.csv INTO TABLE orders FIELDS TERMINATED BY , LINES TERMINATED BY \n;这种方式的优点是可以少部署一个工具直接在 SQL 客户端里发起。缺点是单条 SQL 处理超大文件时如果中途断了恢复起来没有命令行工具那么方便。所以我更推荐把文件先分片然后再用多条 SQL 并发导入或者直接用命令行工具。这里还要提一个非常实用的变种分区交换。如果目标是一张按时间分区的大表你可以先把数据导入一张同结构的分区临时表再通过分区交换操作把临时表快速挂载为正式分区。这种用法适合“每个月出一张新分区、一次性换入”的跑批场景几乎不会影响其他分区的在线查询。3.3 导入完成后的校验与收尾工作数据导完别急着欢呼。我最开始做导入的时候就遇到过“提示成功但数量对不上”的情况。所以导入完成后一定要做几件事。先做行数校验。最直接的办法是源端统计文件行数和目标表SELECT COUNT(*)对一下。如果分片很多可以用多个并发查询按分区汇总效率更高。行数不对的时候先查是不是文件里本身有空行、结尾换行符处理不一致或者某些字段因为类型转换失败被过滤掉了。然后是抽查数据质量。随便抽几条源文件里的记录到目标表里按主键查出来对比关键字段是否一致。批量导入最容易出问题的点是字符串截断、时区转换、浮点精度。订单金额、时间戳这类字段建议重点看。要么写一个简单的对比脚本要么用数据库侧的校验函数对关键列做聚合校验。最后一步是更新统计信息。旁路导入是直接生成数据文件数据库的统计信息不会自动更新。统计信息一旦过期查询优化器很可能选错执行计划最典型的表现就是“导完数据之后简单查询变慢了”。我在 4.2 节会细讲这个问题。现在只需要记住导入完成后要手动收集一次统计信息必要的时候再做一次合并把新挂载的数据文件整理得更紧凑。4. 实战中反复踩到的坑以及排查思路这部分内容不是我翻文档看来的是真实跑过好几轮导入之后攒下来的教训。我挑几个高频问题给出一眼就能用的排查思路。4.1 导入速度一直上不去问题出在哪如果是旁路导入还是慢先别怪数据库。排查顺序通常是源端读取 - 网络传输 - 数据解析 - 目标端落盘。源端读取是最容易被忽视的瓶颈。你文件放在机械硬盘上却要求导入吞吐跑满万兆网卡这不现实。先把文件放到 SSD 或者把读文件的方式改成内存映射再测一次往往有惊喜。如果你从对象存储拉数据那瓶颈就更明显了对象的 QPS 限制可能比数据库落盘还低。其次看网络。小文件吞吐测试发现带宽不达标时检查是不是只用了单条 TCP 连接。并行度上去了但每个线程还是顺序读同一个大文件网络层没有建立足够多的连接同样跑不满。这时候把大文件多切几个分片让不同的线程读不同的文件网络利用率会立刻改善。再看解析和类型转换。CSV 文本解析非常耗 CPU尤其是字段多、字符串占比高的时候。同一个数据我用 CSV 导入比用 Parquet 导入慢了将近一半。如果数据链路允许尽量把源文件转成列式格式再导入能省掉大量文本解析开销。真的只能用 CSV 时也要避免在导入语句里做表达式计算和类型转换这些东西会在导入线程里逐个字段执行非常拖速度。最后看目标端落盘。如果磁盘写吞吐已经打满并行度再高也没有用。此时要么压缩源文件体积减少写入量要么把导入分配到多个租户、多个节点上把写入压力分散开。还有一个相对少见的坑导入时如果有其他任务在做大合并磁盘 IO 会被合并吃掉一大截导致旁路导入速度骤降。遇到这种情况最好查一下后台合并调度给它设置一个低优先级时段。4.2 导入完成后查询反而变慢导入成功行数也对但业务方反馈“查询比之前慢了不少”。我排查过一次发现原因很简单统计信息没有更新。正常写入一条条插入的时候数据库会逐步更新统计信息优化器对数据分布有基本感知。旁路导入直接生成一批数据文件相当于凭空多出了一个“数据岛”统计信息完全不知道新文件里有什么。比如某张订单表的日期字段原来最大只到今天现在导入了去年的历史数据优化器还按照“只有几个月数据”的模型去算扫描行数自然选错执行计划。解决办法就是导入后立刻收集统计信息。在 OceanBase 里可以调用统计信息收集的存储过程对整个表或者单个分区做一次统计非常重要。收集完统计信息如果发现查询还是慢再看数据文件的分布。旁路导入生成的文件未必是全局有序的如果你的查询经常做范围扫描可以主动发起一次合并让数据文件更紧凑、索引效率更高。我一般把这一步排到发布流程里避免上线后才被业务方找上门。还有一个隐蔽问题目标表如果有二级索引旁路导入在导入阶段会同步构建索引。如果构建索引时并行度不够或者索引列的数据分布极度倾斜导入完成后某些索引扫描路径会特别慢。这时要检查目标表所有索引的统计信息和数据分布必要的时候重建一下倾斜严重的索引。4.3 旁路导入和在线业务的资源冲突怎么解旁路导入虽然不产生 redo、不争事务锁但它毕竟要消耗 CPU、内存、磁盘 IO 和网络带宽。如果完全不控制它完全可以把一台机器的 IO 打满在线业务的写入延迟立刻飙升。我的建议是第一做限流。命令行工具通常支持设置并发和带宽上限先按业务低谷时可用资源的 50% 来配置跑一轮看看效果。如果在线业务延迟没变化再逐步往上加。不要一上来就用一个极高的并发去挑战极限生产系统经不起这种冒险。第二做时间窗。不是所有业务都 24 小时高负载。旁路导入尽量安排在业务低峰期比如凌晨。把最重的导入任务放在窗口内完成即使中途遇到问题也有足够的时间人工介入不影响白天业务。第三是监控合并任务。导入生成的新文件会在后台触发调度如果导入量很大可能造成合并任务排队并在某个时间集中执行。集中合并的 IO 压力不亚于导入本身。我会在导入完成后的半小时内盯一下合并相关的监控指标如果出现合并流量突增及时调整合并触发阈值或者手动错峰。下面这个表格是我整理的高频问题速查表遇到问题可以直接对照排查。现象可能原因解决方向导入速度上不去源文件在机械盘或被单文件读取限制切分文件、换 SSD、用列式格式导入并行度越高越慢瓶颈在网络或目标端磁盘 IO检查带宽和磁盘写吞吐降并行度导入报唯一约束冲突源数据重复或边界数据未去重按主键排序去重后再导入导入成功但行数不对空行、转义、类型转换被过滤对比文件行数抽查关键字段导入后简单查询变慢统计信息过期、生成文件不紧凑收集统计信息、主动合并导入期间在线事务变慢磁盘 IO 或 CPU 被导入占满限流、低峰导入、控制并行度导入中断后重跑很痛单文件过大失败重试代价高分片成多个小文件断点续传5. 写在最后旁路导入的适用边界和我的个人体会用了这么多次旁路导入我自己的体会是它解决的是“大规模初始化和批量同步”的问题不是“每秒钟持续高频写入”的问题。一张表既扛高并发交易又能快速导入 PB 级数据这句话的真正含义是可以在业务基本不停的情况下把海量存量数据在很短时间内灌进去。但如果你把它理解成“可以一边跑实时交易一边无限量持续灌数据”那一定会碰壁。综合来看适合用旁路导入的场景是这几类新集群上线时的全量数据迁移、历史库和冷数据归档批量入库、报表分析系统的大分区初始化、数据仓库每天的批量跑批。这些场景的共同点是单次数据量大对导入吞吐要求高并且导入窗口和在线业务可以错开。不适合的场景则是小碎数据高频实时写入那会生成大量小的数据文件反而拖累后续查询和合并。最后再分享一个我自己的操作习惯每次启动大导入之前先用一小片数据做一轮完整演练包括导入、校验、统计信息收集、在线查询验证。这个过程只要花十几分钟但能提前发现绝大多数格式、权限、资源问题。别拿生产环境几 TB 的数据当试验品演练阶段省下来的时间会在正式导入的时候翻倍还给你。
阅读完成 · 觉得有帮助?
咨询建站