該整理一下phpHiveAdmin好玩的知識點了。
訪問Hive介面有thrift,這沒有太多可說的,只要呼叫封裝好的方法就行了。之前因為Socket的阻塞問題,經常會發生Hive介面讀取超時,修改一下Thrift裡面的TSocket.php就好了。修改方法參看之前的php開發Hive web查詢,跟網上的其他相關文章還是略有區別。
資料庫的管理方面主要就是獲取網頁變數,然後拼sql字串,這好像也沒啥可講的。多看Hive手冊就會了。
核心內容是查詢部分,這個是比較有趣的地方,最早的一版查詢是完全用thrift完成的,查詢特別慢不說,關鍵是沒有進度返回,而且如果中間關閉視窗就徹底找不到任務了。當時十分羨慕淘寶的Hive介面,有map/reduce進度條。於是自己調了兩天,寫了一個獲取map/reduce進度的方法,雖然沒有進度條,但是可以讀取到Hive執行的map/reduce進度,並實時返回。其核心思路是既然hive命令列可以將mr進度列印到控制檯上的stdout和stderr,那就寫個程式讀命令列執行的stdout和stderr就好了。但是要實時輸出到網頁的話,就需要邊讀邊寫,這對php來說就比較難了。對於php程式設計師來說,絕大多數是開發網頁的,用到執行緒和程式管理的非常少,極少。根據php針對網頁的特點。如果不用ajax,php本身無法對程式進行非同步處理。但是系統執行是在後端的,跟網頁無關,所以其實這是一個php在作業系統方面進行非同步執行的問題。pcntl是子程式管理,比較方便,但是需要在php編譯的時候enable,我不想給自己找麻煩,特別是不想給其他使用者造成困難,所以最後選擇了proc_open來新開一個程式完成非同步的處理。至於為什麼沒有選擇Java開發,或者python開發,也是考慮其實相比於php,java和python在網頁方面的開發還是偏小眾,配置LNMP可能會更大眾化,或許可以讓大家上手大資料更輕鬆一些。但是也不排除將來會用java或者python再寫一版,反正寫完交給別人自己查數管叢集,我也沒事幹,閒著也是閒著。
所以核心就在下面。
一個hive查詢通過頁面傳送給命令列執行,網頁會在伺服器上通過proc_open建立一個php程式,然後讀取Hive命令列執行返回的stdout和stderr,將執行過程的輸出寫入到一個臨時檔案。然後前端的頁面會讀取這個檔案,將內容倒排後返回給網頁,這樣就完成了map/reduce的實時讀取。說起來簡單,寫起來還是比較難的。中間還要涉及到Linux基本環境的配置,對HADOOP,HIVE,JAVA環境變數的輸出。通常php工作在nobody或者www這樣的使用者下面,這種使用者的預設shell是/sbin/nologin,似乎這類使用者不會獲得任何環境變數。所以必須在傳送Hive命令列查詢之前,將環境變數發給作業系統。整個這一套新開程式加發現環境變數問題等等,調通用了整整兩天。
- public function NonBlockingRun($pCmd,$pTimestamp,$pFilename,$pType,&$pCode)
- {
- global $env;
- $descriptorspec = array(
- 0 => array("pipe", "r"),
- 1 => array("pipe", "w"),
- 2 => array("pipe", "w")
- );
- $pipes= array();
- $process = proc_open($pCmd, $descriptorspec, $pipes);
- $output= "";
- if (!is_resource($process))
- {
- return false;
- }
- fclose($pipes[0]);
- stream_set_blocking($pipes[1],0);
- stream_set_blocking($pipes[2],0);
- $todo= array($pipes[1],$pipes[2]);
- $fp = fopen($pFilename,"w");
- #fwrite($fp,$pTimestamp." ");
- while( true )
- {
- $read= array();
- #if( !feof($pipes[1]) ) $read[]= $pipes[1];
- if( !feof($pipes[$pType]) ) $read[]= $pipes[$pType];// get system stderr on real time
- if (!$read)
- {
- break;
- }
- $ready= stream_select($read, $write=NULL, $ex= NULL, 2);
- if ($ready === false)
- {
- break; #should never happen - something died
- }
- foreach ($read as $r)
- {
- $s= fread($r,128);
- $output .= $s;
- fwrite($fp,$s);
- }
- }
- fclose($fp);
- fclose($pipes[1]);
- fclose($pipes[2]);
- $pCode= proc_close($process);
- return $output;
- }
這段就是主要用來讀取Hive命令列輸出的程式碼,這樣做的好處是,所有Hive發行版通吃,只要他能夠在命令列輸出內容,就能用phpHiveAdmin。什麼Apache版,Cloudera版,都能用。不方便的地方是,必須在執行phpHiveAdmin的機器上部署一個Hive和Hadoop(無需執行Hadoop,只要能訪問叢集即可),phpHiveAdmin依賴於Hive可執行檔案。但是並沒有因此拋棄thrift介面,thrift用來獲取庫名錶名,執行Hive管理什麼alter,drop,create,insert命令還是非常好用的。
回顧一下現在的工作,也是個挺神奇的事情,當吐個槽吧,最早剛進公司並不是以資料部門的名額被招進來的,只是個php web程式設計師,做線上部門的開發。那時候的那個領導姓張,上班第一天就讓我做專案,我用了大概兩週的時間,搭建了一整套基於scribe和awk的日誌採集和分析系統,除了生成報表,基本我一人全包了。awk指令碼都寫好了,然後那傢伙跟我說,你水平太差,你還是走吧。上班兩週做完一專案,然後要開掉我。當時震驚的無以復加,就去找人事說了一下這個情況,人事幫我轉到了資料部門。正好資料部門在搞hadoop,陰差陽錯。當時覺得hadoop安裝太費勁,就在老趙調研的基礎上寫了個指令碼。然後覺得Hive操作不方便,就寫了phpHiveAdmin。在童小軍的幫助下,phpHiveAdmin在2012年1月29日開源到github;EasyHadoop第一版安裝指令碼在2012年1月31日開源到github。
在這裡要特別感謝公司裡的3個人,首先是線上部門姓張的領導,如果不是因為你想讓我幹完專案就開掉我,我是不會到資料部門接觸Hadoop的,不接觸Hadoop就寫不了EHM和PHA,寫不了EHM和PHA我的部落格就沒啥可寫的。所以,儘管我非常厭惡你,但是還是需要感謝一下,因為有你的逆天存在,我才有機會寫出這篇部落格。真心感謝,不是吐槽高階黑。雖然我也很想趁你走夜路的時候拍板磚,不為我,為那些被你排擠走的優秀的同事。所以罵歸罵,該感謝還是得感謝。
其次感謝的是資料部門的前任領導童小軍,也是現在EasyHadoop社群扛大旗的人,基於他的鼓勵和工作協調下,我才能夠有時間開發和維護這兩個專案。也正是基於他的努力,才有了一個開源,開放的社群。
還有前任同事趙修湘,教會了我很多Hadoop生態圈的相關知識,盼望我們再次共事的那一天。
十分感謝公司資料組的每一位同事,有你們幫我分擔MR任務,才有EHM的PHA的誕生,你們是最棒的。