(建议收藏)nohup详解、利用systemd工具管理程序,并实现(以java为例)服务开机自启动、利用sh脚本实现java服务开机自启动
一、nohup详解1、什么是nohup?2、nohup案例3、nohup和&两者的区别二、利用systemd工具管理程序,并实现(以java为例)服务开机自启动1、systemd工具介绍①什么是service?②什么是systemctl?2、编写systemctl脚本①编写简单的systemctl脚本②JVM知识扩展:③用systemctl命令,让服务实现开机启动3、systemctl 实现启动、
目录:
二、利用systemd工具管理程序,并实现(以java为例)服务开机自启动
3、systemctl 实现启动、停止、重启、查看运行状态、开机启动、取消开机启动
③ sh脚本的功能说明:启动、停止、重启、查询状态、归档、调试、备份
一、nohup详解
1、什么是nohup?
nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用 nohup 命令运行后台中的程序。要运行后台中的 nohup 命令,添加 & ( 表示“and”的符号)到命令的尾部。
nohup 是 no hang up 的缩写,就是不挂断的意思。
nohup命令:如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。
在缺省情况下该作业的所有输出都被重定向到一个名为nohup.out的文件中。
2、nohup案例
1. nohup python3 main.py >> main.log 2> &1 &
在上面的例子中,0 – stdin (standard input),1 – stdout (standard output),2 – stderr (standard error) ;
2>&1是将标准错误(2)重定向到标准输出(&1),标准输出(&1)再被重定向输入到myout.file文件中。例如nohup command > myout.file 2>error.txt & 那么错误内容会输出到error.txt文件中
2. 0 22 * * * /usr/bin/python /home/pu/download_pdf/download_dfcf_pdf_to_oss.py > /home/pu/download_pdf/download_dfcf_pdf_to_oss.log 2>&1
这是放在crontab中的定时任务,晚上22点时候怕这个任务,启动这个python的脚本,并把日志写在download_dfcf_pdf_to_oss.log文件中
3、nohup和&两者的区别
& : 指在后台运行
nohup : 不挂断的运行,注意并没有后台运行的功能,,就是指,用nohup运行命令可以使命令永久的执行下去,和用户终端没有关系,例如我们断开SSH连接都不会影响他的运行,注意了nohup没有后台运行的意思;&才是后台运行
&是指在后台运行,但当用户推出(挂起)的时候,命令自动也跟着退出
那么,我们可以巧妙的吧他们结合起来用就是
nohup COMMAND &
这样就能使命令永久的在后台执行
例如:
1. sh test.sh &
将sh test.sh任务放到后台 ,即使关闭xshell退出当前session依然继续运行,但标准输出和标准错误信息会丢失(缺少的日志的输出)
将sh test.sh任务放到后台 ,关闭xshell,对应的任务也跟着停止。
2. nohup sh test.sh
将sh test.sh任务放到后台,关闭标准输入,终端不再能够接收任何输入(标准输入),重定向标准输出和标准错误到当前目录下的nohup.out文件,即使关闭xshell退出当前session依然继续运行。
3. nohup sh test.sh &
将sh test.sh任务放到后台,但是依然可以使用标准输入,终端能够接收任何输入,重定向标准输出和标准错误到当前目录下的nohup.out文件,即使关闭xshell退出当前session依然继续运行。
二、利用systemd工具管理程序,并实现(以java为例)服务开机自启动
1、systemd工具介绍
说道systemd工具,不得不提到service命令。它们是Linux服务管理的两种方式service和systemctl。但还是有区别,可以这么说:systemctl基本上是的更强大的版本service。
①什么是service?
service命令是Redhat Linux兼容的发行版中用来控制系统服务的实用工具,它以启动、停止、重新启动和关闭系统服务,还可以显示所有系统服务的当前状态。
service命令实现的原理其实是去/etc/init.d目录下,去执行脚本文件,init.d目录包含许多系统各种服务的启动和停止脚本。当Linux启动时,会寻找这些目录中的服务脚本。
②什么是systemctl?
systemctl是一个systemd工具,主要负责控制systemd系统和服务管理器。
在systemd管理体系中,被管理的deamon(守护进程)称作unit(单元),对于单元的管理是通过命令systemctl来进行控制的。unit表示不同类型的systemd对象,通过配置文件进行标识和配置;文件主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息。
2、编写systemctl脚本
①编写简单的systemctl脚本
编写 test.service 丢到/usr/lib/systemd/system目录下
[Unit]
Description=test.jar包服务程序
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
User=root
Group=root
ExecStart=/opt/jdk1.8.0_161/bin/java -server -Xms1024m -Xmx2048m -Dspring.profiles.active=production -jar /root/test.jar
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
[Install]
WantedBy=multi-user.target
②JVM知识扩展:
/opt/jdk1.8.0_161/bin/java -server -Xms1024m -Xmx2048m -Dspring.profiles.active=production -jar /root/test.jar
JVM调优参数:
-Xms 最小堆的大小, 也就是当你的虚拟机启动后, 就会分配这么大的堆内存给你
-Xmx 是最大堆的大小 ,当最小堆占满后,会尝试进行GCJVM标准参数-server与-client参数的区别:
可以通过-server或-client设置jvm的运行参数。
它们的区别是Server VM的初始堆空间会大一些,默认使用的是并行垃圾回收器,启动慢运行快。
Client VM相对来讲会保守一些,初始堆空间会小一些,使用串行的垃圾回收器,它的目标是为了让JVM的启
动速度更快,但运行速度会比Serverm模式慢些。
JVM在启动的时候会根据硬件和操作系统自动选择使用Server还是Client类型的JVM。32位操作系统
如果是Windows系统,不论硬件配置如何,都默认使用Client类型的JVM。
如果是其他操作系统上,机器配置有2GB以上的内存同时有2个以上CPU的话默认使用server模式,否则
使用client模式。
64位操作系统
只有server类型,不支持client类型。
把service后缀的文件放在指定目录中后,就可以用systemctl 命令来管理程序了!
#启动test.service服务
systemctl start test.service
#查看服务状态
systemctl status test.service
效果如下:
我这里试了试service test status,发现也可以,额,好吧
我重启了一下,发现又用不了了:
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
它的意思是:服务命令只支持基本的LSB操作(启动、停止、重启、尝试重启、重载、强制重载、状态)。对于其他操作,请尝试使用systemctl。
(⊙o⊙)…
在你修改了.service文件后使用systemctl 管理命令,可能会出现警告信息:
Warning: test.service changed on disk. Run 'systemctl daemon-reload' to reload units.
这个时候就要重新加载systemctl配置了,然后就会应用最新的配置。
systemctl daemon-reload
对于那些支持 Systemd 的软件,安装的时候,会自动在/usr/lib/systemd/system目录添加一个配置文件。这个时候你就可以直接用systemctl命令来管理了。
③用systemctl命令,让服务实现开机启动
到第②小节的步骤就已经可以用systemctl 管理命令来管理你自己的程序了,如果你想让该程序开机启动,就执行下面的命令(以test.service为例)。
sudo systemctl enable test
上面的命令相当于在/etc/systemd/system目录添加一个符号链接,指向/usr/lib/systemd/system里面的test.service文件。
这是因为开机时,Systemd只执行 /etc/systemd/system目录里面的配置文件。这也意味着,如果把test.service文件不使用符号链接而是直接放到 /etc/systemd/system目录下,就可以实现开机启动。当然,在 /usr/lib/systemd/system如果没有放 test.service文件就用不了systemctl 命令来管理程序了!
那么,利用systemd工具来实现开机自启动(以java为例),就大功告成了!
3、systemctl 实现启动、停止、重启、查看运行状态、开机启动、取消开机启动
①systemctl 的常用命令:
(注意:systemctl start test 也可以用 systemctl start test.seriver )
#启动test
systemctl start test
#停止test
systemctl stop test
#重启test
systemctl restart test
#查看状态test
systemctl status test
#如果需要开机启动
systemctl enable test
#如果需要取消开机启动
systemctl disable test
#杀进程,向正在运行的进程发出kill信号。
systemctl kill test
#查看test相关的service配置文件
systemctl cat test
##查看 multi-user.target 包含的所有服务
systemctl list-dependencies multi-user.target
#切换到另一个 target,shutdown.target 就是关机状态
sudo systemctl isolate shutdown.target
②顺便扩展一下service的各种管理命令:
service的常用方式:
1.格式:service <service>
打印指定服务<service>的命令行使用帮助。
2.格式:service <service> start
启动指定的系统服务<service>
3.格式:service <service> stop
停止指定的系统服务<service>
4.格式:service <service> restart
重新启动指定的系统服务<service>,即先停止(stop),然后再启动(start)。
5.格式:chkconfig --list
查看系统服务列表,以及每个服务的运行级别。
6.格式:chkconfig <service> on
设置指定服务<service>开机时自动启动。
7.格式:chkconfig <service> off
设置指定服务<service>开机时不自动启动。
8.格式:ntsysv
以全屏幕文本界面设置服务开机时是否自动启动。
打开redis命令:service redis start
关闭redis命令:service redis stop
设为开机启动:chkconfig redis on
三、利用sh脚本实现java服务开机自启动
1、创建sh脚本
请使用下列方式创建sh脚本:server.sh(脚本亲测好用,不用额外配置编辑)
①使用notepad++软件转换成unix格式
使用notepad++打开文件---编辑---文档格式转换---转为unix---上传至linux
② server.sh 脚本代码如下:
#!/bin/bash
# log format function
function log(){
loglevel="$1"
shift
if [ "$1" ];then case "$loglevel" in
debug)
;; # echo -e "\033[35m[$(date "+%Y-%m-%d %H:%M:%S")] [DEBUG]\t${@}\033[0m" ;;
info)
echo -e "\033[32m[$(date "+%Y-%m-%d %H:%M:%S")] [INFO]\t${@}\033[0m" ;;
warning)
echo -e "\033[33m[$(date "+%Y-%m-%d %H:%M:%S")] [WARNING]\t${@}\033[0m" ;;
error)
echo -e "\033[31m[$(date "+%Y-%m-%d %H:%M:%S")] [ERROR]\t${@}\033[0m" ;;
*)
echo "${@}" ;;
esac
fi
}
# Load environment variables
if [ -f "/etc/profile" ]; then
log debug "从 [/etc/profile] 加载环境变量."
. /etc/profile
fi
if [ -f "$HOME/.bash_profile" ]; then
log debug "从 [$HOME/.bash_profile]加载环境变量."
. $HOME/.bash_profile
fi
if [ -f "$HOME/.bashrc" ]; then
log debug "从 [$HOME/.bashrc]加载环境变量."
. $HOME/.bashrc
fi
# Verify that the service is running as a normal user
if [ "$(whoami)" == "root" ]; then
log warning "不推荐使用 [$(whoami)] 用户运行应用服务."
fi
# Verify the java command, otherwise exit directly
if [ ! "$(command -v java)" ];then
log error "未找到java命令,必须先安装JDK或JRE并配置环境变量."; exit 1
fi
# Switch working directory and define variables
cd $(dirname $0)
basedir="$(pwd -P)"
jarfile="$(find $basedir -maxdepth 1 -type f -name "*.jar")"
jarnums="$(find $basedir -maxdepth 1 -type f -name "*.jar"|wc -l)"
logfile="$basedir/log/application.log"
logconf="$basedir/log/logrotate.cnf"
logstat="$basedir/log/logrotate.status"
jarback="$basedir/backup"
log debug "basedir: [$basedir]"
log debug "jarfile: [$jarfile]"
log debug "jarnums: [$jarnums]"
log debug "logfile: [$logfile]"
log debug "logconf: [$logconf]"
log debug "jarback: [$jarback]"
# check jar file exists
function check(){
if [ "$jarnums" -lt "1" ];then
log error "目录 [${basedir}] 下未找到.jar文件."; exit 1
elif [ "$jarnums" -gt "1" ];then
log warning "目录 [${basedir}] 下.jar文件不唯一"; exit 1
else
pid="$(ps -aux|grep "java"|grep "$jarfile"|grep -v "grep"|awk '{print $2}'|tr '\n' ' ')"
fi
}
# status function
function status(){
check
if [ "$pid" ];then
log info "应用服务 [$(basename $jarfile)] 状态: 运行中,PID:[ $pid]."
else
log info "应用服务 [$(basename $jarfile)] 状态: 未运行."
fi
}
# start function
function start(){
check
if [ "$pid" ];then
log warning "应用服务 [$(basename $jarfile)] 已经在运行中, PID: [ $pid]."
else
log info "应用服务 [$(basename $jarfile)] 正在启动..."
log debug "创建应用服务日志目录"
log debug "mkdir -p $basedir/log"
mkdir -p "$basedir/log"
log debug "nohup $(command -v java) -Xms256M -Xmx512M -jar $jarfile $@ >> $logfile 2>&1 &"
nohup $(command -v java) -Xms256M -Xmx512M -jar $jarfile $@ >> $logfile 2>&1 &
pid="$!"
if [ "$pid" ];then
log debug "应用服务 日志轮转开始."
log debug "(while kill -0 $pid;do rotate;sleep 60;done) > /dev/null 2>&1 &"
(while kill -0 $pid;do rotate;sleep 60;done) > /dev/null 2>&1 &
log info "应用服务 [$(basename $jarfile)] 启动完成,PID: [ $pid ]"
log warning "应用服务 [$(basename $jarfile)] 日志输出将在30秒后自动退出."
sleep 3
log debug "应用启动日志: tail -1f $logfile &"
tail -1f $logfile &
(sleep 30 && kill $!) > /dev/null 2>&1 &
log debug "(sleep 60 && kill $!) > /dev/null 2>&1 &"
fi
fi
}
# stop function
function stop(){
check
if [ "$pid" ];then
log info "应用服务 [$(basename $jarfile)] 停止中..."
log debug "kill -9 $pid"
kill -9 $pid > /dev/null 2>&1
sleep 2 && echo
log debug "应用服务 [$(basename $jarfile)] 已经停止"
else
log warning "应用服务 [$(basename $jarfile)] 似乎没有在运行,不需要停止"
fi
}
# restart function
function restart(){
stop
sleep 2
start "$@"
}
# console start function
function console(){
check
if [ "$pid" ];then
log warning "应用服务 [$(basename $jarfile)] 已经在运行中, PID: [ $pid]."
else
log info "应用服务 [$(basename $jarfile)] 正在启动..."
log warning "console 参数仅用于调试, 使用 [Ctrl + C] 终止调试进程."
log debug "创建应用服务日志目录"
log debug "mkdir -p $basedir/log"
mkdir -p "$basedir/log"
sleep 2
log debug "cd $basedir && $(command -v java) -Xms256M -Xmx512M -jar $jarfile $@ 2>&1 | tee $logfile"
cd $basedir && $(command -v java) -Xms256M -Xmx512M -jar $jarfile $@ 2>&1 | tee $logfile
fi
}
# rotate function
function rotate(){
log debug "创建应用服务日志目录"
log debug "mkdir -p $basedir/log"
mkdir -p "$basedir/log"
if [ ! -e $logconf ];then
log warning "日志轮转配置文件 [${logconf}] 不存在, 将创建此配置文件."
log debug "${logfile} {\n size 32M\n rotate 16\n compress\n missingok\n dateext\n dateformat -%Y%m%d-%s\n copytruncate\n}"
echo -e "${logfile} {\n size 32M\n rotate 16\n compress\n missingok\n dateext\n dateformat -%Y%m%d-%s\n copytruncate\n}" > $logconf
fi
if [ -e $logfile ];then
log info "归档并压缩应用服务日志 [${logfile}]"
log debug "/usr/sbin/logrotate -s $logstat $logconf"
/usr/sbin/logrotate -s $logstat $logconf
log info "归档并压缩日志文件 ${logfile} 完成."
log debug "使用 [ll -h ${logfile}*] 命令查看归档日志文件"
fi
}
# backup function
function backup(){
if [ ! -d "$jarback" ];then
log warning "创建jar包备份目录 [$jarback]"
log debug "mkdir -p $jarback"
mkdir -p $jarback
fi
jarbasename="$(basename $jarfile)"
jarbackname="${jarbasename%.*}-$(date "+%Y%m%d-%H%M%S").${jarbasename##*.}"
log debug "应用服务 备份jar包目录 [$jarback]"
log debug "应用服务 备份jar包名称 [$jarback/$jarbackname]"
log info "备份jar包文件 [$jarfile]"
log info " ==> jar包备份目录 [$jarback]"
cp $basedir/$jarbasename $jarback/$jarbackname
}
# help
function help(){
log "" "使用说明:"
log "" " $0 {start|stop|status|restart|console|backup|rotate} [options]"
log "" " [options] : "
log "" " --spring.config.location=app.yml,app-ext.yml # 指定服务配置文件为: app.yml,app-ext.yml"
log "" " --spring.profiles.active=development # 指定服务配置环境为: development"
log "" " --server.port=8888 # 指定服务配置端口为: 8888"
log "" " --server.servlet.context-path=/test # 指定服务配置路径为: /text"
}
act="$1"
shift
arg="$(echo "$@"|sed 's/[ ]*=[ ]*/=/g')"
log debug "Script parameters [ $act ]"
case "$act" in
start)
start $arg ;;
stop)
stop ;;
restart)
restart $arg ;;
status)
status ;;
rotate )
rotate ;;
console)
console $arg ;;
backup)
backup ;;
*)
start $arg ;;
esac
exit 0
注意:文件都要设置为可执行文件:
sudo chmod 755 server.sh
因为脚本会自动获取当前目录可运行的jar包,所以在当前目录下请保持仅有一个包;
③ sh脚本的功能说明:启动、停止、重启、查询状态、归档、调试、备份
脚本功能介绍:
./server.sh 默认执行./server.sh start ========》启动当前目录java程序
./server.sh stop 默认执行./server.sh start ========》启动当前目录java程序
./server.sh restart ========》重启程序
./server.sh status ========》查询程序运行状态
./server.sh rotate ========》归档日志
./server.sh console ========》前台运行程序,[Ctrl + C] 会终止进程
./server.sh backup ========》备份jar包文件
2、编辑系统rc.local文件,让脚本加入系统开机启动
在上面的第一步就可以使用脚本来管理程序了,接下来是让脚本加入到系统的开机启动
记录当前server.sh脚本的路径,编辑/etc/rc.d/rc.local。命令如下:
cd /etc/rc.d
vi rc.local
#!/bin/bash
# THIS FILE IS ADDED FOR COMPATIBILITY PURPOSES
#
# It is highly advisable to create own systemd services or udev rules
# to run scripts during boot instead of using this file.
#
# In contrast to previous versions due to parallel execution during boot
# this script will NOT be run after all other services.
#
# Please note that you must run 'chmod +x /etc/rc.d/rc.local' to ensure
# that this script will be executed during boot.
#就是说rc.local的程序已经启动了, 防止重复运行
touch /var/lock/subsys/local
#脚本的绝对路径
/root/server.sh
注意:rc.local文件要授权:sudo chmod 755 rc.local
3、系统重启,查看效果
sudo reboot
查看java程序:
ps -ef | grep java
可以看到:
大功告成!
欢迎点赞收藏,有问题请在评论区告诉我~
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)