1. 程式人生 > >分散式進階(五)之JSVC配置

分散式進階(五)之JSVC配置

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

應用場景: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、編譯 

[[email protected] ~]# sudo make  

執行結果如下圖所示:

 

 #若報錯 

[[email protected] ~]# make clean 

[[email protected] ~]# make    #重新編譯成功 

 

6、編譯完成後出現jsvc資料夾,複製jsvc/usr/lib/tomcat/apache-tomcat-6.0.28/bin目錄下面 

[[email protected]localhost ~]# cp jsvc /usr/lib/tomcat/apache-tomcat-6.0.28/bin

 

7、在/etc/init.d/(注意不是init資料夾)目錄下編寫tomcat6啟動服務配置檔案。 

[[email protected] ~]#cd /etc/init.d/ 

[[email protected] ~]# 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 $1 " "}' | wc | awk '{print $2}' >/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 $1 " "}'  

       echo ") is running "  

     else  

       echo "Tomcat6.0.28 is stopped"  

     fi  

}  

  

case "$1" 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檔案可執行許可權 

[[email protected]~]# chmod +x /etc/init.d/tomcat6.0.28 

------------------新增服務----------------------------------------- 

9、[[email protected]~] #chkconfig --add tomcat6.0.28           ##新增tomcat服務 

若提示chkconfig命令未找到,則需要執行sudo apt-get install chkconfig

參考網址:http://blog.sina.com.cn/s/blog_66fb0c830100xm5y.html

PS:chkconfigredhat公司遵循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 的系統執行級別:

系統停機狀態

單使用者或系統維護狀態

2~5 多使用者狀態

重新啟動

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[[email protected]~] #chkconfig list |grep tomcat6.0.28    ##檢視tomcat服務是否被新增 

--------------------啟動服務--------------------------------------------- 

11、[[email protected]~] # 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的兩個版本,CentOSUbuntu,需要在兩個版本中都可以開機啟動服務。Ubuntu沒有 /etc/rc.d/init.d這個目錄,所以,為了保持同一種服務在CentOSUbuntu使用的統一性,將服務指令碼(注:服務指令碼在兩個不同版本中是不同的)都放在 /etc/init.d 目錄下,最終達到的效果是相同的。

需要說明的是:在CentOSUbuntu兩個版本中,除了服務指令碼放置的目錄是相同的,服務指令碼的編寫及服務配置都是不同的。比如CentOS使用Chkconfig進行配置,而Ubuntu使用sysv-rc-conf進行配置。

檢視/etc/rc2.d/裡面的apachemysql啟動指令碼,通常都是兩個阿拉伯數字後再接一個英文字母,再加指令碼名稱,例如S20tomcat6.0.28。英文字母是S的都是會自動啟動的,K則相反。所以只要找到apachemysql的啟動指令碼,把S改成K就可以了。

以下命令實現開機啟動或不啟動某服務(真的太像chkconfig了)

sudo sysv-rc-conf 服務名 on(off)

12[[email protected]~] # sudo sysv-rc-conf  off            ##停止tomcat服務 

13[[email protected]~] #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服務就寫好了,你可以在TestJsvcinit(),start(),stop(),destroy()方法裡新增你的業務,做你想做的事。

 

下面講解jsvc 啟動Java Linux下的實現原理

 

jsvc 是在apachedaemon專案下的開源專案,主要功能可以使一些執行在普通使用者下的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 到比較大的值。

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述