分布式進階(五)之JSVC配置
應用場景:在linux系統上進行項目開發,在部署java項目時,常用方法就是寫一個shell腳本,但當服務器重啟了,經常會忘了啟動shell腳本了。所以我們需要把自己的應用變成linux的服務,當服務器啟動的時候就自行啟動自己的應用。使用JSVC就能夠實現上面的功能。
在linux上以服務的方式啟動java程序步驟:
注:其實bin目錄下并沒有jsvc.tar.gz這個文件,需要自己下載。解壓完之后呢,執行sh?support/buildconf.sh?命令,提示autoconf:not?found,如下圖所示:
若不存在jsvc.tar.gz包,還可以嘗試如下方法:
1、在/home/shq/apache-tomcat-6.0.28/bin中有commons-daemon-native.tar.gz?壓縮包
2、解壓commons-daemon-native.tar.gz
tar?-zxvf?commons-daemon-native.tar.gz
3、解壓完成,出現commons-daemon-1.0.2-native-src文件夾(目錄)
1、??進入commons-daemon-1.0.2-native-src?下的unix目錄
ls
cd?commons-daemon-1.0.2-native-src/unix
2、??發現configure?配置文件,執行如下修改屬性的命令
sudo?chmod?777?configure
4、執行configure配置文件,運行效果如下圖所示:
上面這個這個圖是因為沒有加后面的參數sudo?./configure?--with?-java=/usr/lib/java,添加后面的參數后,效果圖如下圖所示:
其實真正的命令應該是sudo?./configure?--with?-java=/usr/lib/java/jdk1.6.0_45也就是說后面的參數應該是jdk的所在目錄,因為里面有相應的編譯工具。結果如下圖所示:
make時若出現以下錯誤,也可以通過上面的方法解決:
5、編譯
[root@localhost?~]#?sudo?make
運行結果如下圖所示:
#若報錯
[root@localhost?~]#?make?clean
[root@localhost?~]#?make????#重新編譯成功
6、編譯完成后出現jsvc文件夾,復制jsvc到/usr/lib/tomcat/apache-tomcat-6.0.28/bin目錄下面
[root@localhost?~]#?cp?jsvc?/usr/lib/tomcat/apache-tomcat-6.0.28/bin
7、在/etc/init.d/(注意不是init文件夾)目錄下編寫tomcat6啟動服務配置文件。
[root@localhost?~]#cd?/etc/init.d/
[root@localhost?~]#?vi?tomcat6.0.28
#!/bin/sh
#?tomcat:?Start/Stop/Restart?tomcat
#
#?chkconfig:?2345?85?15
#?description:?Apache?tomcat6
#?Small?shell?script?to?show?how?to?start/stop?Tomcat?using?jsvc
JAVA_HOME=/usr/lib/java/jdk1.6.0_45???#根據自己的實際jdk位置來修改
CATALINA_HOME=/usr/lib/tomcat//apache-tomcat-6.0.28??#根據自己實際tomcat位置來修改
DAEMON_HOME=$CATALINA_HOME/bin
#?I?did?not?use?the?user.
TOMCAT_USER=tomcat
#?for?multi?instances?adapt?those?lines.
TMP_DIR=$CATALINA_HOME/tmp
PID_FILE=$DAEMON_HOME/jsvc.pid
CATALINA_BASE=$CATALINA_HOME
.?/etc/rc.d/init.d/functions
CATALINA_OPTS=
CLASSPATH=\
$JAVA_HOME/lib/tools.jar:\
$CATALINA_HOME/bin/commons-daemon.jar:\
$CATALINA_HOME/bin/bootstrap.jar
start()?{
echo?-n?$"Starting?Tomcat6.0.28:?"
#?If?you?want?to?specify?a?user?to?run?Tomcat.
#increase?the?'user?$?TOMCAT_USER?\'?to?the?parameter?list.
$DAEMON_HOME/jsvc?\
-home?$JAVA_HOME?\
-Dcatalina.home=$CATALINA_HOME?\
-Dcatalina.base=$CATALINA_BASE?\
-Djava.io.tmpdir=$TMP_DIR?\
-wait?10?\
-pidfile?$PID_FILE?\
-outfile?$CATALINA_HOME/logs/catalina.out?\
-errfile?'&1'?\
$CATALINA_OPTS?\
-cp?$CLASSPATH?\
org.apache.catalina.startup.Bootstrap
echo?"*****************************[ok]"
}
stop()?{
echo?-n?$"Stopping?Tomcat6:?"
#
$DAEMON_HOME/jsvc?\
-stop?\
-pidfile?$PID_FILE?\
org.apache.catalina.startup.Bootstrap
echo?"*****************************[ok]"
}
status()?{
ps?ax?--width=1000?|?grep?"[o]rg.apache.catalina.startup.Bootstrap"?|?awk?'{printf??"?"}'?|?wc?|?awk?'{print?}'?>/tmp/tomcat_process_count.txt
read?line?/tmp/tomcat_process_count.txt
if?[?$line?-gt?0?];?then
echo?-n?"tomcat6?(?pid?"
ps?ax?--width=1000?|?grep?"[o]rg.apache.catalina.startup.Bootstrap"?|?awk?'{printf??"?"}'
echo?")?is?running?"
else
echo?"Tomcat6.0.28 is?stopped"
fi
}
case?""?in
start)
#?Start?Tomcat
start
exit?$?
;;
stop)
#?Stop?Tomcat
stop
exit?$?
;;
restart)
#?Restart?Tomcat
stop
sleep?3
start
exit?$?
;;
status)
status
exit?$?
;;
*)
echo?"Usage:?tomcat6?{start|stop|restart|status}"
exit?1;;
esac
#####
####
8、錄入完成,按Esc鍵。輸入:?wq(vi下輸入:x)保存退出并賦予/etc/init.d/tomcat6文件可執行權限
[root@localhost~]#?chmod +x /etc/init.d/tomcat6.0.28
------------------添加服務-----------------------------------------
9、[root@localhost~]?#chkconfig?--add?tomcat6.0.28???????????##添加tomcat服務
若提示chkconfig命令未找到,則需要執行sudo?apt-get?install?chkconfig
參考網址:http://blog.sina.com.cn/s/blog_66fb0c830100xm5y.html
PS:chkconfig是redhat公司遵循gpl規則所開發的程序在ubuntu上默認是不支持chkconfig命令的,但可以自己安裝。Ubuntu下是使用sysv-rc-conf來代替chkconfig。
sudo?apt-get?install?sysv-rc-conf
安裝完成后,直接運行sudo?sysv-rc-conf命令即可打開該管理軟件,如下圖所示:
操作界面十分簡潔,你可以用鼠標點擊,也可以用鍵盤方向鍵定位,用空格鍵選擇,?“X”表示開啟該服務。?用Ctrl+N翻下一頁,用Ctrl+P翻上一頁,用Q退出。
Ubuntu?的系統運行級別:
0?系統停機狀態
1?單用戶或系統維護狀態
2~5?多用戶狀態
6?重新啟動
Ubuntu下可以直接加入啟動程序,例如把?/etc/init/tomcat6.0.28?加入到系統自動?啟動列表中:
#sudo?sysv-rc-conf?tomcat6.0.28?on
想關閉tomcat6.0.28的開機自動啟動,只需#sudo?mv?/etc/init.d/tomcat6.0.28(注意將配置腳本備份,否則刪除后就跪了。)就可以了。
參考網址:http://www.linuxidc.com/Linux/2012-10/73123p2.htm
10、[root@localhost~]?#chkconfig?–list?|grep?tomcat6.0.28????##查看tomcat服務是否被添加
--------------------啟動服務---------------------------------------------
11、[root@localhost~]?#?service?tomcat6.0.28??start????????????##啟動tomcat服務
執行以上命令后,出現如下錯誤提示:
按照網上的說法,添加軟連接ln?-s?/lib/lsb/init-functions?/etc/rc.d/init.d/functions,繼續提示錯誤,原因很明顯:軟連接的文件夾壓根就不存在!
繼續搜索,發現以下說法:
在Linux中,/etc/init.d?和?/etc/rc.d/init.d這兩個目錄,都是用來放服務腳本的,當Linux啟動時,會尋找這些目錄中的服務腳本,并根據腳本的run?level確定不同的啟動級別。
在制作服務腳本的過程中,使用了Linux的兩個版本,CentOS和Ubuntu,需要在兩個版本中都可以開機啟動服務。但Ubuntu沒有?/etc/rc.d/init.d這個目錄,所以,為了保持同一種服務在CentOS和Ubuntu使用的統一性,將服務腳本(注:服務腳本在兩個不同版本中是不同的)都放在?/etc/init.d?目錄下,最終達到的效果是相同的。
需要說明的是:在CentOS和Ubuntu兩個版本中,除了服務腳本放置的目錄是相同的,服務腳本的編寫及服務配置都是不同的。比如CentOS使用Chkconfig進行配置,而Ubuntu使用sysv-rc-conf進行配置。
查看/etc/rc2.d/里面的apache和mysql啟動腳本,通常都是兩個阿拉伯數字后再接一個英文字母,再加腳本名稱,例如S20tomcat6.0.28。英文字母是S的都是會自動啟動的,K則相反。所以只要找到apache和mysql的啟動腳本,把S改成K就可以了。
以下命令實現開機啟動或不啟動某服務(真的太像chkconfig了)
sudo?sysv-rc-conf?服務名?on(off)
12、[root@localhost~]?#?sudo?sysv-rc-conf??off????????????##停止tomcat服務
13、[root@localhost~]?#sudo?sysv-rc-conf?--list?tomcat6.0.28??##查看tomcat服務啟動狀態
命令執行效果如下:
Linux?系統主要啟動步驟:
1.?讀取MBR?的信息,啟動Boot?Manager?Windows使用NTLDR作為Boot?Manager,如果您的系統中安裝多個版本的?Windows,您就需要在NTLDR?中選擇您要進入的系統。Linux?通常使用功能強大,配置靈活的GRUB作為Boot?Manager。
2.?加載系統內核,啟動init?進程.init?進程是Linux?的根進程,所有的系統進程都是它的子進程。
3.?init?進程讀取?/etc/inittab?文件中的信息,并進入預設的運行級別,按順序運行該運行級別對應文件夾下的腳本。腳本通常以?start?參數啟動,并指向一個系統中的程序。
通常情況下,?/etc/rcS.d/?目錄下的啟動腳本首先被執行,然后是/etc/rcN.d/?目錄。例如您設定的運行級別為3,那么它對應的啟動目錄為/etc/rc3.d/?。
4.?根據?/etc/rcS.d/?文件夾中對應的腳本啟動Xwindow?服務器xorgXwindow?為Linux?下的圖形用戶界面系統。
5.?啟動登錄管理器,等待用戶登錄Ubuntu?系統默認使用GDM?作為登錄管理器,您在登錄管理器界面中輸入用戶名和密碼后,便可以登錄系統。(您可以在?/etc/rc3.d/文件夾中找到一個名為S13gdm?的鏈接)
2.編寫服務啟動類
package?com.sohu.jsvc.test;
public?class?TestJsvc?{
public?static?void?main(String?args[])?{
System.out.println("execute?main?method!");
}
public?void?init()?throws?Exception?{
System.out.println("execute?init?method!");
}
public?void?init(String[]?args)?throws?Exception{
System.out.println("execute?init(args)?method");
}
public?void?start()?throws?Exception?{
System.out.println("execute?start?method!");
}
public?void?stop()?throws?Exception?{
System.out.println("execute?stop?method!");
}
public?void?destroy()?throws?Exception{
System.out.println("execute?destroy?method!");
}
}
main方法可以去掉,但是init(String[]?args),start(),stop(),destroy()方法不能少,服務在啟動時會先調用init(String[]?args)方法,然后調用start()方法,在服務停止時會首先調用stop()方法,然后調用destroy()?方法.
3.把這個類打包成webservice_engine.jar放到/usr/lib目錄下
4.編寫啟動服務的腳本?webservice_engineJSVC
#!/bin/sh
#?myjsvc?This?shell?script?takes?care?of?starting?and?stopping
#
#?chkconfig:?-?60?50
#?description:?tlstat?stat?is?a?stat?data?daemon.
#?processname:?webservice_engineJSVC
#?Source?function?library.
.?/etc/rc.d/init.d/functions
RETVAL=0
prog="webservice_engineJSVC"
#?jdk的安裝目錄
JAVA_HOME=/usr/lib/java/jdk1.6.0_45
#應用程序的目錄
MYJSVC_HOME=/test
#jsvc所在的目錄
DAEMON_HOME=/usr/lib/tomcat//apache-tomcat-6.0.28/bin
#用戶
MYJSVC_USER=root
#?for?multi?instances?adapt?those?lines.
TMP_DIR=/var/tmp
PID_FILE=/var/run/tlstat.pid
#程序運行是所需的jar包,commons-daemon.jar是不能少的
CLASSPATH=/usr/lib/webservice_engine.jar:/usr/lib/tomcat/apache-tomcat-6.0.28/bin/commons-daemon.jar:
case?"$1"?in
start)
#
#?Start?TlStat?Data?Serivce
#
$DAEMON_HOME/jsvc?-user?$MYJSVC_USER?-home?$JAVA_HOME?-Djava.io.tmpdir=$TMP_DIR?-wait?10?-pidfile?$PID_FILE?#控制臺的輸出會寫到tlstat.out文件里
-outfile?$MYJSVC_HOME/log/myjsvc.out?-errfile?'&1'?-cp?$CLASSPATH?#服務啟動類
test.main.WebServiceEngine
#
#?To?get?a?verbose?JVM
#-verbose?#?To?get?a?debug?of?jsvc.
#-debug?exit?$?
;;
stop)
#
#?Stop?TlStat?Data?Serivce
#
$DAEMON_HOME/jsvc?-stop?-pidfile?$PID_FILE test.main.WebServiceEngine
exit?$?
;;
*)
echo?"Usage Webjsvc?start/stop"
exit?1;;
esac
5.?把myjsvc文件拷貝到/etc/init.d/目錄下
6.?#chmod?-c +x /etc/init.d
7.?添加,啟動服務
#sudo sysv-rc-conf webservice_engineJSVC on
你可以從/test/log/myjsvc.out文件里看到如下信息:
execute?init(args)?method
execute?start?method
#service?myjsvc?stop
你會發現/test/log/myjsvc.out文件里會增加如下信息
execute?stop?method
execute?destroy?method
并且在系統重啟時會自動啟動myjsvc服務
好了,一個簡單的?liunx服務就寫好了,你可以在TestJsvc的init(),start(),stop(),destroy()方法里添加你的業務,做你想做的事。
下面講解jsvc?啟動Java?在Linux下的實現原理。
jsvc?是在apache的daemon項目下的開源項目,主要功能可以使一些運行在普通用戶下的java進程獲取一些root權限下的權利,比如端口在1024下等。
如何運行?
在自己的java代碼中,實現start,?init?,?stop,destroy的方法,將自己的編譯打成jar文件,??通過調用jsvc?來啟動
./jsvc?-java-home??/usr/java/jdk1.7.0_09/?-user?nobody??-pidfile?/opt/apache-tomcat_1/logs/catalina-daemon1.pid?-wait?10?-errfile?"/tmp/error"?-outfile?"/tmp/output"?-debug?-classpath?/root/test.jar:/root/commons-daemon.jar?test
幾個注意點:
commons_daemon.jar文件是用于調用你的class文件,
關于-java-home,?在這里有一個bug(https://issues.apache.org/jira/browse/DAEMON-268),哪怕指定,也會指定為默認的/usr/java
實現原理?
jsvc?是一個源碼是c的程序,通過fork出子進程去啟動java,而進程成為控制進程,可以實現監視java子進程的目地。
改變啟動虛擬機的進程用戶id和用戶組
通過調用setgid,setuid來改變當前進程的用戶id和組,這里要注意的是當改變用戶id和組的時候,當前進程會改變進程的capability,?所以需要reset?進程的capability。
查看進程的capability可以通過內核調用?__NR_capget?/?__NR_capset?的方式
static?int?get_legacy_caps(){
struct?__user_cap_header_struct?caphead;
struct?__user_cap_data_struct??cap;
memset(&caphead,?0,?sizeof?caphead);
caphead.version?=?LEGACY_CAP_VERSION;
if?(syscall(__NR_capget,?&caphead,?&cap)?0)
log_error("capget?failed:?%m");
log_debug("PID?is?%d?print?the?cap??0x%x,?0x%x,?0x%x\n",?getpid(),?cap.effective,?cap.permitted,?cap.inheritable);
return?0;
}
啟動java
通過調用JNI_CreateJavaVM?啟動虛擬機器,同時調用包common-daemon里的DaemonLoader?class,?調用你所寫的類中的start,...這些方法。
碰到的問題
在jsvc?里啟動java以后就將jvm的虛擬機的進程的capability?設置成了0,??導致在虛擬機里的創建線程受到max?process?的控制,?ulimit?-u
已經創建issue:?https://issues.apache.org/jira/browse/DAEMON-270,?短期解決辦法可以設置ulimit?到比較大的值。
Linux 分布式
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。