該整理一下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命令列查詢之前,將環境變數發給作業系統。整個這一套新開程式加發現環境變數問題等等,調通用了整整兩天。

 

  1. public function NonBlockingRun($pCmd,$pTimestamp,$pFilename,$pType,&$pCode
  2.     global $env
  3.     $descriptorspec = array
  4.         0 => array("pipe""r"),   
  5.         1 => array("pipe""w"),  
  6.         2 => array("pipe""w"
  7.     ); 
  8.  
  9.     $pipesarray(); 
  10.      
  11.     $process = proc_open($pCmd$descriptorspec$pipes); 
  12.  
  13.     $output""
  14.  
  15.     if (!is_resource($process)) 
  16.     { 
  17.         return false; 
  18.     } 
  19.  
  20.     fclose($pipes[0]); 
  21.  
  22.     stream_set_blocking($pipes[1],0); 
  23.     stream_set_blocking($pipes[2],0); 
  24.      
  25.     $todoarray($pipes[1],$pipes[2]); 
  26.  
  27.     $fp = fopen($pFilename,"w"); 
  28.     #fwrite($fp,$pTimestamp." "); 
  29.     while( true ) 
  30.     { 
  31.         $readarray();  
  32.         #if( !feof($pipes[1]) ) $read[]= $pipes[1]; 
  33.         if( !feof($pipes[$pType]) ) $read[]= $pipes[$pType];// get system stderr on real time 
  34.          
  35.         if (!$read
  36.         { 
  37.             break
  38.         } 
  39.  
  40.         $ready= stream_select($read$write=NULL, $ex= NULL, 2); 
  41.  
  42.         if ($ready === false) 
  43.         { 
  44.             break; #should never happen - something died 
  45.         } 
  46.          
  47.         foreach ($read as $r
  48.         { 
  49.             $sfread($r,128); 
  50.             $output .= $s
  51.             fwrite($fp,$s); 
  52.         } 
  53.  
  54.     } 
  55.  
  56.     fclose($fp); 
  57.  
  58.     fclose($pipes[1]); 
  59.     fclose($pipes[2]); 
  60.  
  61.     $pCode= proc_close($process); 
  62.  
  63.     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的誕生,你們是最棒的。