問題描述
部門的Hadoop叢集運行有一個多月了,今天需要做點調整,但是突然發現Hadoop不能正常關閉。
Hadoop版本:2.6.0
具體情況如下:
[root@master ~]# stop-dfs.shStopping namenodes on [master]master: no namenode to stopslave2: no datanode to stopslave1: no datanode to stop...
問題原因
執行jps,發現namenode,datanode等進程都正常運行著。納了悶。
誰報的錯就找誰吧,於是就開始閱讀hadoop-daemon.sh指令檔,結果找出問題原因了。
首先找到報錯的位置,在檔案的最後幾行:
if [ -f $pid ]; then TARGET_PID=`cat $pid` if kill -0 $TARGET_PID > /dev/null 2>&1; then echo stopping $command kill $TARGET_PID sleep $HADOOP_STOP_TIMEOUT if kill -0 $TARGET_PID > /dev/null 2>&1; then echo "$command did not stop gracefully after $HADOOP_STOP_TIMEOUT seconds: killing with kill -9" kill -9 $TARGET_PID fi else echo no $command to stop fi rm -f $pid else echo no $command to stop fi
代碼很多,我們只看我們關心的部分:
if [ -f $pid ]; then ....#省略n多行 else echo no $command to stop fi
這樣就很明顯了,如果pid檔案不存在就會列印:no xxx to stop
那麼pid是什麼檔案,為什麼會不存在,找到pid變數的聲明語句,在指令檔的第107行:
pid=$HADOOP_PID_DIR/hadoop-$HADOOP_IDENT_STRING-$command.pid #第107行
接著再找HADOOP_PID_DIR變數的聲明部分:
首先在指令碼注釋部分找了很關鍵的一句話:
# HADOOP_PID_DIR The pid files are stored. /tmp by default.
我們知道了,HADOOP_PID_DIR 變數儲存的是pid檔案的儲存路徑。預設儲存在/tmp目錄中,代碼如下:
if [ "$HADOOP_PID_DIR" = "" ]; then //97~99行 HADOOP_PID_DIR=/tmpfi
那麼這個pid檔案是啥呢。Hadoop啟動後,會把進程的PID號儲存在一個檔案中,這樣執行stop-dfs指令碼時就可以按照進程PID去關閉進程了。
現在問題原因很明確了,就是/tmp目錄下的hadoop-*.pid的檔案找不到了。 解決問題
那就看看/tmp目錄下還有啥:
[root@slave1 ~]# ll /tmp/srwxr-x--- 1 root root 0 Mar 26 13:39 Aegis-<Guid(5A2C30A2-A87D-490A-9281-6765EDAD7CBA)>drwxr-xr-x 2 root root 4096 Apr 10 13:55 hsperfdata_rootsrwxr-x--- 1 root root 0 Mar 26 13:39 qtsingleapp-aegisG-46d2-0srwxrwxrwx 1 root root 0 Mar 26 13:39 qtsingleapp-aegiss-a5d2-0
額,除了我們需要的,其他啥都有。
我們知道/tmp是臨時目錄,系統會定時清理該目錄中的檔案。顯然把pid檔案放在這裡是不靠譜的,pid檔案長時間不被訪問,早被清理了!
既然Hadoop不知道需要關閉哪些進程了,那我們只能手動關閉了。
先用ps -ef查看namenode\datanode等進程的PID,然後用kill -9幹掉即可。
重啟Hadoop後再看看/tmp目錄的變化,多出了下面幾個檔案:
[root@master ~]# ll /tmp-rw-r--r-- 1 root root 6 Apr 10 13:39 hadoop-root-namenode.pid-rw-r--r-- 1 root root 6 Apr 10 13:39 hadoop-root-secondarynamenode.pid-rw-r--r-- 1 root root 6 Apr 10 13:55 yarn-root-resourcemanager.piddrwxr-xr-x 4 root root 4096 Apr 10 14:52 Jetty_0_0_0_0_50070_hdfs____w2cu08drwxr-xr-x 4 root root 4096 Apr 10 14:52 Jetty_0_0_0_0_50090_secondary____y6aanvdrwxr-xr-x 5 root root 4096 Apr 10 15:02 Jetty_master_8088_cluster____i4ls4w
前三個檔案是存放PID的檔案,後三個Jetty_xxx格式的目錄是Hadoop的web應用的臨時目錄,不是我們關心的。
開啟一個pid檔案看看:
[root@master tmp]# cat hadoop-root-namenode.pid32169
很簡單,就儲存了namenode進程的PID,再關閉namenode進程時就要從這個檔案中讀取PID。
到這裡問題已經愉快的解決了。
但是,明知道pid檔案放這裡不安全,還不修改一下就顯得我太懶了。
修改pid檔案存放目錄,只需要在hadoop-daemon.sh指令碼中添加一行聲明即可:
HADOOP_PID_DIR=/root/hadoop/pid #第25行
記住要先關閉Hadoop再修改,不然你修改完又無法關閉了。同樣的道理,你還需要修改yarn-daemon.sh
YARN_PID_DIR=/root/hadoop/pid
然後執行start-dfs.sh \ start-yarn.sh 啟動Hadoop。再去/root/hadoop/pid目錄下看看:
[root@master pid]# ll-rw-r--r-- 1 root root 5 Apr 10 14:52 hadoop-root-namenode.pid-rw-r--r-- 1 root root 5 Apr 10 14:52 hadoop-root-secondarynamenode.pid-rw-r--r-- 1 root root 5 Apr 10 15:02 yarn-root-resourcemanager.pid
好了,從此再也不用擔心出現no xxx to stop的警告了。 /tmp目錄的清理策略
除了更換pid檔案的儲存路徑外,我不由會想起另外一種解決思路,不讓作業系統刪除儲存在/tmp目錄下的pid檔案不就可以了嘛。好的,那我們就來看看作業系統是怎麼清理/tmp目錄的。
遇到這個問題之前,我也沒關係過/tmp目錄,度娘一下,得到答案。
我們先來看一個重要的命令:
tmpwatch
tmpwatch指令可刪除不必要的暫存檔案,你可以設定檔案超期時間,單位以小時計算。
常用參數:-m 或–mtime 根據檔案被更改時間-c 或–ctime 根據檔案更改狀態時間-M 或–dirtime 根據檔案夾被更改時間-x 或–exclude=path 排除某路徑-X 或–exclude-pattern=pattern 排除某規則下的路徑
/tmp作為臨時檔案夾,系統預設每天清理一次該目錄。系統通過定時任務每天會執行一次/etc/cron.daily/tmpwatch這個指令碼。其原理就是利用tmpwatch指令,設定清理策略。我們來看一下這個指令碼內容:
/etc/cron.daily/tmpwatch#! /bin/shflags=-umc/usr/sbin/tmpwatch "$flags" -x /tmp/.X11-unix -x /tmp/.XIM-unix \ -x /tmp/.font-unix -x /tmp/.ICE-unix -x /tmp/.Test-unix \ -X '/tmp/hsperfdata_*' 10d /tmp/usr/sbin/tmpwatch "$flags" 30d /var/tmpfor d in /var/{cache/man,catman}/{cat?,X11R6/cat?,local/cat?}; do if [ -d "$d" ]; then /usr/sbin/tmpwatch "$flags" -f 30d "$d" fidone
代碼的4~6行是一條語句,設定/tmp目錄的清理策略. -x或-X是用來排除不清理的檔案或目錄,10d表示會刪除最近10天沒有被訪問的檔案(有的系統可能是240 ,表示240小時,也是10天)。
好吧 ,10天不用就給刪除了,Hadoop叢集運行幾十天了,當然也就找不到pid檔案了。
你有注意第6行代碼中,被排除的檔案嗎 。/tmp/hsperfdata_*,我們在上面解決問題時,第一次查看/tmp目錄就有一個匹配此模式的檔案:hsperfdata_root 。
那麼,想不讓系統刪除pid檔案,比著榴蓮畫個瓢就行了。在tmpwatch指令碼中增加一個排除條件即可:
-X '/tmp/*.pid'
不過,既然是臨時目錄,重要的檔案就不要放這了,還是推薦第一種解決方式。