
1. 先说典型故障现场Kettle在麒麟系统上的“首秀”翻车记录我是怎么碰上这个坑的去年底接了一个国产化环境的数据集成项目服务器用的是鲲鹏920处理器装的是银河麒麟V10aarch64版本。需求很简单把业务库的数据按天抽取到分析库技术选型原本是Kettle因为团队一直在用版本也比较熟。结果一上来就卡在“安装”这一关连图形界面都没看到。当时的操作路径是这样的先从官网下载了pdi-ce-9.4.0.0-343.zip解压到/opt/data-integration用java -version确认了OpenJDK 1.8能正常跑接着执行./spoon.sh。屏幕上没有弹出任何窗口终端直接给出了一段让人头皮发麻的提示Unable to load SWT libraries: could not load SWT library. Check SWT_SWTZLIB_PATH, SWT_LIBRARY_PATH or java.library.path.再换命令行模式试./kitchen.sh -version结果更离谱连脚本本身都没法执行报“No such file or directory”。我一度怀疑是zip包没解压完整但ls -l一看文件都在权限也是-rwxr-xr-x。后来才意识到这个报错不是文件不存在而是脚本里引用的某个动态库或解释器在aarch64架构上根本对不上。如果你也在国产ARM服务器上安装Kettle大概率会遇到下面这几种情况的排列组合典型报错第一反应实际原因No such file or directory在.sh上文件损坏、没执行权限shell脚本或JVM加载的native链接库缺失could not load SWT library图形库配置错误官方包只带了x86_64的SWT本地库Cannot execute binary file下载错了包解压到了Intel二进制文件无法在ARM上运行Error occurred during initialization of VMJDK没装好装了x86的JDK而不是aarch64版本这篇文章就是冲着这些问题来的。我会把从确认系统架构、安装JDK、下载Kettle、修复SWT、配置数据库驱动到最终跑起来定时任务的全过程写清楚尤其会重点解释“为什么在x86上三步就能装好的东西在麒麟上会多出这么多破事”以及每个坑背后对应的系统原理。2. 动手之前的底牌摸排CPU架构、系统版本与JDK选型2.1 先确认你真的处于aarch64环境下在开始折腾Kettle之前先把系统底细弄清楚。执行下面这几条命令uname -m lscpu | grep Architecture如果输出结果是aarch64或者ARM64那么恭喜你后面所有和x86_64强相关的二进制包都会出问题。如果输出是x86_64那标题里的“架构不兼容”基本和你无关可以直接跳到安装依赖那一步。这里有个细节容易让人迷惑aarch64和arm64在Linux内核里通常是同一个东西。aarch64是ARM公司官方叫法arm64是Linux内核选用的名称所以很多软件文档里混着写。但Kettle官方发行包可不管这个它只提供常见的x86_64、ppc64le、s390x等目录部分较新版本会带上aarch64但历史上大量稳定版本没有。我建议你在执行下面所有操作之前先把uname -m的结果记录下来。后续排查脚本报错时经常会用到这个值去和spoon.sh里的case分支做比对。2.2 系统版本影响软件源的可用性麒麟系统分好几个大版本最常见的是银河麒麟V10和统信UOS 20二者的软件包管理都兼容CentOS/RHEL的风格。比如银河麒麟V10可以用yum安装软件统信UOS也能用apt或者yum取决于桌面版还是服务器版。先看一下系统信息cat /etc/os-release正常情况下能看到NAMEKylin或者nameuos这样的标识。这一步不是只看个热闹后续安装依赖包时要依赖系统的软件源。如果源没有配置好或者默认源指向的是x86_64的仓库那么yum install的时候要么404要么下载的是Intel平台的rpm装上之后运行照样崩。我习惯的做法是先确认源是否工作yum repolist如果发现源有问题优先修改/etc/yum.repos.d/下的配置文件换成系统对应的ARM源。热搜词里出现的“centos 7.9 aarch64 yum”其实就是很多人在ARM服务器上装了CentOS兼容环境后又缺包跑过来找源这个思路在麒麟上同样适用。2.3 JDK选型别用Oracle别用JRE更别用太新的版本Kettle本身是Java程序理论上只要JVM能跑它就能跑。但这里有几个坑叠加在一起很容易让人混淆Oracle JDK 8官方只提供x86_64和sparcv9等版本没有Linux aarch64安装包。CentOS/麒麟源里自带的java-1.8.0-openjdk是ARM版本可以直接用。Kettle 9.x对Java版本要求是8或11如果你的系统默认的Java 17或21很可能在启动时报UnsupportedClassVersionError。我推荐的组合是银河麒麟V10 OpenJDK 1.8 Kettle 9.4。下面是安装与配置命令sudo yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel # 找到实际的JDK路径 ls -d /usr/lib/jvm/java-1.8.0-openjdk* export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PATH$JAVA_HOME/bin:$PATH如果系统里同时有多个JDK建议显式指定PENTAHO_JAVA_HOME避免Kettle脚本自己乱猜export PENTAHO_JAVA_HOME$JAVA_HOME有人喜欢用绝对路径写死我这里更推荐把环境变量追加到/etc/profile或者~/.bashrc因为后面配置定时任务、重启系统时环境变量不会自动带过去到时候又是一堆“找不到Java”的麻烦。3. 下载和解压Kettle版本选择与目录布局的技巧3.1 版本选择为什么我不建议追新Kettle的版本演进很快社区版CE从9.x一路更新到10.x以上。但很多老项目还停留在8.3或9.3。面对aarch64架构我反而建议选择更成熟的9.x系列理由有这么几条9.x对JDK 8的兼容性最稳定而JDK 8在ARM上的OpenJDK实现最成熟。10.x及以上版本可能需要JDK 11或17虽然也能跑但SWT和GTK的兼容性调试成本会变高。社区里针对aarch64的魔改方案主要集中在8.x和9.x上遇到问题找资料更容易。我用的版本是pdi-ce-9.4.0.0-343.zip它对应Kettle 9.4。如果你从官网的Get Started页下载选Linux版即可。下载后注意文件名末尾是-343这是构建号不同构建号里面的SWT结构会有细微差别建议固定一个版本别来回换。3.2 解压目录不要埋中文和空格解压目录的选择看似无关紧要但实际影响脚本解析。Kettle的spoon.sh、kitchen.sh内部会拼接各种相对路径如果目录里含有空格或者中文某些老版本会直接找不到资源文件。可以放在/opt下面unzip pdi-ce-9.4.0.0-343.zip -d /opt/ mv /opt/data-integration /opt/kettle94这里我额外提一句把目录从>#!/bin/sh在麒麟系统上/bin/sh必然存在所以一般不在这儿翻车。真正容易忽略的是脚本里用到的外部命令比如uname、find、awk等。只要这些系统命令可用shell脚本大概率能执行。但脚本里可能会判断架构后去加载libswt/os/linux/$(arch)目录下的动态库此时目录不存在动态库加载失败于是抛出一堆“XX is not found”的异常最终显示成“No such file or directory”。这类问题不是Kettle独有任何用C或C编写的native库都会有类似行为。对应的排查方法是file /opt/kettle94/spoon.sh ldd /opt/kettle94/libswt/os/linux/x86_64/libswt-gtk-*.so如果libswt-gtk-*.so是Intel的ELF格式而当前系统是ARM那么即使文件名对得上它也永远无法被加载。4.2 手动指定JAVA_HOME后为什么还是报错有不少人按照网上的教程设置了PENTAHO_JAVA_HOME但依然报错。原因是Kettle脚本中有很多种逻辑有的版本读JAVA_HOME有的读PENTAHO_JAVA_HOME还有的读JDK_HOME。部分版本甚至会在/usr/lib/jvm里自动搜索搜到一个x86的JDK就认为完成了任务。最稳妥的办法是直接把环境变量全部声明清楚export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PENTAHO_JAVA_HOME$JAVA_HOME export JDK_HOME$JAVA_HOME export KETTLE_HOME/opt/kettle94设置完成后先跑一下./kitchen.sh -version确认命令行模式可用。如果这个通了你的ETL任务已经可以跑了GUI就看你是否愿意继续折腾。5. 图形界面的SWT库问题替换还是彻底放弃5.1 为什么SWT是跨平台Kettle最大的坎Kettle的图形界面Spoon是用SWT写的。SWT和AWT/Swing不同它不依赖JVM内置的图形组件而是通过JNI调用操作系统的原生窗口控件。在Linux上SWT底层需要GTK库同时还需要针对不同CPU架构编译的.so文件。官方Kettle Linux包自带的是x86_64的SWT库所以在aarch64上加载必然失败。具体报错形式可能有两种直接提示could not load SWT library提示undefined symbol或者libgtk-x11-2.0.so.0: cannot open shared object file。5.2 从Eclipse仓库获取aarch64版SWTSWT是Eclipse的开源组件Eclipse官方Maven仓库里有对应aarch64的SWT jar包。你可以去repo.eclipse.org搜索org.eclipse.swt.gtk.linux.aarch64下载和你当前Kettle版本匹配的SWT包然后替换进Kettle目录。具体步骤备份原SWT jarcd /opt/kettle94/lib ls -l libswt*.jar cp libswt*.jar /root/backup/下载aarch64版SWT jar后放到/opt/kettle94/lib/里覆盖注意先确认原Kettle里究竟用的是哪个jar不同版本可能叫libswt.jar或org.eclipse.swt.gtk.linux.x86_64_3.114.0.jar。创建aarch64目录并复制本地库mkdir -p /opt/kettle94/libswt/os/linux/aarch64 cp ~/swt-libs-aarch64/* /opt/kettle94/libswt/os/linux/aarch64/设置环境变量让JVM能找到新目录export SWT_LIBRARY_PATH/opt/kettle94/libswt/os/linux/aarch64这个方案在理论上很完美但实际会遇到两个问题一是Kettle 9.x里SWT的版本可能和Eclipse仓库的SWT版本之间存在差异造成API不兼容二是SWT本地库除了libswt-gtk.so还依赖GTK的版本如果在服务器上没装libgtk-3.so.0替换jar后依旧报错。所以这个方案更适合有图形界面的桌面系统纯服务器环境我建议放弃GUI直接走命令行。5.3 命令行模式才是aarch64的最优解我在这次项目中最后没有换SWT库因为客户那边只有命令行需求最终部署的是kitchen.sh。它的启动只依赖Java进程不碰GTK。只要把作业文件.kjb和转换文件.ktr准备就绪就能稳定跑。至于日常调试我是在自己x86笔记本上做好再上传到麒麟服务器上执行。如果你的业务场景必须在麒麟服务器上打开Spoon图形界面那至少需要确认系统里有GTK图形库并且已经安装了中文字体、桌面环境。在纯文本跑批的服务器上打开GUI本身就是一件反模式的事。6. 数据库驱动与JNDI配置架构之外的另一批雷6.1 驱动jar包放错位置等于白放Kettle 9.x的驱动加载方式和传统Java项目不太一样。它会在启动时扫描lib/目录下的所有jar包也会扫描libext/下的可选扩展。如果我们把MySQL、达梦、人大金仓的驱动直接丢到lib/下面通常能被识别。但要注意一点lib/下不允许出现同名但不同版本的jar否则会被Kettle的类加载器随机选中一个导致莫名的No suitable driver。驱动jar的正确放置路径根据使用方式分两类通用驱动复制到/opt/kettle94/lib/仅在单个作业中使用的驱动通过“Set Variables”设置PLUGIN_CLASS或使用Kettle的Driver参数指定建议在数据库连接中勾选“自定义驱动类”并显式填入类名避免自动探测不准。例如MySQL 8填com.mysql.cj.jdbc.Driver达梦填dm.jdbc.driver.DmDriver人大金仓填com.kingbase8.Driver。6.2 JNDI配置的“路径陷阱”搜索热词里有“kettle jndi配置”说明很多人卡在这里。对于KettleJNDI数据源的核心配置文件是simple-jndi/jdbc.properties。问题在于这个配置文件的读取位置是基于KETTLE_HOME环境的。如果你没有设置KETTLE_HOME默认会使用当前用户目录下的.kettle/simple-jndi/jdbc.properties。我在麒麟系统上犯过的错误是把jdbc.properties写到了Kettle安装目录下但作业是通过crontab以root用户运行的Kettle根本找不到于是所有JNDI连接全部报错。正确的做法是mkdir -p ~/.kettle/simple-jndi vim ~/.kettle/simple-jndi/jdbc.properties内容示例ds_etl/typejavax.sql.DataSource ds_etl/drivercom.mysql.cj.jdbc.Driver ds_etl/urljdbc:mysql://192.168.1.50:3306/etldb?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/Shanghai ds_etl/useretluser ds_etl/passwordEtl2024在数据库连接界面选择“JNDI数据源”并填入ds_etl不要填主机地址否则Kettle会忽略JNDI配置。6.3 国产数据库驱动在ARM上更容易踩的坑很多国产数据库厂商提供的JDBC驱动是纯Java实现比如达梦、人大金仓、GBase等理论上Java能跑它们就能跑。但部分版本为了性能在驱动里通过JNI调用了本地加密库或通信库这些本地库往往只提供x86_64版本。如果你连接时遇到libcrypto.so.1.1: cannot open shared object file这类报错十有八九是驱动自带的native库依赖了Intel的libcrypto。解决办法有两种换用该数据库的“纯JDBC”无本地库版本驱动在系统里安装ARM版本的OpenSSL并替换驱动内置的库路径。推荐优先找纯JDBC版本省心省力。7. 把Kettle变成可靠的定时任务环境变量与内存控制7.1 包装脚本要写全别指望crontab自动带环境在Kettle里跑作业通常的做法是写一个shell包装脚本由crontab每分钟或每天调用。但你必须知道crontab默认的环境变量非常少可能连JAVA_HOME都没有。如果直接在crontab里写/opt/kettle94/kitchen.sh -file...大概率会报“Java not found”。我用的包装脚本run_etl_daily.sh内容如下#!/bin/bash export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PENTAHO_JAVA_HOME$JAVA_HOME export PATH$JAVA_HOME/bin:$PATH export KETTLE_HOME/root/.kettle WORK_DIR/opt/kettle94 LOG_DIR/var/log/etl DATE$(date %Y%m%d%H%M) mkdir -p $LOG_DIR cd $WORK_DIR ./kitchen.sh -file$WORK_DIR/jobs/daily_import.kjb \ -levelBasic \ -logfile$LOG_DIR/daily_import_$DATE.log \ -param:DATE${DATE}这份脚本里需要注意-logfile和-param之间的引号。Kettle参数值如果包含空格或特殊字符很容易被shell切碎。稳妥做法是每个参数都单独加双引号。7.2 内存参数不能照抄x86的默认值Kettle 9.4的spoon.sh和kitchen.sh脚本末尾通常会有一行PENTAHO_DI_JAVA_OPTIONS-Xms1024m -Xmx2048m在ARM服务器上默认堆内存往往偏保守数据量一大就OutOfMemoryError。我建议根据服务器物理内存动态调整比如128G物理机给4~8G堆内存即可。修改时直接编辑脚本里的这行PENTAHO_DI_JAVA_OPTIONS-Xms2g -Xmx8g -XX:UseG1GC -Dfile.encodingUTF-8ARM处理器在高并发场景下G1GC的停顿表现通常优于CMS。不建议照抄x86上的低延迟参数组合因为不同处理器的内存带宽特性不一样。7.3 防止作业重复并发执行Kettle作业没有内置的分布式锁如果上次任务没跑完下次crontab触发会同时启动两个实例导致数据重复或数据库锁冲突。最简单的办法是用flock命令锁住执行进程exec 9/var/lock/etl_daily.lock if ! flock -n 9; then echo $(date) Another ETL instance is running, exit. $LOG_DIR/skip.log exit 0 fi把这段放在包装脚本的kitchen.sh执行之前能避免绝大多数并发灾难。这个技巧对于在aarch64上部署的Kettle同样适用与架构无关。8. 中文字体与系统级异常安装完跑得好才算好8.1 不要忽视“豆腐块”字体问题热搜词里有很多“麒麟系统字体下载”“新罗马字体”“仿宋”相关的问题说明字体是国产化系统上使用Java应用的高频痛点。Kettle如果用来生成Excel、PDF报表或者展示图表缺少中文字体会导致输出文件中出现方块。在麒麟系统上安装中文字体的命令sudo yum install -y wqy-zenhei-fonts wqy-microhei-fonts sudo fc-cache -fv如果客户要求特定字体比如仿宋GB2312或方正小标宋可以手动下载ttf文件放到/usr/share/fonts/下然后更新字体缓存。注意Kettle的JVM不一定实时感知新安装的字体如果还是乱码需要重启Java进程或者在PENTAHO_DI_JAVA_OPTIONS里加一行-Djava.awt.headlesstrue仅当不需要GUI时。8.2 “麒麟开机后黑屏”这类问题的快速分流“麒麟系统开机后黑屏”也出现在搜索热词里虽然不完全属于Kettle安装范畴但如果你是在桌面版麒麟系统里折腾Kettle黑屏会导致你的操作界面全部丢失。通常原因有三类显卡驱动冲突、某个rpm包升级后破坏了桌面依赖、磁盘空间满了导致图形服务起不来。排查思路很简单journalctl -xe -u lightdm.service df -h free -m如果只是Kettle安装过程中因为内存不足导致桌面崩溃重启后用命令行模式跑Kettle就是最好的出路。我在一次项目中就遇到过由于解压Kettle并同时打开Spoon8G内存的机器直接卡死桌面黑屏最后只能重启机器把图形界面暂时禁用改用kitchen.sh调度。8.3 做一个最终版的“架构自检”脚本为了方便以后在同类服务器上部署建议把所有环境检查写成一个脚本遇到不同的机器可以快速验证#!/bin/bash echo uname uname -m echo OS cat /etc/os-release | head -2 echo Java java -version 21 echo Kettle SWT ls /opt/kettle94/libswt/os/linux/ 2/dev/null echo GTK ldconfig -p | grep gtk | head -5把这个脚本丢到服务器上跑一圈能提前暴露大部分环境缺陷比如缺少libgtk-3.so.0、JDK不是aarch64等。遇到问题再去针对性安装比直接跑Kettle然后看一堆堆栈要高效得多。9. 我对麒麟系统下Kettle部署的一点后续心得在国产化ARM服务器上部署Kettle其实没那么玄乎核心就是“别和架构硬刚”。官方没有aarch64版本的SWT那就绕开GUI官方脚本里的架构检测逻辑不完善那就手动指定环境变量并验证JDK路径数据库驱动有native依赖那就换成纯JDBC版本。这些思路同样适用于其他Java系工具比如DBeaver、DataX等应用在ARM平台上的适配。如果后面再上手类似项目我给自己定的排查顺序是这样的先确认uname -m和JDK架构再用kitchen.sh验证命令行能不能跑最后才考虑GUI。凡是需要在生产环境长期运行的ETL任务一律写成带日志、带锁、带内存限制的shell脚本交给crontab管理。这样即使界面打不开数据工单也不会耽搁。记住了遇到No such file or directory先别怀疑文件缺失用file和ldd看二进制兼容性遇到SWT报错先想清楚自己到底需不需要图形界面遇到字体乱码先装字体并清缓存遇到定时任务找不到Java就先导出JAVA_HOME。把这些细节都做对了aarch64上的Kettle一样可以当生产工具用。