凌晨三点爬起来补数的那天,我把问题归咎于“Sqoop导入慢”,排查到最后才发现,真正的瓶颈根本不是导入那一步,而是导入之后落地的文件格式。没错,就是平时很少有人主动关心的Sqoop导入数据文件格式。默认情况下Sqoop会把数据写成纯文本,下游Spark任务读这张表时被迫全量扫描、全字段反序列化,一个本可以用列裁剪缩短到十分钟的ETL,硬生生跑了一个多小时。这篇文章就把五种常用格式——TextFile、SequenceFile、Avro、Parquet、ORC——放在一起逐项拆解,说清楚各自的原理、代价和适用场景,最后给出我自己这些年做数仓沉淀下来的选型思路。适合正在用Sqoop做数据同步、或者准备从RDMBS向HDFS/Hive迁移数据的朋友参考。
1. 逃离“默认格式陷阱”:一次凌晨补数的复盘
1.1 这次问题是怎么暴露出来的
事情发生在给某业务线做月度报表补数的时候。源端MySQL订单表接近十亿行,Sqoop全量导入HDFS只用了不到四十分钟,听起来很正常对吧?问题出在下游:SparkSQL读这张表做聚合,需要按天过滤、只取五个字段。按理说这点数据量加上谓词下推,配合合适的存储格式应该是秒级到分钟级的事。但实际跑起来,Spark任务卡了快一个半小时,执行的DAG里Scan阶段读取的数据量几乎是全表体积的好几倍。
当时第一反应是集群资源不够,查了YARN资源、磁盘IO和网络,全部正常。后面把Spark物理计划翻出来,发现读取数据时用的是Scan parquet,但实际读到的却是TextFile格式,且没有做任何列裁剪和过滤下沉——所有字段全部加载,所有行全部扫过,等于把整张表完整读了一遍后才开始算。问题的根子不是任务参数,而是Sqoop导入时沿用了默认的文本格式。
1.2 Sqoop的默认行为与文件格式的“隐藏选择”
Sqoop从关系型数据库往HDFS导数据时,如果没有显式指定格式参数,默认输出就是纯文本文件,每条记录一行,字段间用分隔符隔开。这个设计很“朴实”:直接落盘、可直接查看、任何Hive表都能兼容。但朴实不等于划算,尤其当数据量上了亿级、下游还要频繁分析时,文本格式在存储成本和查询性能上的劣势就会被无限放大。
Sqoop实际上给了五个可选格式,分别对应--as-textfile、--as-sequencefile、--as-avrodatafile、--as-parquetfile和--as-orcfile。很多人知道这几个参数,但不太清楚彼此之间到底差在哪,甚至连“默认是TextFile”这件事都是踩完坑才反应过来。
提醒一句:Sqoop导入时的格式选择,本质上是在为下游查询引擎选择存储模型。这一步一旦走错,后面改格式就得重新导一次全量数据,代价远高于导入时的性能差异。
1.3 为什么这个坑普遍存在
我见过不少团队在Sqoop建同步任务时,只关注--query怎么写、--split-by选哪个字段、--num-mappers调多少,几乎没有人会主动去问“落盘格式选什么”。原因很简单:Sqoop的文档把格式参数放在“可选”的说明里,示例代码也大多以TextFile为主,大家自然觉得默认的就是唯一选项。再加上初建任务的往往是平台运维或BI工程师,他们面对的核心诉求是“数据有没有导过去”,而不是“导过去以后查得快不快”。
这个认知差会一直隐藏到数据量爆发的那一天。到那个时候,要改的可就不只是Sqoop命令了,还得同步改Hive建表语句、下游Job的读取逻辑、分区策略,甚至触发全量重导。所以与其说这是一篇格式对比文章,不如说是想帮大家从源头避开类似的被动局面。
2. 五种格式逐一拆解:同一张订单表,五种落地形态
2.1 TextFile:零成本但不是零代价
TextFile是Sqoop导入的默认格式,也是使用门槛最低的一种。本质上就是按行存储的纯文本,每一行对应一条记录,字段之间用分隔符分割。默认分隔符如果不显式指定,不同版本Sqoop的表现会有差异,所以实际项目里我几乎总是显式指定--fields-terminated-by,尽量和Hive表定义保持一致。
Sqoop导入TextFile时可以这样写:
sqoop import \ --connect "jdbc:mysql://127.0.0.1:3306/dw?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8" \ --username reader \ --password readpass \ --table orders \ --target-dir /warehouse/ods/orders_text \ --delete-target-dir \ --as-textfile \ --fields-terminated-by '\u0001'优点很直白:文件可读性强,出问题时可以直接用cat或less排查数据;没有任何schema约束,Hive表怎么建都可以;配合gzip、bzip2、snappy压缩后存储体积也能接受。但代价也非常集中——TextFile是纯行存,没有内建schema,这意味着:
- 不支持真正的列裁剪,查询引擎即使只取两个字段也得解析整行;
- 不支持谓词下推,Hive/Spark读一张十亿行文本表,几乎只能全表扫;
- 复杂类型(数组、Map、嵌套结构)没有原生的表达方式,硬塞进去也只能序列化成JSON字符串,查询时非常别扭;
- gzip压缩的文本文件无法split,下游Map/分区数可能被钉死成1个,并行度彻底失效。
TextFile最合理的定位是临时数据、小规模探查、或者对读性能完全无感的场景。一旦进入常态化分析链路,它基本就是上线那天埋下的雷。
2.2 SequenceFile:旧Hadoop时代的遗留
SequenceFile是Hadoop历史最长久的二进制行存格式之一,以key-value对的形式组织记录。Sqoop导入时可以把每一行数据封装成一条记录写入其中,支持无压缩、记录压缩和块压缩三种方式,压缩率通常优于纯文本。
导入命令:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --target-dir /warehouse/ods/orders_seq \ --as-sequencefile \ --compression-codec snappySequenceFile最核心的优势是和MapReduce生态绑定紧密,大量旧版MR任务可以直接使用。但放到现在的技术环境里,它的短板越来越明显:
- schema仍然隐藏在二进制结构里,没有统一的字段定义;
- 跨语言访问困难,除了Java系引擎,Spark、Presto、Flink读取它都很别扭;
- 列裁剪和谓词下推能力几乎为零,二进制反而比文本更难读取;
- 不适合数据湖、数据仓库这种需要多引擎访问的架构。
我的判断是:除非你的链路里存在改不动的大量老MR作业,且它们明确只认SequenceFile,否则新项目完全没有必要选它。Sqoop支持它更多是历史包袱,而不是推荐你主动入坑。
2.3 Avro:带schema的“国际快递”
Avro和TextFile、SequenceFile最大的区别在于它内置完整schema,而且是JSON格式定义,写在每个数据文件的头部。这意味着任何拿到文件的系统都能自解释字段名、字段类型和嵌套结构,天然适合跨系统、跨语言的数据交换场景。
Sqoop导入Avro时,会自动生成一个.avsc后缀的schema描述文件,放在目标目录下,方便后续建表或下游程序使用:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --target-dir /warehouse/exchange/orders_avro \ --as-avrodatafile \ --compression-codec snappyAvro的核心价值在于schema演进。源表加了字段、改了类型,只要给新字段配了默认值,旧文件和新文件可以在同一张表里共存,下游读取时按reader schema去解析,不会像某些格式那样一旦结构变化就必须全量重导。再加上它有成熟的行存序列化实现,序列化和反序列化的性能在几个二进制格式中相当靠前,很适合作为数据交换层、Kafka消息落盘、或者异构系统之间的中间格式。
它的局限是行存储架构,压缩率和查询性能不如Parquet和ORC。如果你的数据要落到数仓里做频繁聚合、过滤分析,Avro并不是最优解。更合适的用法是充当“传输格式”——从MySQL同步到HDFS形成ODS前的缓冲、或与其他团队做数据对接时的标准交付格式。
2.4 Parquet:列式存储里的扛把子
Parquet是目前大数据分析场景下使用面最广的列式存储格式,也是我这几年做数仓大概率会选的默认格式。列式存储的核心思想是按列组织数据,查询时只读取涉及列的数据块,配合谓词下推和压缩编码,能显著降低IO和内存开销。
Sqoop导入Parquet时指定:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --target-dir /warehouse/ods/orders_parquet \ --as-parquetfile \ --compression-codec snappyParquet的优势集中在这几点:
- 每列独立编码,压缩率高,数据量越大优势越明显;
- 支持复杂嵌套结构,天然适配Avro、Protobuf这类层级模型转换;
- Spark、Presto、Impala、Hive等主流引擎对Parquet的支持最成熟,尤其Spark和Parquet几乎绑定;
- 相比ORC,Parquet在跨生态兼容性上明显更好,不同引擎读起来都顺畅。
但Parquet也有一个容易被忽视的短板:写入时整个row group需要积攒一定数据量再刷盘,小批量数据频繁写入会产生大量小文件,既拖慢写入,又严重影响后续查询效率。Sqoop全量导入还好,如果是高频率增量小表导入,最好先落文本或带缓冲的方式再转换成Parquet,或者合理控制--num-mappers和导入频率。
另外,Parquet的schema演进相对保守,尤其遇到字段重命名、删除、嵌套结构变更时,往往需要重写文件。设计表结构时前瞻一点,比事后折腾心智负担小得多。
2.5 ORC:Hive派系的主场格式
ORC是Hive生态里优化最深入、查询性能最极致的列式格式之一。它在Parquet的列式思路上进一步增加了行组索引、布隆过滤器、谓词下推等能力,数据读取时可以做到只扫描满足过滤条件的最小组件,在Hive数仓场景下经常是性能最佳的那个。
Sqoop从1.4.6版本系列开始支持--as-orcfile参数,如果你用的是老版本Sqoop,建议通过HCatalog方式来写入ORC表。一个完整的写入示例:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --hcatalog-database dw \ --hcatalog-table ods_orders \ --create-hcatalog-table \ --hcatalog-storage-stanza "stored as orc"或者直接指定格式:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --target-dir /warehouse/ods/orders_orc \ --as-orcfile \ --compression-codec zlibORC的强项和Parquet有部分重叠,但它的优化更多面向Hive引擎:stripe级别的统计信息、索引过滤、复杂类型支持等都很成熟。压缩率通常略优于Parquet,尤其在以压缩比为核心诉求的表格上更明显。
短板也很直接:Spark对ORC的优化过去长期不如Parquet,虽然Spark 3.x之后已有明显改善,但如果你的一线查询引擎是Spark主导而不是Hive主导,优先推荐还是Parquet。另外ORC在Sqoop上的直接写入能力偏新,遇到小文件和高版本兼容问题时,排查资料不如Parquet多,踩坑时耐心得留足。
3. 五张表放一起才看得清的差异,以及三个常被忽略的维度
3.1 一张对比表看全核心指标
先把五种格式最关键的指标放一张表里,后面再针对性说明最有信息量的几个维度。
| 维度 | TextFile | SequenceFile | Avro | Parquet | ORC |
|---|---|---|---|---|---|
| 存储模型 | 行存 | 行存 | 行存 | 列存 | 列存 |
| 内建Schema | 无 | 无 | 有 | 有 | 有 |
| 列裁剪 | 不支持 | 不支持 | 不支持 | 支持 | 支持 |
| 谓词下推 | 不支持 | 不支持 | 不支持 | 支持 | 支持(最强) |
| 复杂类型 | 弱(需序列化) | 弱 | 强 | 强 | 强 |
| 跨引擎兼容 | 最好 | 差 | 好 | 最好 | 好(略偏Hive) |
| 压缩split能力 | 依赖压缩格式 | 支持 | 支持 | 支持 | 支持 |
| schema演进 | 无 | 无 | 好 | 一般 | 一般 |
| 典型定位 | 临时探查 | 存量MR | 数据交换 | 分析/湖仓 | Hive数仓 |
3.2 维度一:schema演进能力
现实中源表结构不是一成不变的,业务方加个字段、改个长度,甚至替换字段类型都时有发生。如果你的同步链路是“MySQL -> Sqoop -> HDFS -> Hive”,那么格式对schema演进的支持程度直接决定了线上表改动时的痛苦程度。
Avro的方案最优雅,因为reader schema和writer schema是分开定义的,新加字段只要声明了默认值,旧数据也能正常读取。Parquet和ORC虽然也支持某些演进操作,但实际使用时更谨慎,尤其是字段重命名、类型变更、嵌套结构改动,往往需要工具辅助重写整个文件。TextFile完全没有schema概念,所谓演进就是把新文件的字段数变一下,旧文件能不能兼容全看下游解析逻辑怎么写。
结论很清晰:如果是周期性同步且源表结构经常微调,Avro作为中间交换层会比直接上列式格式稳得多;如果数据要进分析层,那就需要接受列式存储演进成本偏高的事实,尽量在设计期把字段规划完整。
3.3 维度二:压缩之后能不能split
这个问题特别容易被忽略。很多人觉得“反正都是snappy,导完就算成功”,但忽略了压缩格式和文件格式的相互作用。
TextFile配合gzip时,压缩后的文件不可split,一个几GB的文件会被Map或Spark当成一个整体来读,并行度直接降为1,查询速度肉眼可见地崩盘。而bzip2和LZO可split,snappy本身不可split,但在Parquet/ORC这类容器格式里,snappy的块存储可以按容器的block/stripe来切分,所以不受影响。SequenceFile的block压缩、Avro的块结构、Parquet和ORC的列块存储都能保证在压缩基础上保持可split能力。
这背后的逻辑是:split能力取决于“能不能在不知道完整文件内容的前提下定位到某个数据块的起始位置”,容器格式天然可以做到,普通压缩格式做不到。所以同样是“用了snappy”,配在TextFile上和配在Parquet上完全是两回事。建议在Sqoop导入阶段就把这一点纳入考虑,不要事后发现下游Job并行度全被压缩干掉才回头找原因。
3.4 维度三:谓词下推与列裁剪的真实收益
对于分析型查询,谓词下推和列裁剪带来的收益不是“提升一点”,而是数量级的差距。一张十亿行的订单表,每天只查最近一周数据、只取五六列,Parquet和ORC实际读取的数据量可能只有TextFile的几十分之一。
TextFile那类行存格式做不到这一点,是因为列裁剪必须建立在“最小读取单元是列而不是整行”的前提下,这也是列式存储存在的根本理由。ORC的索引能力比Parquet更细,能定位到stripe甚至行组级别,所以Hive场景下性能上限更高;Parquet则在Spark/Presto生态中优化更充分,绝大多数情况下的收益已经足够明显。
从Sqoop的角度看,唯一要记住的结论是:如果表是要常态化进数仓分析链路的,永远不要使用默认TextFile;在Parquet和ORC之间选一个合适的列式格式,再差也比行存强。
4. 选型不是A/B测试:结合下游引擎和业务负载的决策路径
4.1 按下游引擎定第一优先级
选格式的第一把尺子,永远是“谁在读这些数据”。不要拿着格式说明文档在会议室里搞技术辩论,而是先看你们集群里跑得最多的是Spark、Hive、Presto还是其他引擎。
如果你的数仓主要是Hive跑离线任务和报表,ORC往往是最合适的选择,因为Hive对ORC的优化颗粒度最细,还有对bloom过滤和行组剪枝的内建支持。如果Spark主导批量分析,Parquet是兼容性最好、优化最成熟的选项,几乎每个Spark版本都优先适配Parquet特性。如果查询引擎是Presto/Trino,两者都能用,但考虑到团队熟悉度和迁移成本,Parquet通常更省心。
这个优先级基本能把Parquet和ORC的争论收敛掉七成。剩下三成,再看访问模式。
4.2 按访问模式再做第二重筛选
确定了引擎偏好后,还要看这张表的使用节奏和查询特征。
- 偏扫描型:每天跑全量聚合、很少做点查,Parquet和ORC差异不大,按引擎习惯选即可。
- 偏过滤型:查询总是带明确where条件,例如按日期、状态过滤,ORC的索引优势会逐渐放大。
- 偏宽表型:一张表几百列,但查询经常只取少数几列,列式格式的收益最大,列裁剪越强越好,两者都达标但Parquet在Spark下表现更直接。
- 偏轻量交换:数据是给另一个团队用的、对方引擎未知,此时Avro反而是比列式格式更稳的选择,因为对方不一定能方便读Parquet。
- 偏运维探查:数据量很小,主要是人工验证、查错,TextFile最方便,没必要为性能引入复杂度。
4.3 一个可复用的选型决策表
把上述思路整理成一个可以拿来就用的决策表:
| 业务形态 | 推荐格式 | 实践原因 |
|---|---|---|
| Hive数仓核心表 | ORC | 索引优、压缩优、Hive优化最完整 |
| Spark分析/数据湖 | Parquet | 生态最成熟、谓词下推与列裁剪收益稳定 |
| 跨团队/跨引擎数据交换 | Avro | schema内嵌、演进友好、实现成本低 |
| 临时数据/小表探查 | TextFile | 可视化排查方便、无需schema约束 |
| 存量MR作业链路 | SequenceFile | 仅为了兼容历史任务,不推荐新建 |
4.4 混合使用的实际例子
很多团队会形成一种误解:整条链路只能统一用一种格式。实际不是这样,我更推荐“分层混合用”。ODS层从MySQL同步过来的原始数据,可以直接落Parquet或ORC,保证分析性能;中间和上游系统做数据交换时,可以单独导一份Avro或TextFile给对方;Hive的DWD/DWS层继续保持列式存储。同一份业务数据,在不同生命周期选择不同格式,完全合理。
Sqoop的负载本身对这种混合模式是友好的,因为它只是一次性的批量导入任务,不同任务写不同目标目录、不同格式,互不干扰。这也就引出下一个问题:既然选型如此重要,实际操作中哪些坑最容易让人白折腾。
5. 从连接失败到Hive表读写错乱:Sqoop实操避坑清单
5.1 MySQL连不上的四类根因
Sqoop使用过程中出现频率最高的异常,大概就是Could not connect to MySQL server。这类问题通常不是Sqoop本身的问题,而是JDBC连接链路的问题,按优先级排查四类原因:
第一,驱动jar包缺失。Sqoop需要mysql-connector-java类库才能连接MySQL,很多人忽略把jar放进/usr/lib/sqoop/lib或~/.sqoop/lib目录,导致连接报错“No suitable driver”。这个坑的排查方式很简单,sqoop version跑一下,确认Driver类能被加载,再往下走。
第二,连接串参数不达标。MySQL 8.x默认认证插件是caching_sha2_password,老驱动容易报认证失败;同时数据库连接串里缺少useSSL=false、serverTimezone=Asia/Shanghai、characterEncoding=utf8等参数时,也会出现奇怪的握手错误或时区异常。小技巧:连接串里加上allowPublicKeyRetrieval=true能解决一部分公钥检索失败的问题。
第三,网络连通性。MySQL所在机器绑定了bind-address=127.0.0.1时外部无法连接,或者目标端口在防火墙里没放行。用telnet测一下3306端口是最快的判断方式。
第四,账号权限。同步账号需要有SELECT权限,如果用到--query这种自由SQL,还要确保账号对相关库表有读取权限,否则导入跑到一半才会报权限异常。这类问题看起来小,但实际定位起来最耗时间,建议提前把所有配置参数模板化,新环境直接套用。
5.2 格式与Hive表映射的错位问题
选了某个格式导入之后,紧接着要面对的是“Hive怎么建表才能正确读它”。这个环节的坑非常集中。
TextFile格式最常见的是分隔符不一致。Sqoop导入时用了逗号或制表符,Hive建表时也要使用完全相同的分隔符,否则字段错位是必然的。更稳妥的方式是统一用\u0001,这是Hive的默认分隔符,两边天然对齐。Avro格式导入后,目录下会生成一个.avscschema文件,建Hive表时要么用CREATE EXTERNAL TABLE ... STORED AS AVRO并指定TBLPROPERTIES('avro.schema.url'='...'),要么直接借助sqoop create-hive-table生成。工作流里最方便的做法是用HCatalog方式同步建表,避免手工维护schema。Parquet格式如果Sqoop版本过旧,导出的文件有时候无法被当前的Hive正确识别,尤其注意版本兼容,Sqoop至少升到1.4.7以上再评估。ORC通过--as-orcfile导入时,Hive表的存储格式必须写成STORED AS ORC,不要试图用TextFile建表再load,读出来往往是null或者乱码。
5.3 小文件、数据倾斜与压缩编码决策
Sqoop导入时最典型的三连坑:小文件过多、数据倾斜、压缩编码选错。它们常常是叠加出现的。
--num-mappers设太大,或者--split-by选了分布极不均匀的字段,会产生大量极小的part文件。比如--split-by选了一个只有几十个不同值的状态字段,而mapper数量设成50,最终跑完可能只有不到10个文件有数据,剩下全是空文件,HDFS上到处是1KB级别的小文件。改进方式是优先选择主键、自增ID这类分布均匀的字段来split,或者对无主键的表用--query里的顺序查询来控制切分方式。
压缩编码的选择也要和格式配合。TextFile + gzip的“不可split”问题前面已经强调过,Sqoop导入任务本身可能没感觉,但下游读取时并行度会被卡死。如果是Parquet或ORC,压缩编码选snappy或zlib问题都不大,注意Hive表属性里的parquet.compression或orc.compress要与Sqoop写出的实际codec一致,否则部分引擎读取时会出现解压异常或统计信息失配。
5.4 再补充两个容易踩的细节
第一个是目标目录的清理机制。Sqoop导入默认要求目标目录不存在,重跑任务时经常报“Target directory already exists”,所以脚本里要么带--delete-target-dir,要么在导入前主动清理目标目录。这个参数加上之后风险很低,建议直接固化在模板里。
第二个是字符集问题。MySQL端数据是utf8,但Sqoop的JDBC连接串里忘了带characterEncoding=utf8,导出的文本可能出现中文乱码,尤其在TextFile格式下最明显。Avro、Parquet这些二进制格式由于有schema记录,通常能正常保留字符编码信息,但也不排除个别字段出现内部异常。统一在连接串模板里加上编码参数,是最省事的做法。
6. 选型思维不止作用于文件格式:Sqoop与周边生态的落地组合
6.1 Sqoop导出和导入是两套逻辑,其中导出默认是文本
Sqoop不只用来导入,反向导出也经常用到,比如把HDFS上的结果集同步回MySQL供报表系统使用。导出的默认行为同样是文本解析,通过--export-dir指定源目录,Sqoop按行读取数据再写入数据库表。
这里的格式选型逻辑会更简单一点:因为最终写入目标是关系型数据库的行结构,所以源文件一般用TextFile就足够了,关键在于--fields-terminated-by要与Sqoop export的参数对齐。如果源文件是Parquet或ORC,Sqoop导出前需要确保引擎能读取对应格式,实际上很多版本对列式格式的export支持并不完善,处理起来更麻烦。所以在一个完整的数据集成平台里,建议形成一条“导入/导出格式按方向分别设定”的规范,不要一刀切用同一种格式应对所有场景。
6.2 Sqoop同步HBase时的格式思路
有一些场景会把MySQL数据同步到HBase,而不是HDFS上的表。Sqoop支持通过--hbase-table、--column-family、--hbase-row-key直接写入HBase表,例如:
sqoop import \ --connect jdbc:mysql://127.0.0.1:3306/dw \ --username reader --password readpass \ --table orders \ --hbase-table orders \ --column-family cf \ --hbase-row-key order_idHBase底层是KV存储,没有文件格式可选择,但思维模式是一样的:导入之前先想清楚下游访问模型。HBase适合基于rowkey的点查和范围扫描,不适合即席分析,所以要不要把数据从MySQL同步到HBase,取决于业务查询是否依赖rowkey模型,而不是“HBase听起来更分布式”。写HBase时也要关注--hbase-row-key是否唯一、批量写入对region split的压力、以及数据一致性校验策略。
6.3 在更现代的数据集成链路里,格式选型仍然是第一道关卡
这几年新出的数据集成工具不少,从DataX到SeaTunnel、从Flink CDC到各种数据湖方案,都试图替代Sqoop的一部分工作。但无论工具怎么换代,从关系型数据库向HDFS/数据湖同步数据时,“落盘格式”始终是第一道关卡。新工具普遍默认Parquet或ORC写入,恰恰说明了这个选择有多重要。
这个逻辑和消息队列选型很像:Kafka、RabbitMQ、RocketMQ没有绝对的好坏之分,只有吞吐、延迟、可靠性语义与业务场景是否匹配的问题。文件格式选型也一样——五个格式不是五个等级,而是五个不同的适用面。Sqoop的老化不影响这套决策模型的复用,甚至到了更现代的数据集成平台上,同样的决策方法论可以直接平移。
我个人的体会是:数据链路里最难改的不是脚本参数,而是存储模型。Sqoop任务里一行--as-parquetfile几乎没有成本,但它决定了这张表未来两年的查询性能、扩展方式和运维体验。刚开始做数仓的时候我也习惯用默认格式,多踩几次坑之后才学会在第一次建同步任务时就问自己三个问题:谁在读取这批数据、怎么读、读多频繁。把这几个问题回答清楚,格式选型自然就有答案了。