1. 为什么还要在 Linux 上折腾 FastExport 这种"老古董"
FastExport 是 Teradata 生态里专门用来做大批量数据导出的并行工具,走的是 FastLoad 那条底层通道,跟普通的 BTEQ 导出完全不是一个量级。BTEQ 导出几千万行数据,你可能得泡杯茶等半小时;FastExport 在同样硬件上,几分钟就能把数据落到文件里,差距就是这么直接。它最适合的场景是:数据仓库里几百 GB 的事实表要定期卸到文件系统,再喂给下游的 Hadoop、对象存储或者别的分析平台。
但问题也很现实——FastExport 的版本迭代早就停了,1.7 这个版本号在官方文档里都属于"考古级"。你在 Linux 上装它,官方不会给你一个 yum 源或者 apt 包,全靠手动解压、配环境变量、调库依赖。我前后在三四个不同发行版上装过这东西,踩的坑足够写一篇避雷指南。这篇就把整个流程拆开讲清楚:从包结构、依赖判断、环境变量配置,到实际跑通一个导出任务,再到常见报错怎么排查。
适合谁看?如果你手头有一台 Linux 服务器,需要跟 Teradata 打交道,又不想被 BTEQ 的龟速折磨,那这篇就是给你准备的。哪怕你之前没碰过 Teradata 客户端工具,跟着走也能装起来。我会尽量把"为什么这么做"讲透,而不是甩一堆命令让你照抄。
2. 装之前先搞清楚 FastExport 到底由哪些东西组成
2.1 安装包里的目录结构长什么样
FastExport 1.7 的 Linux 安装包通常是一个压缩归档,解压后你会看到类似这样的结构:
fastexport/ ├── bin/ # 可执行文件,核心是 fexp 和 fexp主程序 ├── lib/ # 依赖的共享库,比如 libfexp.so、libcli.so ├── msg/ # 错误消息文件,报错时靠它翻译成人话 ├── samples/ # 示例脚本,新手照着改最快 └── scripts/ # 一些辅助脚本,比如环境初始化这里有个关键点:FastExport 不是单个二进制文件就能跑的。它依赖 Teradata 的 CLI(Call Level Interface)库,也就是libcli.so这一套。如果你机器上已经装了 Teradata 的其他客户端(比如 BTEQ、TPT),那 CLI 库可能已经存在,你只需要把 FastExport 自己的库路径加进去就行。如果啥都没有,那就得先把 CLI 运行时装好,否则fexp一启动就报 "cannot open shared object file"。
2.2 版本匹配这件事比你想的重要
FastExport 1.7 对应的 CLI 库版本、TTU(Teradata Tools and Utilities)版本是有对应关系的。我见过有人拿一个很新的 CLI 库去配老版 FastExport,结果连会话都建不起来,报错信息还特别含糊,就一句 "CLI error"。后来查了半天才发现是版本不兼容。
判断方法很简单:看安装包里有没有README或者release notes,里面会写明依赖的 CLI 最低版本。如果没有,那就用ldd命令看fexp依赖哪些库:
ldd /opt/teradata/client/17.00/bin/fexp输出里会列出所有.so文件。你对照一下系统里现有的库版本,差太多就得考虑换包。经验之谈:宁可 FastExport 版本略低于 CLI 版本,也不要反过来。老工具配新库,通常还能跑;新工具配老库,基本必挂。
2.3 系统层面的前置条件
Linux 发行版这块,FastExport 1.7 对 glibc 版本有要求。太新的发行版(比如某些滚动更新的)可能因为 glibc 太新导致老二进制跑不起来,报GLIBC_2.xx not found。这种情况要么找兼容包,要么用容器跑一个老一点的 base image。
另外确认几件事:
- 磁盘空间:FastExport 本身不大,几十 MB,但导出数据可能很大,
/tmp和输出目录要留够。 - 文件句柄数:并行导出会开很多文件句柄,
ulimit -n建议调到 65535。 - 网络连通性:能 telnet 通 Teradata 的 1025 端口(数据库服务端口),这是最基本的。
提示:装之前先用
uname -a和cat /etc/os-release把系统信息记下来,后面排查问题时这是第一手资料。
3. 手把手完成 FastExport 1.7 的安装与配置
3.1 解压与目录规划
我习惯把 Teradata 客户端统一放在/opt/teradata/client/下面,版本号单独建目录,方便以后多版本共存:
sudo mkdir -p /opt/teradata/client/17.00 sudo tar -zxvf fastexport_1.7_linux.tar.gz -C /opt/teradata/client/17.00/解压完检查一下权限,bin目录下的可执行文件必须有x权限:
chmod -R 755 /opt/teradata/client/17.00/fastexport/bin这一步看着简单,但我真遇到过解压后权限丢失的情况,fexp死活执行不了,查了半天才发现是权限问题。所以养成习惯,解压后先ls -l看一眼。
3.2 环境变量的正确配法
FastExport 靠几个环境变量找库和消息文件,配错了就是各种 "not found"。核心是这几个:
| 环境变量 | 作用 | 示例值 |
|---|---|---|
PATH | 找到 fexp 可执行文件 | /opt/teradata/client/17.00/fastexport/bin |
LD_LIBRARY_PATH | 找到共享库 | /opt/teradata/client/17.00/fastexport/lib |
NLSPATH | 找到消息文件 | /opt/teradata/client/17.00/fastexport/msg/%N |
COPLIB | 字符集相关库路径 | /opt/teradata/client/17.00/fastexport/lib |
写进/etc/profile.d/teradata.sh里,这样所有用户登录都能生效:
export PATH=/opt/teradata/client/17.00/fastexport/bin:$PATH export LD_LIBRARY_PATH=/opt/teradata/client/17.00/fastexport/lib:$LD_LIBRARY_PATH export NLSPATH=/opt/teradata/client/17.00/fastexport/msg/%N export COPLIB=/opt/teradata/client/17.00/fastexport/lib配完source /etc/profile.d/teradata.sh,然后验证:
which fexp fexp -v如果fexp -v能打印出版本号,说明基本环境通了。注意LD_LIBRARY_PATH的顺序,如果你系统里已经有别的 Teradata 库,把 FastExport 的路径放前面,避免加载到旧版本。
3.3 验证 CLI 库依赖是否满足
前面说过 FastExport 依赖 CLI 库。用ldd再确认一遍:
ldd $(which fexp) | grep -i "not found"如果输出为空,恭喜,依赖全齐。如果有 "not found",就得把缺失的库补上。常见的缺失是libcli.so和libcops.so,这两个通常在 Teradata 的 CLI 运行时包里。找到对应版本的.so文件,拷到lib目录或者加到LD_LIBRARY_PATH里。
注意:不要随便从网上下一个
libcli.so就塞进去,版本不匹配会导致运行时崩溃,而且报错信息极难定位。优先用同一套安装介质里的库。
3.4 配置 Teradata 连接信息
FastExport 连接数据库靠的是fexp脚本里的登录信息,或者用.tdconnect之类的配置文件。最直接的方式是在脚本里写:
.LOGON 数据库地址/用户名,密码;但这样密码明文暴露不安全。更好的做法是用 Teradata 的tdwallet或者环境变量传密码。我一般用环境变量:
export TD_USER=myuser export TD_PASS=mypassword然后在脚本里引用。虽然也不是绝对安全,但至少不会硬编码在文件里。
4. 跑通第一个导出任务:从建脚本到出数据
4.1 写一个最小可用的 FastExport 脚本
FastExport 的脚本语法跟 BTEQ 有点像,但有自己的关键字。下面是一个导出单表的例子:
.LOGON 192.168.1.100/dbc,dbc; DATABASE mydb; .BEGIN EXPORT SESSIONS 4; .EXPORT OUTFILE /data/export/customer_data.txt FORMAT TEXT; SELECT * FROM customer WHERE create_date >= '2024-01-01'; .END EXPORT; .LOGOFF;几个关键点解释一下:
.BEGIN EXPORT SESSIONS 4:开 4 个并行会话。这个数字不是越大越好,一般跟 Teradata 的 AMP 数量挂钩,通常是 AMP 数的 1/4 到 1/2。开太多反而会因为资源争抢变慢。.EXPORT OUTFILE:指定输出文件路径。注意这个路径是数据库服务器端还是客户端取决于配置,FastExport 默认是客户端本地路径。FORMAT TEXT:文本格式,还有FORMAT FASTLOAD等选项,按下游需求选。
4.2 执行脚本并观察输出
fexp < export_customer.sql > fexp.log 2>&1执行过程中,fexp.log里会打印会话建立、数据行数、耗时等信息。重点看几个指标:
- Sessions established:会话数是否跟预期一致。
- Rows exported:导出的行数,跟源表 count 对一下。
- Elapsed time:总耗时。
如果行数对不上,先别急着怀疑工具,检查一下 WHERE 条件是不是把数据过滤掉了,或者字符集问题导致某些行被跳过。
4.3 参数调优的实战经验
FastExport 的性能主要受这几个参数影响:
| 参数 | 作用 | 调优建议 |
|---|---|---|
| SESSIONS | 并行会话数 | 从 4 开始试,逐步加到 8、16,观察耗时曲线 |
| PACK | 每次网络传输的打包行数 | 默认 1000,大行宽可降到 500 |
| BUFFERSIZE | 缓冲区大小 | 默认 64K,可加到 256K |
| TENACITY | 出错重试策略 | 网络不稳时设成TENACITY 5 |
我实测下来,SESSIONS 从 4 加到 8 通常有 30% 左右的提升,但加到 16 之后收益就很小了,甚至因为上下文切换变慢。所以别盲目堆会话数,找到那个拐点就行。
5. 常见报错与排查速查表
装和跑的过程中,报错是家常便饭。我把踩过的坑整理成一张表,遇到问题先对号入座:
| 报错信息 | 可能原因 | 解决方向 |
|---|---|---|
cannot open shared object file | 库路径没配或库缺失 | 检查LD_LIBRARY_PATH,用ldd定位 |
CLI error 2 | 连接信息错误或网络不通 | telnet 测试端口,核对地址用户名 |
GLIBC_2.xx not found | 系统 glibc 版本不匹配 | 换兼容包或用容器 |
No more room in database | 导出目标空间不足 | 清理空间或换输出路径 |
FEXP: fatal error无详细信息 | 消息文件路径错 | 检查NLSPATH配置 |
| 导出中途卡住不动 | 会话死锁或网络抖动 | 加TENACITY,检查数据库锁 |
| 中文乱码 | 字符集不匹配 | 设置COPLIB和会话字符集 |
5.1 一个特别隐蔽的坑:消息文件路径
NLSPATH配错的时候,FastExport 不会直接告诉你"消息文件找不到",而是抛一个没有任何上下文的 "fatal error"。我第一次遇到时完全懵,后来用strace跟踪才发现它在找msg目录下的文件。所以如果报错信息特别含糊,第一反应就是检查NLSPATH。
5.2 权限问题导致的"假死"
有时候fexp启动了,会话也建了,但就是不出数据,日志也不更新。这种情况十有八九是输出目录没写权限。FastExport 在写文件失败时,某些版本不会立即报错,而是默默重试,看起来就像卡住了。解决办法很简单:touch一下输出文件,看能不能创建。
提示:排查任何"卡住"的问题,先看
ps -ef | grep fexp进程状态,再用lsof -p 进程号看它在等什么资源,比瞎猜快得多。
6. 几个让 FastExport 跑得更稳的实操心得
6.1 用 nohup 和日志轮转保护长任务
FastExport 导出大表可能跑几个小时,SSH 一断任务就没了。所以一定要用nohup:
nohup fexp < export.sql > fexp_$(date +%Y%m%d).log 2>&1 &日志按日期命名,方便回溯。如果任务特别长,再加个logrotate规则,避免日志把磁盘撑爆。
6.2 导出前先做小批量验证
别一上来就导全表。先用SAMPLE或者WHERE ROWNUM <= 1000导一小批,确认格式、字符集、字段分隔符都符合下游要求,再放开跑全量。我吃过这个亏——全量导了三个小时,结果下游说分隔符不对,全部重来。
6.3 监控会话资源占用
FastExport 开多个会话时,数据库端的资源消耗要盯着。用 Teradata 的PMON或者dbc.SessionInfo视图看会话状态,避免因为单个任务把数据库拖垮,影响其他业务。生产环境跑之前,最好跟 DBA 打个招呼,约定好会话数上限。
6.4 版本升级的取舍
FastExport 1.7 确实老,但如果你的 Teradata 数据库版本也不新,强行升级客户端反而可能引入兼容问题。我的建议是:只要当前版本能稳定跑通业务,就别轻易动。真要升级,先在测试环境完整验证一遍导出流程,包括字符集、大字段、NULL 值处理这些边界情况。
7. 关于字符集和 NULL 值处理的补充
字符集这块值得单独拎出来说。FastExport 导出时,如果数据库用的是 UTF-8,而客户端COPLIB指向的是别的字符集,中文就会变成问号或者乱码。确认方法是在脚本里显式指定:
.SET SESSION CHARSET UTF8;NULL 值的处理也容易出问题。默认情况下,NULL 在文本格式里可能导出成空字符串,也可能导出成特定标记,取决于FORMAT选项。如果下游系统对 NULL 敏感,最好在 SELECT 里用COALESCE显式转换,别指望 FastExport 的默认行为。
SELECT COALESCE(name, 'N/A'), COALESCE(amount, 0) FROM customer;这样导出来的数据干净,下游不用再做二次清洗。虽然多写几个函数,但省下的排查时间远超这点成本。
8. 最后聊聊这套流程的适用边界
FastExport 适合的是大批量、结构化、定期的导出场景。如果你的需求是实时同步、增量捕获,那它不合适,得看 CDC 或者消息队列那套方案。如果数据量不大,几万行级别,那 BTEQ 甚至普通的 JDBC 查询就够了,没必要上 FastExport 这套重装备。
我在实际项目里的做法是:日常小批量用 BTEQ,月度全量卸数用 FastExport,两者配合。FastExport 的脚本模板化之后,改改表名和日期参数就能复用,维护成本并不高。真正花时间的是第一次装环境和调通流程,一旦跑顺了,后面就是例行公事。
装 FastExport 1.7 这件事,难点不在命令本身,而在那些文档里不写的细节——库版本匹配、消息文件路径、权限和字符集。把这些坑提前填了,剩下的就是体力活。希望这篇能帮你少走点弯路,一次装通。