背景

在使用ftp下载插件时,发现进行本地执行时可以正常,但当选择了远程执行并指定了远程服务器后发现出现了错误:从 FTP:User cannot log in. 获取文件时发生错误。根据错误信息可以判断是因为ftp登录不上的原因,至于具体的原因无法定位,为了一探究竟,于是便萌生了调试远程作业的想法,顺便深入了解一下了解kettle运行原理以及源码学习。

思路

carte服务器实际上就是一个web server,该web server 是基于 Jetty 这个嵌入式的开源 servlet 容器。这个web server主要是提供转换运行的环境,另外一个重要的功能通过提供servlet来在客户端、主服务器和从属服务器之间进行通讯和控制。主服务器和从属 服务器之间是通过httpClient来进行通讯的,通讯时传递的数据是xml格式。通过提供的servlet,可以实现启动、停止、暂停转换或者作业、 获得转换或者作业的状态、注册子服务器、获得子服务器的列表等等.
其实思路以及LZ使用的方法很简单:通过java代码在eclipse中启动一个Carte服务器,然后远程执行作业时指定服务器作为载体。

搭建Carte服务启动环境

首先创建一个普通的java project项目,如果没有kettle源码环境的话可以创建maven project,这样直接从中心仓库上面获得jar包以及源码。刚好LZ之前有编译过kettle源码且已 经作为项目导入了eclipse中,所以 源码以及相关kettle的jar包都已经有了。

创建了项目后,需要把相关的jar包加到java bulid path中,下面的jar包也可以从PDI工具的lib目录下获得:

smart kettle运行监控 kettle远程执行作业_kettle

把依赖包加入到项目中后,创建一个类来启动Carte服务:

public class CarteServer {
    publicstaticvoid main(String[] args) throws Exception {
            SlaveServerConfig config =new SlaveServerConfig("192.168.31.43", 7088, true);//ip与端口与通过Carte.bat启动时指定的参数一样
            Carte.runCarte(config);  //通过该静态方法启动carte
        }
    }

开始远程调试

  1. 启动carte服务,建好CarteServer类后,直接debug as --> java application,即可启动carte服务,在控制台可以看到以下信息:
2016/08/11 10:55:55 - Carte - 创建web服务监听器@地址: 192.168.31.43:7088
2016-08-11 10:55:55.912:INFO::jetty-6.1.26
2016-08-11 10:55:55.933:INFO::Started SocketConnector@192.168.31.43:7088
  1. 打开spoon工具,创建一个job,下面的job是从ftp服务器上下载文件:
  2. smart kettle运行监控 kettle远程执行作业_smart kettle运行监控_02

  3. 因为作业用到了FTP下载插件,在源码中对应JobEntryFTP类,打开该类并在execute()方法中打上断点:
  4. smart kettle运行监控 kettle远程执行作业_远程_03

  5. 运行job,选择远程执行,选择上述类CarteServer中启动的服务器(要先在spoon工具中新建一个子服务器):
  6. smart kettle运行监控 kettle远程执行作业_源码_04

  7. 观察断点位置,看到已经进入了调试:
  8. smart kettle运行监控 kettle远程执行作业_kettle_05

大功告成,至于ftp下载插件为什么在远程执行中错误另外说明。

远程执行流程

  1. 用户运行kettle作业并选择“远程执行”,触发org.pentaho.di.job.Job类的sendToSlaveServer方法
  2. 在sendToSlaveServer方法中,首先生成XML格式的作业元数据描述。
  3. 调用SlaveServer的sendXML()方法把这些元数据会被发送到远程的carte服务器。
  4. 服务器端AddJobServlet接收到请求后,进入doGet()方法通过元数据构造出Job实体并把作业保存到JobMap中。
  5. 在sendToSlaveServer方法中,把XML发送到carte服务器后,接着调用SlaveServer的execService()方法进行启动远程的job
  6. 此时服务器端StartJobServlet会接收到请求后,会给job(其实是一个Thread)做一堆初始化工作,最后调用job的start方法进行启动。