前言
今天重啟了服務器,發現supervisor管理的rabbitmq的進程居然啟動失敗了,查看日志發現老是報錯,記錄一下解決的辦法。
報錯:erlexec:HOME must be set
- 找了網上的許多人的博客,一般的說法是在進程的啟動的腳本中加入:
export HOME=/usr/local/erlang
export PATH=$PATH:$HOME/bin
- 系統默認的HONE是/root,可能造成erlang語言環境獲取不到HOME參數;上述修改可以用在chkconfig管理和service管理的進程中,但是對於supervisor管理的進程,由於進程的啟動命名在supervisor.conf中,不能直接修改HOME參數。
辦法: 在supervisor的啟動腳本中加入上述語句。
vi Ssupervisor.conf
#!/bin/sh
# chkconfig: 2345 70 90
export HOME=/usr/local/erlang
export PATH=$PATH:$HOME/bin
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
- 這樣做可以保證只是臨時改變了HOME,但是對系統的HOME沒有影響。
溯源
- 為什么會有這個錯誤?
這個錯誤不是rabbitmq的原因,而是erlang語言環境的原因;查看一個erl進程:
ps aux | grep beam
# 結果:
root 1779 0.4 0.5 3863876 86060 ? Sl 19:21 0:06 /usr/local/erlang/bin/x86_64-unknown-linux-gnu/beam.smp -W w -A 64 -P 1048576 -t 5000000 -stbt db -zdbbl 32000 -K true -B i -- -root /usr/local/erlang -progname erl -- -home /root
- 可以看到-home參數就是啟動是加進去的,啟動一個erl實例,其調用了erlexec的c文件;
# erlexec.c 文件的路徑為/usr/local/erlang/erts/etc/common/erlexec.c
# 部分代碼
static char * home;
static char ** Eargsp = NULL;
static int EargsCnt = 0;
static char **argsp = NULL;
static void get_home( void )
{
home = get_env("HOME");
if (home == NULL)
error("HOME must be set");
}
-
可以看到get_env函數獲取HOME環境變量,如果獲取失敗就輸出‘HOME must be set’。
-
目前一個不明白的地方是HOME參數有一個默認的值/root,為什么get_env函數獲取不到,而是返回了null;有待繼續研究;
rabbitmq重啟失敗
-
發現手動殺死rabbitmq的進程后,supervisor重啟rabbitmq要么失敗,要么不重啟;
-
如果采取supervisor后台的進程管理來啟動和停止rabbitmq是可以的,但是如果手動殺死rabbitmq進程則無法重啟進程;
原因:
-
rabbitmq使用rabbitmq-server start 或使用rabbitmq-server啟動后,會有兩個進程,一個是erlang的節點服務程序;一個是rabbitmq的應用程序;rabbitmq的應用程序在erlang的節點上運行;
-
如果強制殺死rabbitmq的應用程序進程,supervisor會嘗試啟動,這時會嘗試啟動erlang的節點服務程序和rabbitmq的應用程序,發現已經存在一個erlang的節點服務程序,所以啟動會失敗;
-
如果強制殺死erlang的節點服務程序,這時erlang的節點服務程序和rabbitmq的應用程序都會被停止,如果配置參數為autorestart=unexpected 的話,那么supervisor不會去重啟該進程,如果參數設置為autorestart=true,那么supervisor會去重啟erlang的節點服務程序和rabbitmq的應用程序;
結論:
-
由supervisor管理rabbitmq進程並不是很合適,因為在rabbitmq的應用程序崩潰而erlang的節點服務程序正常的情況下,重啟是失敗的;
-
如果只有節點在運行,但是沒有rabbitmq的應用程序實例,那么對於rabbitmq的管理后台也是無法登陸的。