1、問題背景算法
轉換和做業是Kettle的兩支利劍。其中,轉換採用多線程併發運行架構,做業採用遞歸順序執行架構。所以,在增長CPU、內存等硬件資源的狀況下,Kettle轉換隻需修改配置,便可充分利用基礎設施能力,提升執行效率。轉換的這種垂直擴展能力,使其成爲實現ETL功能的必備工具,也是性能優化的核心。數據庫
固然,性能優化是一個系統工程,不只涉及工具自己的優化,更涉及到ETL工具以外的諸多因素。好比,ETL要讀取數據庫,那麼目標DMBS的性能、SQL語句、網絡等相關因素都影響到執行效率。Kettle的中文意思爲水壺,意即經過這把「水壺」,把上游產生的「水」(數據)順利輸送到下游各部門。想要讓整個輸送過程實現效率最高,取決於三個因素:上游來水渠道、水壺的大小與數量、下游輸水渠道。編程
本文在假設第1、第三個因素已經達到最優的前提下,討論第二個因素如何優化。即在外部環境因素不變、內部轉換不變時,如何定位到性能瓶頸步驟,並經過垂直擴展進行有針對性、實效性的優化。文章最後還簡要介紹了自定義優化插件的編程思路。數組
2、工具侷限性能優化
Kettle工具自己具有性能監測手段。設計階段經常使用的Spoon工具中,轉換執行以後,窗口底部執行結果中有一個步驟度量標籤頁(以下圖1所示)。微信
圖1網絡
從步驟度量中,能夠看到每一個步驟的執行時間以及速度。在生產環境中,經過Pan或者Kitchen的執行日誌,也可以看到讀、寫行數和速度。那麼,是否是速度慢的步驟就是性能瓶頸?或者執行時間最長的就是卡的步驟呢?下面經過實例來分析。多線程
圖1中的轉換,共包括42個步驟。在測試機器上,經過Spoon中調試執行共需3分4秒,各步驟的性能度量結果圖2所示。架構
從圖2中能夠看出,執行時間長、執行速度慢的步驟都集中在黃色區域,即步驟C01~C15和D00~D07,每一個步驟的執行時間大概是3分1秒。那麼,性能瓶頸是否就在這些步驟中呢?併發
答案是非也!
經過目測Spoon調測窗口(詳見圖1中虛線框步驟)的運行狀態,咱們能夠看到,C01前的步驟幾乎都在5秒內完成,而C01後的步驟,因爲都在等C01的輸出,因此執行時間隨之變長,執行速度幾乎都在1條記錄/秒。所以,本轉換的性能瓶頸在步驟C01,跟其餘步驟無關(固然這種目測方法不適合用於生產環境)。
圖2
3、解決辦法
一、原理探究
致使這種誤判現象背後的緣由到底是什麼呢?
咱們分析發現,Kettle列出的每一個步驟的執行時間,是經過步驟完成時間減去步驟開始時間而得出的時間間隔(參照圖3中org.pentaho.di.trans.step.BaseStep源碼)。所以,即便步驟沒有作具體的事情,只是在等待輸入行,但因爲步驟並無執行完畢,因此等待時間也包含在執行時間中。這是致使誤判的根本緣由。
圖3
經過JDK工具JavaVirtualVM監測各線程執行狀態,也能夠證明這一點。圖4爲轉換執行過程當中的一個截圖。能夠看出,Kettle爲每個轉換都至少啓動了一個線程,線程的命名規則爲:
轉換名稱 – 步驟名稱
本例轉換名稱爲KettleSample004,因此步驟C01所在線程名稱就爲「KettleSample004– C01」。圖4中綠色部分表明線程處在工做狀態,橙色部分表明等待執行狀態。截圖時刻(15:51:40至15:52:00),步驟C01一直處在工做狀態,而C02~C15基本上都處在等待狀態(只有C02存在小段工做時間)。
圖4
所以,解決問題的關鍵在於,須要一個程序來統計步驟的實際工做時間,實際工做時間長的步驟,能夠斷定爲轉換性能瓶頸。圖5爲在另一臺測試機器上,運行一樣轉換獲得的實際工做時間數據(去掉了一些時間很是短的步驟),左側爲各步驟實際工做時間表,右側爲時間數據散點圖。因爲C01實際工做時間與其餘步驟相比懸殊太大,爲了更容易分類,右側下半部分繪製了排除C01時間數據以外的散點圖。從圖5中的數據能夠明顯看出轉換的性能瓶頸步驟,也能夠根據散點圖按照各步驟執行時間分爲幾種不一樣類別,分類進行優化。
圖5
二、手工解決辦法
第一步:分組。
根據散點圖的分析結果,咱們能夠按照實際工做時間的長短,將步驟分爲5個組(以下表1所示)。實際工做時間在100-400毫秒之間的步驟納入#1組;實際工做時間在2100~6800毫秒之間的步驟納入#2組;實際工做時間在7800~12000毫秒之間的步驟納入#3組;實際工做時間最高的C01單獨納入#4組;其餘步驟納入#5組。
表1
第二步:定義命名參數。
在Spoon中雙擊轉換,在轉換屬性對話框中添加4個命名參數,並設置默認值。表1中的其餘步驟分組#5無需單獨定義參數,由於這些步驟的複製數量能夠保持默認值1不變。具體設置如圖6所示。
圖6
第三步:設置步驟。
根據表1的分組結果,設置每個步驟的複製數量,以利用Kettle的垂直擴展能力。具體操做是在每個步驟上點擊右鍵,選擇「改變開始複製的數量…」菜單,並按住Ctrl+Alt+空格鍵,在下拉框中選擇對應分組的命名參數便可。注意,某些步驟可能不容許改變複製數量。若是這些步驟對性能調優很是重要,咱們能夠在步驟前加一個空操做步驟,再進行設置;若是不重要,忽略便可。配置後的結果以下圖7所示:
圖7
第四步:運行調優。
若是咱們單純把線程數量無限增大,因爲建立線程、線程上下文切換等其餘資源的消耗,可能帶來執行速度不升反降。所以,不能簡單地按照實際工做時間比例來調整複製數量。例如#4組的實際工做時間是#3組的40倍以上。按此比例,#3的值若是設置爲8,那麼#4的值應該設置爲320,這顯然不是一個合理的設置。因此在環境不變的狀況下,如何獲得最優的複製數量,是一個有挑戰性的問題。本文僅討論依據經驗經過不一樣設置的實際執行效果,來找到局部最優解的方法。其餘方法將在另外的文章中進行討論。
經過Pan命令,能夠設置不一樣的參數來執行一樣的任務,經過總體運行時間,找到一個較好的參數組合。具體命令示例以下(Windows環境):
Pan.bat "/file:D:\KettleSample004.ktr" "/param:#2=1""/param:#3=1" "/param:#4=1"
在測試機器上,不一樣參數組合的執行結果以下表2所示:
表2
從4次實驗的結果看,選擇2,3,8,10的參數值組合,執行時間爲16秒,獲得局部最優解。
三、使用插件
比手工解決更快捷的方法是利用插件,收集各步驟的運行結果,並自動分組、定義各分組相關步驟的命名參數。特別是在步驟相對較多的狀況下,能夠極大提升工做效率。下面簡要介紹插件的用法。
第一步:打開已經定義好的轉換,在左側核心對象樹中選擇Kettle博士分類下的複製優化步驟,拖動放到轉換中的任意位置。
第二步:雙擊複製優化步驟,在彈出的對話框中選擇清空全部複製,並點擊肯定。這樣,轉換中全部已經設置複製數量的信息都將清空,以確保獲取真實的性能監測數據。以下圖8所示。
圖8
第三步:雙擊複製優化步驟,在彈出的對話框中輸入分組的數量(默認是7個分組),勾選自動建立參數,並點擊肯定。以下圖9所示。
圖9
第四步:運行轉換。能夠在Spoon中或者生產環境命令行中執行。執行後,能夠在日誌中看到分組的結果、每個步驟的實際工做時間等信息,並自動建立相關命名參數,設置到轉換每個相應的步驟中(若是在Spoon中運行,須要從新打開轉換文件)。下圖10爲在Spoon中執行的結果分析信息,圖11爲自動建立的命名參數以及步驟設置結果。
圖10
圖11
4、插件編程要點
下面來介紹插件編程的主要代碼,插件中基於實際工做時間進行聚類的算法不在本文討論之列。讀者能夠參照其餘數據挖掘文章,找到關於聚類的算法。
首先須要瞭解的背景知識是,Java線程包含6種狀態(NEW RUNNABLE BLOCKED WAITING TIMED_WAITING TERMINATED),對於優化需求而言,只需統計Kettle轉換步驟線程的RUNNABLE狀態時間,而後排序輸出便可。主要代碼解釋以下:
一、查找轉換的全部步驟
用到類org.pentaho.di.trans.Trans的主要方法:
publicList<StepMetaDataCombi> getSteps()
能夠獲得轉換的全部步驟列表。列表中每一個元素都是StepMetaDataCombi類的實例。而StepMetaDataCombi類有一個公有屬性stepname表明步驟名稱。
publicString getName()
能夠獲得轉換名稱。
如前所述,獲得了轉換名稱和步驟名稱,Kettle步驟執行線程的名稱便可肯定。
二、查找全部線程
查找全部線程的方法代碼以下:
public Thread[] findAllThreads() {
if(topGroup == null) {
ThreadGroupgroup = Thread.currentThread().getThreadGroup();
topGroup= group;
while(group != null) {
topGroup= group;
group= group.getParent();
}
}
intestimatedSize = topGroup.activeCount() * 2;
Thread[]actualContainer = new Thread[estimatedSize];
intactualSize = topGroup.enumerate(actualContainer);
Thread[]threads = new Thread[actualSize];
System.arraycopy(actualContainer,0, threads, 0, actualSize);
returnthreads;
}
三、時間統計
啓動一個後臺線程,固定間隔時間查看各線程狀態,若是爲RUNNABLE狀態,則累計時間。一直到轉換執行完畢或者中止時,時間統計能夠中止,排序輸出統計結果後,線程運行結束。判斷轉換是否執行完畢,能夠調用上述Trans類的isFinished方法;判斷線程是否中止,能夠調用其isStopped方法。
四、複製次數設置
添加命名參數,能夠調用TransMeta類的addParameterDefinition方法。設置複製數量,能夠調用StepMeta類的setCopiesString方法。
5、總結
本文介紹了經過對Kettle垂直擴展參數的優化,提升轉換執行性能的方法。同時也把編程相關API要點逐一闡述。全部實際工做中的轉換優化問題,都可參考。因爲每個轉換步驟優化的方法不盡相同,因此未討論單個步驟的優化問題。
如需原始轉換及演示數據文件,請聯繫微信號carol_sxh獲取,添加好友時請註明所需文件名(示例轉換文件KettleSample004.7z(免費);插件文件kettle-doctor-plugin.7z(付費))。
注意:因爲插件只在Kettle6~8版本上進行過驗證,其餘版本未經嚴格測試,使用前務必作好備份!
【注意】本公衆號所發文章皆爲原創,如轉載請註明出處及做者。
本文分享自微信公衆號 - Kettle博士(gh_f656c3d7ba54)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。