资讯详情

资讯详情

OceanBase旁路导入:一张表同时支撑高并发交易与PB级数据装载

做数据的人大概都有这种经历业务方半夜丢来一个需求说有一批几个 TB 的历史数据要在第二天早高峰之前灌进线上库还不能影响白天的交易。传统做法要么是深夜停写、跑批量脚本要么用 INSERT 一条条塞结果白天业务一上来锁等待、IO 抖动、日志暴涨全来了。OceanBase 4.x 之后引入的“旁路导入”思路就是为了解决这个两头堵的问题一张表既能继续扛高并发交易同时还能把 PB 级数据批量灌进去。这篇文章围绕“一张表同时支撑交易和导入”这条主线把旁路导入到底绕过什么、怎么做、踩过什么坑讲清楚。适合正在做数据迁移、历史数据归档、或者数据库选型评估的同学读不需要你事先精通 OceanBase 内部原理只要能看懂 SQL、知道主键索引大概是怎么回事就行。1. 为什么“一边交易、一边导数据”这么难1.1 在线交易的底层存储逻辑决定了写入成本要理解旁路导入的价值得先搞明白为什么普通 INSERT 在 PB 级数据面前会“卡脖子”。绝大多数关系型数据库为了保证并发交易的正确性写入都要经过完整链路SQL 解析、权限检查、事务分配、写入日志、修改内存中的数据结构再异步落盘。这一套机制在每秒几千笔订单的场景下没问题但放到“一次性灌入几十亿行历史记录”的场景问题就被放大了。首先是日志放大。每一行数据通过普通写入路径进库几乎都对应着事务日志的产生而事务日志为了保证崩溃恢复又要做双写甚至多副本同步。数据本身只有 1GB日志和相关开销可能让它变成 3GB 甚至更多的磁盘写入。PB 级数据按这个放大系数算磁盘寿命和耗时都是灾难。其次是锁与冲突。在线表有大量并发交易在写批量导入也在写两条写路径同时操作同一张表轻则行锁等待重则锁升级。我见过某系统做历史数据补录时正常交易响应时间从 5 毫秒直接飙到 2 秒最后只能停掉导入任务让业务先跑。第三是内存与合并压力。带 LSM 或类似存储结构的数据库写入会先到内存表再按规定策略合并到持久化层。大批量写入会让内存表快速膨胀触发频繁的合并操作而这些合并操作会大量占用 CPU 和磁盘 IO进一步干扰在线交易。所以问题不在“能不能导入”而在“导入动作本身如何不拖垮在线负载”。1.2 传统导入方案的三个“不治本”很多人遇到大数据量导入第一反应是开并行、加机器、挑业务低峰期。这些办法能缓解但解决不了根本矛盾。加并行度只是把压力摊到更多线程上总体的日志放大和锁冲突还在。挑低峰期也只是把问题推迟到凌晨如果业务是全球化的所谓低峰期根本不存在。更麻烦的是数据校验和失败重试几千亿行数据跑到 90% 的时候报了一个唯一键冲突整个任务回滚换谁都想摔键盘。这时候需要的不是“更快地走老路”而是直接换一条路数据不经过传统事务引擎的写入链路而是以文件形式直接进存储层。1.3 一张表同时扛两种负载的本质OceanBase 允许多种负载共存的底气来自其存储引擎的架构设计。持久化数据以类 SSTable 的文件形式组织同时内存中有服务于在线写入的结构。旁路导入做的事情就是让批量数据绕过内存表、绕过事务日志直接在存储层生成新的数据文件然后通过内部机制让这些文件对查询可见。这样一来导入消耗的不再是“事务写路径”的资源而是存储节点的文件生成能力两者在物理上就被隔离开了。2. 旁路导入到底“旁”在哪2.1 常规写入路径的七步链路先拆一次普通 INSERT 在 OceanBase 里大致做了什么。SQL 进来以后先解析、生成执行计划然后进入事务引擎分配事务 ID写 redo 日志再把数据更新到内存表。内存表积累到一定大小之后会触发合并把数据落到存储文件。- 整个过程要保证 ACID要支持回滚要为并发读写提供多版本一致性。这些保证在交易场景下全是优点但在批量导入场景全变成负担。可以这样理解普通写入进来相当于客人到餐厅点菜厨师一菜一菜地炒服务员一桌一桌地上。再加个日志系统相当于每上一道菜都要录一段视频留证。交易场景必须这样因为每道菜都是独立订单。但如果你要一次性把一整个集装箱的预制菜送进后厨还按“一菜一炒”的办法来就非常蠢。2.2 旁路导入的换路操作旁路导入的思路是既然数据源本身已经是一个“大文件包”那就直接在文件层面做转换。具体来说导入工具读取外部数据源在存储节点上直接生成 OceanBase 存储引擎能识别的数据文件然后把文件分发到对应的分区位置。整个过程中没有逐行事务、没有 redo 日志、没有内存表堆积数据文件生成完毕之后挂载即可。你可以理解为从“一菜一炒”换成了“中央厨房批量出菜直接送进仓库”。这样做带来的直接结果有三个事务日志归零、锁开销归零、内存表压力归零。这就是为什么同样一批数据普通 INSERT 要跑几个小时旁路导入能压到几十分钟。2.3 一致性如何保证有人会担心绕过事务日志万一导入到一半机器断电数据是不是就乱了这里要注意旁路导入并非“无日志裸写”。它依然有完整性校验和断点恢复机制只是在写入阶段不产生面向在线事务的那种日志开销。导入任务本身是作为一个整体被管理的数据文件生成过程中有校验和、文件级同步文件全部就绪后才对外可见。这个机制很像“搬文件”而不是“写数据库”先把所有文件搬到目标目录再统一完成原子切换。在切换那一瞬间在线查询才能看到新数据。所以事务隔离性并没有被破坏只是把“逐行可见”变成了“批量可见”。2.4 一条适用于实际场景的分界线从应用角度可以简单分这么几类增量小批量的数据业务系统实时写入的用普通 DML历史数据迁移、数仓数据回灌、备份恢复这种大批量场景用旁路导入平时数据校验、临时表复制这种中间动作可以按数据量级灵活选。这个分界线不需要一开始就定得非常精确经验值是单次导入超过 100GB或者行数达到亿级就应该认真考虑旁路导入。3. 实操一张表上并行跑交易和数据装载的落地流程3.1 事前准备目标表的“三个对齐”不要拿到数据就开始导。我因为跳过准备步骤吃过亏后来总结出三个必须提前对好的事分区对齐、类型对齐、索引对齐。分区对齐指的是源数据的分片方式最好和目标表分区键一致。比如目标表按订单日期分了 30 个分区那源文件最好也按日期切片否则导入过程中会出现跨分区重分布性能至少打七折。类型对齐看着简单实际上最容易被坑。源系统里时间字段是字符串 “2024-01-01 08:00:00”目标表是 datetime 类型这种转换如果让导入任务逐行做效率极低最好在生成导入文件之前就统一成目标类型。索引对齐更关键。如果目标表上有多个二级索引旁路导入在生成主表数据文件的同时也必须维护索引数据。二级索引越多导入的额外开销越大。我的习惯是对于一次性导入场景先评估哪些索引是业务真正要用的其他索引可以考虑导入完成后再补建。3.2 导入任务配置的通用流程不同版本的接口有差异但通用流程是可以复用的。第一步定义外部数据源位置和格式文本、CSV、或者专用的数据文件格式都可以第二步指定目标表和导入模式明确是覆盖写入还是增量追加第三步设置并行度也就是同时生成多少个数据文件第四步执行导入前的数据校验包括主键冲突、空值率、数据类型第五步启动任务并持续监控。拿一个具体例子某客户系统要把第三方平台导出的 5TB 订单历史导入线上订单表。数据是 CSV 格式按天一个文件共 180 个文件。他们的做法是先把目标表按日期分区调整为与文件粒度一致然后设置了 32 个并发任务每个任务负责若干个日期文件。导入过程中从监控面板能看到各节点同时生成数据文件的进度磁盘 IO 保持稳定同时线上交易的平均响应时间基本没有波动。整个导入耗时大约 70 分钟。作为对比同样的数据用普通批量 INSERT在资源相同的情况下预测需要 12 小时以上而且过程中交易响应时间必然被拖垮。3.3 导入过程中的资源隔离与监控要点旁路导入虽然绕过了事务写路径但它仍然要消耗 CPU、内存、磁盘带宽。生产环境里最好做到三点限速、限并发、盯磁盘。限速就是给导入任务设置带宽上限或者文件生成速率上限避免导入吃满所有 IO。限并发就是不要把所有节点资源都交给导入任务留出裕量给在线交易。盯磁盘则是因为数据文件生成过程中如果磁盘写满或者 IO 延迟出现拐点导入速度会断崖式下降。我见过一个案例某系统导入任务同时生成了大量文件每个文件又设置了多副本结果磁盘 IO 直接被拉满在线写入延迟从 2 毫秒涨到 100 毫秒。后来在导入任务里限制了生成速率又调整了副本写入策略延迟立刻回到 3 毫秒以内。旁路导入的本质是“隔离”但如果你不做资源管控隔离也不起作用。3.4 增量场景下的“先建后切”策略还有一类常见场景不是一次性导入而是周期性地把数仓里的结果回灌到在线表。这种场景我推荐“先建后切”的策略尤其是当目标表数据量很大、且不能接受长时间阻塞的时候。具体做法是在同一个数据库实例里建一张结构相同的新表或者使用全新的一组分区把数据通过旁路导入灌到新对象上。全部数据就绪并完成校验之后用一个切换动作把新数据对业务可见。这样做有几个天然好处导入全程不影响现有表数据即使导入失败回滚成本极低切换之前的任意时刻业务都在访问旧数据安全性最高。实际生产中我曾经协助某业务团队用这个方式把一张 20 亿行的历史表从旧的存储引擎迁移到新表。导入用了 6 个小时中间业务完全无感。切换那一刻只需要在应用层改一下数据源指向或者数据库内部做一个原子切换比直接在原表上做原地变更要稳妥得多。4. 性能表现与调优经验4.1 影响导入速度的三大核心因素第一个因素是数据源本身的读取速度。如果数据在对象存储或者本地磁盘上读取速度基本上决定了导入速度的上限。我做过简单测算5TB 文件从本地磁盘读出假设持续读速度是 800MB/s理论最短时间是 5TB / 800MB/s 约等于 1.8 小时。也就是说旁路导入再怎么优化也不可能低于源端读取时间。第二个因素是 CPU 的解码和编码能力。外部文件解析、字段校验、内部格式转换这些操作都需要 CPU。对于 CSV 这类文本格式CPU 消耗尤其明显因为要做字符串到二进制类型的转换如果是列式存储的专用文件格式CPU 开销会低很多。第三个因素是网络带宽和副本策略。分布式数据库里数据文件生成后往往要同步到多个副本如果网络带宽有限或者副本数设置过高导入耗时会被同步操作拖住。而这三个因素恰好都是在线交易不怎么触及的资源所以调优的方向很清楚哪里瓶颈最明显就从哪里调。4.2 调优实战从 3 小时压到 45 分钟有一个模拟项目的导入任务最初耗时 3 小时让业务方很着急。我参与排查后发现三个问题源文件是单文件读取并发上不去每个任务的数据量不均匀有的任务处理 2TB有的只处理 200GB导致部分节点空闲目标表的分区键和源数据分布不一致产生了大量跨节点数据传输。针对三个问题分别处理把源文件切片成 64 个均匀的小文件调整任务分配策略按数据量而不是按文件数分配提前和目标表对齐了分区逻辑绕开跨节点重分布。完成后导入耗时降到 45 分钟。整个过程中业务端没有停写这组数据就是旁路导入典型收益的缩影。4.3 与普通导入方式的对比表对比维度普通批量 INSERT旁路导入事务日志每一批数据都产生完整事务日志不产生在线事务日志有文件级一致性保障锁影响对目标表产生行锁甚至表锁不产生行级锁对在线 DML 影响小内存表压力大量数据积压触发频繁合并不经过内存表直接生成存储文件性能量级每分钟几万行的写入量级每节点可达每秒数百 MB 级断点恢复大批量回滚代价大支持文件级断点续导适用场景小批量、实时写入历史数据迁移、初始化加载、大规模回灌这里要加一句对比表里的数字都是经验值真实数据取决于硬件配置、数据格式、副本数等。但趋势是稳定的数据量越大、导入越集中旁路导入的优势越明显。4.4 并行度不是越大越好很多人的直觉是并行度开得越高越快实际上到了某个阈值之后收益会迅速递减甚至转为负收益。原因是并发任务之间会争抢 CPU 资源、文件句柄、网络连接和磁盘 IO一旦这些资源出现竞争任务之间反而互相拖慢。我一般在生产环境会先按目标表所在节点的 CPU 核数来估算比如单节点 48 核我会先设置 8 到 16 个并发任务跑一到两分钟观察资源使用率如果磁盘 IO 还有大量余量就逐步增加并发直到磁盘 IO 或者 CPU 出现拐点。这样逐步逼近比一开始拍脑袋定一个数要靠谱得多。5. 常见问题与排查技巧实录5.1 失败类型一导入任务中途卡死最常见的卡死原因第一是源端文件被占用或者权限不足第二是网络连接数打满第三是目标表所在节点资源不足导致任务排队。排查时不要只盯着数据库的会话列表要从整体链路去看源端状态、网络连接、存储节点资源三层依次排查。我有一套固定的排查顺序先看任务当前停留在哪个阶段是读取阶段、转换阶段还是文件生成阶段再看对应节点的磁盘 IO 和网络吞吐确认是否达到瓶颈最后看是否有慢查询或者锁等待在拖后腿。用这个顺序排查大部分问题都能在十几分钟之内定位。5.2 失败类型二导入完成后数据对不上旁路导入虽然有一致性保证但数据校验依然要做特别是源数据本身就不干净的时候。常见的坑有CSV 文件里的引号转义导致字段错位源系统的时间字段包含无效值比如 2 月 30 日字符编码不一致导致中文变成乱码。我现在每次导入前后都会做一个四步校验先记录源文件行数导入完成后对比目标表行数抽样对比若干关键字段包括数值边界和时间边界最后跑一遍业务核心查询看结果是否符合预期。四步都过了再对外宣告导入完成。5.3 失败类型三导入过程挤占了在线业务资源这个问题前面写过核心原因基本都是没做资源隔离。这里补充一个我后来的固定配置导入任务单独设置资源组限制 CPU 使用率上限和 IO 带宽监控指标里增加“在线交易响应时间”和“导入吞吐”两个并列指标当在线业务 P99 延迟超过阈值时会自动降低导入任务的并发度。这套机制听着复杂实际做起来就是几个配置项的事但它能让“旁路导入不影响在线交易”从一句广告词变成一个可量化、可验证的事实。我强烈建议凡是生产环境要做大导入的系统都把这个配置加上。5.4 避坑清单速查问题现象核心原因解决方向导入速度远低于预期源端读取串行文件切片增加源端读取并行度部分节点很忙、部分节点空转任务分配不均匀按数据量或分区粒度重新分配导入过程中交易延迟升高资源未隔离设置资源组、限制并发和带宽导入完成但查询结果异常编码、转义或类型未统一导入前后执行四步校验重新导入失败数据文件残留清理未完成的任务文件后再跑这个清单是我自己维护的每次遇到新问题就补一行。现在基本把生产环境里八成的问题都覆盖了你也可以把它当成一个初始版本在自己的实践里继续扩展。6. 几个容易混淆的点6.1 旁路导入不等于“无日志”很多人在第一次听到旁路导入时会以为它完全不做日志。实际上它只是不做面向在线事务的日志文件本身的生成、校验、同步过程依然有记录。不然的话任务失败了连断点都找不到恢复就无从谈起。你可以把普通事务日志理解成街边小店的流水账每一笔都要记得清清楚楚旁路导入的日志更像是物流仓库的出库单只记录“哪一批货从哪来、发到了哪、批次状态如何”。两种日志的粒度完全不同。6.2 旁路导入不等于“不校验”恰恰相反旁路导入因为数据量大、操作集中校验的重要性比普通写入更高。普通写入可以靠事务回滚来兜底旁路导入一旦在后期才发现数据问题修复成本要高得多。所以我建议在任务启动之前就做大量的前置校验把可能的脏数据挡在门外。导入完成之后再做点位校验前后两头都守住中间过程才不容易翻车。6.3 旁路导入最适合谁用就我的经验而言最需要旁路导入的其实是两类场景。一类是数据平台部门他们经常要在凌晨把几 TB 的数仓结果同步到在线库传统方式每次都搞得胆战心惊另一类是业务系统在做数据迁移或者扩容的时候旧表数据要在尽量短的时间内搬到新表同时又不能停机。至于数据量只有几 GB、甚至几百 MB 的场景普通批量写入完全够用没必要上旁路导入。工具选型最怕的不是“不知道有什么”而是“杀鸡用牛刀”带来不必要的运维复杂度。7. 写在最后的几条个人体会我自己的使用体会是旁路导入最大的价值不是“快”而是“安心”。原来每次做大表迁移脑子里都绷着一根弦怕导入拖垮业务、怕跑到一半失败回滚、怕上线之后数据对不上。用了旁路导入之后导入动作变成了一个可以在业务运行时平稳执行的后台任务心态完全不一样。还有一点想提醒大家任何工具都不是万能的。旁路导入再怎么优化也替代不了业务侧对数据模型的合理设计。表分区策略差、二级索引泛滥、文件格式混乱这些问题在导入环节都会被放大。工具只是给了你一条更好的路怎么把路周边的环境收拾整齐更值得花时间。最后分享一个我最近养成的习惯凡是做超过 1TB 的导入任务都先在测试环境跑一遍完整流程记录耗时和资源曲线再上生产。测试环境和生产环境的硬件不一样但流程跑通之后生产上出现意外情况的数量会明显减少。这个习惯帮我避开了很多次半夜救火的局面你也值得一试。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →