一、内容提要
与程序员类
似,ETL工程师在日常工作中同样面临开发、调试、部署等环节。
Kettle把开发与调试集中在Spoon中完成,部署主要通过Pan、Kitchen、Carte三者完成。
开发调试时,可通过可视化界面非常直观地了解执行过程所有细节。
一旦Kettle正式部署(一般称之为生产环境),想要了解执行过程就不那么直观了。
大多数情况下,生产环境不会把服务器资源浪费在可视化上,技术服务商总是希望所有计算存储资源都用在响应客户需求上,因此日志成为生产环境中的一个最重要的运行监测手段。通过
日志,我们可以了解程序执行成功与否,可以收集执行时间,也可以定位执行错误。
笔者拟通过三篇文章,让读者了解Kettle日志的基本概念、应用方法以及编程知识。三篇难度逐一增加,K友们可以按需阅读。本文主要介绍
Kettle日志的基本概念,为后续应用与开发打下基础。有些概念可能在使用过程中并不直接接触,但理解后方能掌握Kettle日志内幕。
二、主要概念
1、日志源
日志源就是日志的来源,可以理解为产生日志的对象
。在Kettle中有哪些对象能够产生日志?最典型的肯定是作业与转换,但实际情况远比
这两者复杂。
几乎所有Kettle中的要素都可以产生日志从而成为日志源,主要类型包
括资源库、HTTP(Carte/Servlet)、GUI(Spoon/步骤属性对话框/作业项属性对话框)、元数据(转换元数据/作业元数据)、运行时(转换/作业/步骤/作业项/数据库)等。如果没有编程基础,有些概念可能无法理解,但不影响对日志相关内容的掌握。例如Servlet是一个较老的J2EE服务器端开发技术,可以把Servlet理解为Web服务器端HTTP响应的一个对象,实际上Carte的主要服务都是基于Servlet开发的。
每一个日志源都有名称、编号、日志通道、日志级别、注册时间等基本属性。其中注册时间即为日志源登记到日志注册表的时间。如果没有登记到注册表,此属性为null(空引用)。名称与编号,对判断两个日志源是否相等至关重要。
日志源天生具备父子关系
。例如一个转换日志源是其所有步骤的父亲,一个作业日志源是其所有作业项的父亲。由于父对象唯一,所以存在关联的日志源集合会组成一棵树,多棵树最终会形成日志源森林。日志源的父对象,一般在构造时既已明确。默认情况下,子日志源沿用父日志源的基本属性(例如日志级别)。
日志源可以在独立的Java进程中运行,也可以宿主在容器中。独立进程主要是Spoon/Kitchen/Pan三种类型,容器主要是Carte/DI Server/BI Server三种类型(后面两者都是Pentaho的产品,超出本文范围,不再赘述。读者只需理解,在容器中运行时日志源没有独立JVM,而是与容器共用一个进程)。如果在容器中运行,容器也是日志源,那么日志源之间除了父子关系还可能存在宿主关系。宿主关系可以通过日志源的容器对象编号明确。
2、日志通道
日志通道就是日志的传输渠道。如果拿水系来比喻,日志源是发源地,
日志通道就是河道。发源地有高原、冰川、水泊等不同形态,日志源也有资源库、图形用户界面、运行时组件等多种类型。发源地没有河道无以形成河流,
日志源没有通道无以形成日志流。一般来说,每一个日志源都会建立一个唯一对应的日志通道,这样日志源产生的日志,才会源源不断的从日志通道有序输送。
如果看得更加细节一些,日志通道还承担了日志过滤和性能度量职能。日志过滤又包含级别过滤和关键词过滤两种情况。级别过滤是指通道会自动对设定级别之上的日志截流;关键词过滤是指通道会自动对不含关键词的日志进行截流。这里讲的截流可以直观理解为丢弃,亦即不输出。
3、日志注册表
日志注册表负责日志源的集中管理。就像居民上户口要到派出所,日志注册表就是日志源的“户口簿”。所有日志通道的构建,都需要到日志注册表申请一个唯一的通道编号(
由UUID算法生成)并构造日志源对象以完成登记注册。
有了统一管控的注册表,可以带来很多便捷:可以避免两个相等的日志源重复注册;可以控制日志源的总数;可以通过通道编号快速查找日志源;可以快速查找日志源的所有后代。
4、日志仓库
日志源是发源地,日志通道是河道,日志仓库就是大海。所有的日志,从各个日志源,沿着各自的日志通道,最终都输出到日志仓库进行集中存储与管理。其他人需要日志,不管是用在GUI界面中直接展示,还是输出到控制台,都需要通过
与日志仓库的交互而拿到自己感兴趣的日志信息,故而日志仓库是日志体系中权力最大者。
日志仓库负责日志信息的集中存储与管理。它内置一个日志缓冲区,以日志行集合的形式来管理。每个日志行自
产生之日起就会带一个全局唯一的顺序编号,日志使用者可以非常方便地检索两个编号之间的所有日志行。除了编号外,日志行还包含时间戳、日志级别、消息内容等信息。
5、日志级别
人生总要面临选择,技术总是面临权衡。要是追求性能到极致,最好不要输出日志;要是需要精确定位问题,日志输出越详细越好。所以日志的分类必不可少。Java中著名的日志组件
Log4j建议只使用四个级别,优先级从高到低分别是ERROR、WARN、INFO、DEBUG,而Kettle选择自成体系。
Kettle把日志级别分为0-6共七个级别:
0:没有日志,是指程序不会主动输出任何日志信息。如果对ETL性能有极端要求时可以选择此级别。但要注意了解一点编程基础:Kettle使用Java编程语言设计的,而Java程序存在Error和Exception两个概念。Exception代表程序可以处理的异常,Error代表程序不可处理的问题。所以,设置日志级别为0,也可能有Error输出。例如内存不足时,用户总是能够看到OutOfMemoryError错误信息。
1:错误日志,是指程序执行过程中发现的异常情况。这对排查解决ETL程序故障至关重要。错误日志,就是前文所述Exception,此日志一般都会包含异常的名称与描述,方便没有开发背景的工程师解决故障。对开发人员而言,可能还能看到异常堆栈,这样能够定位到源代码的某一行。
2:最小日志,是指程序执行过程中的警告信息或者最基础的提示信息。这个级别有点鸡肋,处在这个级别的日志信息非常少,选择这个级别的场景也少。举例来说,数据库驱动不支持在批量操作时处理错误警告信息是最小日志级别;作业中一个子作业的开始与结束提示信息是最小日志级别。
3:基本日志,是指程序执行过程中的提醒信息。这类信息主要用于内核中一些大的动作,主要场景包括:连接池的创建、插件的注册、Pan/Kitchen执行时的版本号、FTP连接的开始等。
4:详细日志,是指程序执行过程中的详细信息。这类信息主要用于内核中的动作细节,主要场景包括:执行的每一个数据库SQL、每一个插件类的详情、每一个作业项执行的错误数、每一个资源库对象的加载详情等。
5:调试日志,是指调试程序需要的一些过程性信息。读懂这部分信息,需要对Kettle具备源码级理解。生产环境中,一般无法搭建源码调试环境,只有依靠调试日志信息,才能定位程序执行过程中的故障段。注意,这里用的词是故障段,而不是故障点。因为输出调试日志的代码行非常有限,所以程序员只能根据输出,查找出现故障在哪一个代码片段,再根据代码阅读与理解,结合执行环境,才能猜测故障点。逐个排查疑似故障点后,才能最终解决问题。
6:行级日志,是指程序执行过程中精确到每一个数据行的信息。行集是Kettle的一个核心概念(参见内存调优一文中对行集的介绍),简单来说行集就是数据行的集合。行级日志最详细之处在于,日志系统将对每一个数据行生成日志行,在排查某些由数据导致的执行异常时非常有效。通常在设计调试状态下运行良好的ETL程序,当部署到生产环境中时总会出现一些问题。大部分原因,是因为生产环境的数据不同,如果能够找出哪类数据导致故障,那么修改作业或转换就能做到有的放矢。
6、性能度量
性能度量本不该是日志的事情。Kettle的创始人如此设计,颇有些不解。唯有暂时搁置争议,先把名词做一个解释。性能度量就是对动作性能指标值的计算。动作非常多,主要包含数据库(连接、执行SQL、获取元数据等)、插件注册表(注册一个插件、注册扩展点、注册全部插件等)、转换(执行转换、转换初始化、执行步骤等)、作业(执行作业、执行作业项)、日志(清除过期日志、查找日志源子孙等)5类。指标则非常少,共有
6类
(START/STOP/MIN/MAX/SUM/COUNT)。
动作加上指标就构成了性能度量。当然,并不是所有动作都能配得上所有指标。例如连接数据库就只有START/STOP两个指标来度量,两者的时间戳差值,就是连接数据库的总耗时。
三、总结
本文主要介绍日志的基本概念。希望K友们看完本文后,能够记住日志由日志源产生、日志通道传递、日志仓库存储,这就是日志流的核心过程。日志级别用于对日志分类,日志注册表管理所有日志源,两者的加入方能实现更为高效精细的日志系统。