简介:面向数据集成与ETL开发人员,自编译的Pentaho Kettle 9.5完整版(pdi-ce-9.5.0.1-261)适用于macOS M1芯片,同时兼容Windows与Linux,解压后配置JDK17即可直接运行,省去自行编译的繁琐过程。包内共1078个文件,总量约387.49MB,其中626个jar构成核心运行库,196个ktr与19个kjb分别对应ETL转换和作业脚本,另有80个xml配置文件、11个bat/sh启动脚本及若干properties、xlsx等资源,可满足从数据抽取到任务调度的常见场景。值得留意的是,9.4起官方大幅压缩安装包体积,因此当前容量并非精简缺失,而是版本自身特性。目前已有2872人学习下载,适合需要免费开源自用版本、或在Apple芯片上搭建Kettle环境的开发者直接取用。
1. 为什么 Mac 上跑数据抽取,我最后选回了 Kettle 9.5
处理数据的人迟早要面对同一个问题:业务方给一张 Excel 或 CSV,数据库在另一台机器上,中间隔着字段对不上、编码不一致、时间格式千奇百怪。手写 Python 脚本当然能解决,但每次换一个数据源就要改一次,维护成本全堆在个人身上。Kettle(PDI)这类开源 ETL 工具存在的意义,就是把“抽取、清洗、加载”固化成可视化流程,让后续维护的人不用扒代码也能看懂。pdi-ce-9.5.0.1-261 是社区版 9.5 的最新补丁包,在 macOS 上装好之后,拖拽组件就能完成从文件到数据库的同步,适合数据工程师、运维和经常跟异构数据打交道的开发。这篇笔记就把我在 Mac 上从部署到跑通第一个作业的过程、参数和翻车点一次说清。
2. 在 macOS 上把 Kettle 9.5 跑起来:Java 环境、目录结构和启动脚本
2.1 下载包里到底有什么
解压 pdi-ce-9.5.0.1-261 之后,你会看到一个标准的 PDI 安装目录,Mac 用户最容易忽略的不是软件本身,而是它依赖的 Java 运行时。目录里值得关注的几项如下表所示:
| 路径/文件 | 作用 | 说明 |
|---|---|---|
| spoon.sh | Linux/macOS 启动脚本 | 命令行启动入口,不要直接双击 |
| Kitchen | 作业调度命令行工具 | 跑 .kjb 作业文件用的 |
| Pan | 转换命令行工具 | 跑 .ktr 转换文件用的 |
| lib/ | 核心 jar 包目录 | 数据库驱动也放这里 |
| plugins/ | 插件目录 | 连接池、大数据插件等 |
| samples/ | 示例文件和示例作业,建议先跑通再动自己的流程 | 很多坑其实有现成解法 |
Mac 上最直观的启动文件是 Spoon.app,但二进制包解压后并不会自动生成那个 app 快捷方式,你实际上要操作的是 spoon.sh。有人习惯用 Finder 双击 .command 文件,但在 9.5 版本里我建议先用终端跑一遍,因为首次启动最容易出问题的地方往往是 Java 环境,终端里能看到完整报错。
2.2 Java 版本:9.5 为什么必须用 JDK 17
Kettle 9.5 官方基线是 Java 17,但很多人机器上装的是 JDK 8 或 11。我见过最典型的报错是启动到一半直接闪退,终端里提示UnsupportedClassVersionError,就是这个原因。Mac 上检查当前 Java 版本:
/usr/libexec/java_home -V java -version如果你有多个 JDK,建议在~/.zshrc里显式指定 9.5 用的那个:
export JAVA_HOME=$(/usr/libexec/java_home -v 17) export PATH=$JAVA_HOME/bin:$PATH设置完之后source ~/.zshrc,再跑一遍java -version确认输出是 17。这里有个细节:Kettle 自带的启动脚本会优先读取系统JAVA_HOME,如果你环境变量没配对,后面所有连接数据库的报错都会让你误以为是驱动问题,实际是 JVM 版本不对。我一般会用java -version和which java两条命令一起确认,避免 PATH 里残留旧版本。
2.3 首次启动:用命令行而不是双击图标
进入解压目录,给启动脚本加执行权限,然后前台启动:
cd ~/pdi-ce-9.5.0.1-261 chmod +x spoon.sh ./spoon.sh首次启动时间会比较长,因为 Kettle 要加载插件和环境,终端会滚动大量日志。卡在某个插件加载超过两分钟属于正常,不要急着 Ctrl+C。启动成功的标志不是终端停止输出,而是弹出 Spoon 主界面。如果你看到Java Runtime Environment相关报错,说明JAVA_HOME还是没生效;如果看到的是No X11 DISPLAY之类的提示,那通常是远程终端会话导致的,本地登录不会出现。
有人习惯用open Spoon.app启动,那个方式在 9.5 上有个问题:它读取的环境变量跟终端不一样,容易造成“终端里能跑、双击没反应”的诡异局面。所以我一直推荐命令行启动,虽然丑,但报错信息全,排查成本低。
2.4 第一件配置:kettle.properties 与默认连接
进入主界面之后,先别急着拖组件。Kettle 有一个全局配置文件~/.kettle/kettle.properties,第一次启动会自动生成。里面可以定义自定义变量,比如:
# 数据库连接统一用变量管理,换环境不改转换 DB_HOST=192.168.1.100 DB_PORT=3306 DB_NAME=etl_demo DB_USER=etl_user DB_PASSWD=Etl@123在转换里引用变量时写${DB_HOST}即可。这个习惯最好从第一个作业就开始养成,否则等流程多了以后,每个转换里都写死 IP,换一次环境就要全局替换,那场面很难看。Kettle 的变量解析在 Spoon 界面里是即时生效的,改完 properties 文件不用重启,但已打开的转换需要重新打开一次才会刷新变量值。
3. 做一个“零代码 ETL”:文件输入到数据落库的完整转换
3.1 转换与作业的区别
Kettle 里有两类对象:转换(.ktr)和作业(.kjb)。转换负责单次数据流处理,从输入到输出,组件之间用跳线(Hop)连接;作业是更高一层的编排单位,可以串多个转换、做条件判断、定时执行。新手最容易犯的错是在一个转换里塞进所有逻辑,导致图形复杂到没法看。我的习惯是:一个转换只做一件事,比如“读取 CSV 并清洗”和“写入数据库”拆成两个转换,再用作业串联。
新建转换的入口在菜单File -> New -> Transformation。创建之后左侧会列出分类组件,输入类里拖一个CSV file input,输出类里拖一个Table output,两者之间连上跳线。到这里界面还很空,但整个 ETL 的数据流骨架已经成型了。
3.2 定义 CSV 输入并预览数据
双击 CSV 输入组件,进入配置面板。这里有几个参数必须填对,否则后面全串味:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| Filename | /Users/xxx/data/订单明细.csv | 绝对路径或用变量 |
| Delimiter | ,或实际分隔符 | 先从文件里看几行再填 |
| Encoding | UTF-8 | Mac 上乱码多数是这里没设 |
| Header row present | 是 | 首行作为字段名 |
| Lazy conversion | 否 | 开启后类型推断延迟,容易踩坑 |
填完后点Preview,Kettle 会读前 100 行并展示字段类型推断结果。这一步值得花时间检查:数字字段有没有被识别成 String、日期字段是不是Timestamp。如果字段类型不对,可以在 CSV 输入的“Fields”页签里手动改Type。我曾遇到过一个订单表,数量字段被识别成 String,后面做求和时结果完全不对,排查了半小时才发现是这个环节类型没指定对。
3.3 字段映射与类型转换的参数陷阱
跳线连接后,表输出组件需要配置目标表结构和字段映射。点表输出旁边的Edit,选择数据库连接,然后点SQL按钮让 Kettle 根据 CSV 字段自动建表。自动建表很方便,但有一个坑:Kettle 建出来的字段长度默认 255,如果你的源数据里有超长文本,入库时会静默截断。解决办法是在建表 SQL 里手动改字段长度,或者用字段选择组件在入库前做一次强制类型转换。
字段映射的检查点在表输出组件的Database fields页签:左边是输入流字段,右边是对应的目标表字段。自动映射偶尔会配错,比如源字段ID映射到了目标表ORDER_ID。手动核对一遍比事后查数据要省事得多。这一节里我一般会加一个Select values组件放在入表之前,专门用来改字段名、删多余列、调整数据类型,保持源字段尽量独立。
3.4 表输出与提交批次大小
表输出组件里有一个容易忽略的参数:Commit size。默认值是 100,意思是每 100 条记录提交一次事务。如果是首次全量灌数,这个值可以调到 1000 或 5000,批量提交能明显提升写入速度;但如果数据本身有脏数据,批次越大,失败时回滚的代价也越大。所以我的做法是:首次灌数用 500,日常增量同步用 100。数据量大的场景还可以在“表输出”设置里勾选Use batch inserts,配合 JDBC URL 里的rewriteBatchedStatements=true,写入性能能翻一倍。
跑通之后,按F9或点击运行按钮,下方Step Metrics面板会显示每个组件的输入/输出行数和耗时。如果输入行数和输出行数差距很大,说明中间有数据被过滤掉了,顺着跳线找过滤条件就行。
4. 表输入、作业调度和内存参数:Kettle 9.5 的高阶配置细节
4.1 表输入不是“执行 SQL”,是数据源抽取
很多人用表输入组件时直接写一条完整 SQL 然后点运行,这样做没错,但忽略了它作为“数据源”的属性。表输入组件里的 SQL 是每次执行都会完整跑一遍的,如果你要抽取的是增量数据,应该在 SQL 里带上参数,比如:
SELECT * FROM order_main WHERE create_time >= ${LAST_RUN_TIME} AND create_time < ${CURRENT_RUN_TIME}LAST_RUN_TIME这类变量可以定义在kettle.properties里,也可以用作业里的Set variables组件动态赋值。参数化之后,同样的转换既能做全量也能做增量,不用维护两份文件。表输入组件还有一个Enable lazy conversion选项,勾选后字段类型不会立刻转换,而是等下游用到时才处理,对大数据量场景能省内存,但前提是你清楚每个字段最终会被谁消费。
4.2 作业里做循环和条件分支
作业(Job)的核心组件是START、转换、成功、失败和跳线。跳线可以带条件,比如:
START -> 转换(抽取订单明细) 成功 -> 转换(写入汇总表) 失败 -> 邮件告警这比在转换里写复杂逻辑清晰得多。我一般会把“发送通知”放在每个重要转换之后,用Simple Evaluation组件判断行数或者状态字段,只有异常时才发邮件,避免告警轰炸。作业的执行日志在~/.kettle/job.log,排查线上跑批问题基本都是从这个文件看起。
4.3 内存参数:Mac 上默认只给 512MB 的后果
Kettle 9.5 的启动脚本默认 JVM 堆内存很保守,尤其是在 Mac 上,跑几个表输入同时开多个输入流,内存就吃紧。现象是转换运行到一半突然卡死,或者整个 Spoon 界面直接退出。这个问题的根源是启动脚本里PENTAHO_DI_JAVA_OPTIONS的默认值偏小。改法是在终端导出环境变量再启动:
export PENTAHO_DI_JAVA_OPTIONS="-Xmx4096m -Xms1024m -XX:MaxPermSize=512m" ./spoon.sh-Xmx是最大堆内存,-Xms是初始堆内存。我一般会按本机物理内存的一半来分配,比如 16GB 内存的机器就给-Xmx6144m。但要注意一个问题:Mac 的spoon.sh在某些版本里会忽略PENTAHO_DI_JAVA_OPTIONS,改用JAVA_TOOL_OPTIONS,所以我写了一个小脚本同时设置两个变量,保证无论哪个被读取都能生效。
4.4 并发数和批量参数的权衡
Kettle 转换默认是单线程串行处理,但每个输入步骤可以设置“并发线程数”。以表输入为例,Settings -> Number of rows in rowset决定了行集缓冲区大小,默认 10000。如果你开启了多线程,这个值太小会导致下游组件频繁等待,太大则可能内存溢出。一个相对稳妥的组合是:
| 参数 | 值 | 适用场景 |
|---|---|---|
| Number of rows in rowset | 10000 | 单线程、中小数据量 |
| Commit size | 1000 | 大批量灌数 |
| 并发线程 | 2-4 | 多数据源聚合时 |
| 表输入 Fetch size | 1000 | 大表查询避免一次性加载 |
这些参数没有标准答案,但方向是明确的:不要把所有参数都拉满,内存是唯一的硬约束。我见过有人在 8GB 内存的 Mac 上把并发开到 8 个,结果界面直接卡死,最后只能kill -9。
5. 避坑指南:macOS 上 Kettle 9.5 的 5 个高频问题
5.1 双击 .command 启动没反应
现象:双击解压目录里的 Spoon 图标或某些自定义 .command 文件,屏幕闪一下就不见了,没有任何报错。原因:Finder 双击启动时不会加载~/.zshrc里配置的JAVA_HOME,而且 macOS Gatekeeper 对没有签名脚本直接拦截。解决:改用终端手动执行:
cd ~/pdi-ce-9.5.0.1-261 source ~/.zshrc ./spoon.sh如果还是没反应,大概率是内存参数配置错误导致 JVM 直接退出,检查前面说的PENTAHO_DI_JAVA_OPTIONS是否有拼写错误。
5.2 连不上 MySQL 8 / MariaDB,报错 Communications link failure
现象:在数据库连接里填了正确的主机、账号、密码,测试连接却报Communications link failure,甚至能看到Access denied字样。原因:Kettle 9.5 自带的 JDBC 驱动是 MySQL Connector/J 5.1.49,这个旧驱动连接 MySQL 8.x 默认认证插件是caching_sha2_password,老驱动不认识这个新插件。解决:去下载 mysql-connector-java 8.x 的 jar 包,放到lib目录,然后删掉旧驱动,或者手动在 JDBC URL 后面加上:
jdbc:mysql://127.0.0.1:3306/etl_demo?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/ShanghaiallowPublicKeyRetrieval=true这个参数非常关键,不加这个,MySQL 8 会拒绝初次连接时的公钥获取请求。
5.3 从 Windows 拿来的 CSV 全是乱码
现象:CSV 输入预览时中文变成锟斤拷或????。原因:Windows 默认用 GBK 编码,而 Mac 上 Kettle 默认按 UTF-8 读取。解决:在 CSV 输入组件的Encoding字段填GBK。这里有个隐藏细节:如果文件有 BOM 头,需要在Fields页签里勾选Ignore first line of file同时确认首行不是字段名。最简单的判断方法是打开终端执行:
xxd -l 3 文件.csv输出开头的字节如果是ef bb bf,那就是 UTF-8 BOM,直接在 Kettle 里正常读取;如果是其他值,就要按 GBK 处理。编码问题最好在源头就解决,不要指望入表后再转换,因为字段内容里混入特殊字符时会引发不可预知的截断。
5.4 作业跑失败了,但是看不到任何报错
现象:通过 Kitchen 跑作业,日志停在某个转换的前面,没有任何异常输出。原因:Kettle 的默认日志级别是Basic,只记录粗粒度信息,很多异常被吞掉了。解决:运行命令时把日志级别调到Debug或Rowlevel:
./kitchen.sh -file=/path/to/job.kjb -level=DebugRowlevel会把每一行的处理情况都打到日志里,排查字段映射错位时非常有用。但要注意生产环境不要长期开这个级别,否则日志文件增长速度会让你怀疑人生。我平时是在本地调试用Debug,确认没问题后改成Basic上调度。
5.5 连接池和插件目录的路径里有空格
现象:Kettle 的插件加载没问题,但访问某些文件时报File not found,路径明明存在。原因:PDI 对路径中的空格支持不完善,特别是在 Mac 的“文稿”目录这种带空格的路径里。解决:规矩一点的方案是把整个 Kettle 安装目录和数据文件放在无空格的路径下,比如/Users/xxx/etl,然后所有引用路径都用绝对路径。不要图省事用~符号,Kettle 对~的解析并不可靠,我在多个版本里都遇到过变量展开失效的情况,直接写完整路径反而更省心。
6. 进阶技巧:把转换封装成 Mac 上的一键任务并落盘日志
日常维护时,我习惯给每个作业建一个.command文件,双击或定时执行都能复用同一套配置。下面是一个我常用的模板:
#!/bin/bash # 一键执行 Kettle 作业并保留完整日志 export JAVA_HOME=$(/usr/libexec/java_home -v 17) export PENTAHO_DI_JAVA_OPTIONS="-Xmx4g -Xms1g" export KETTLE_HOME=~/pdi-ce-9.5.0.1-261 LOG_DIR=~/logs/kettle mkdir -p "$LOG_DIR" TIMESTAMP=$(date +%Y%m%d_%H%M%S) "$KETTLE_HOME/kitchen.sh" \ -file="$KETTLE_HOME/jobs/daily_sync.kjb" \ -level=Basic \ -logfile="$LOG_DIR/daily_sync_$TIMESTAMP.log" \ -param:DB_HOST=127.0.0.1 \ -param:LAST_RUN_TIME=$(date -v-1d +%Y-%m-%d)这段脚本要做的事很简单:固定 JDK 17 和内存参数,指定作业文件,日志带时间戳落盘,同时传入作业需要的外部参数。-param:是 Kitchen 的参数传递入口,作业内部通过${DB_HOST}、${LAST_RUN_TIME}引用,这样同一个作业文件可以同时服务于手动跑批和 crontab 定时任务,不用各写一套配置。
Crontab 调用时有一个注意点:cron 环境不会加载用户 Shell 配置,所以脚本里三行export必须写全,尤其是JAVA_HOME,否则定时任务报了错你却不知道去哪看原因。我把这个脚本存为run_daily.command之后,每次双击运行就会在后台执行并生成带日期的日志文件,排查问题时直接 open~/logs/kettle目录找到对应时间段的日志即可。从那以后我每次新建转换都要先确认三件事:JDK 版本、内存参数、日志落盘路径,三者都确认无误才敢往下走流程,这个习惯帮我省掉了至少一半的排障时间,希望也能帮到你。
本文还有配套的精品资源,点击获取