1. nohup及2>&1的用法
当我们在Linux服务器上使用类似于./start.sh
的脚本启动服务后,控制台会停留在服务启动后的输出状态下,此时如果点击Ctrl + C或当SSH连接断开后启动的服务也会直接停掉。其实在这种情况下,我们可以使用nohup
命令启动脚本,比如./start.sh >> nohup.log 2>&1 &
,在这种模式下,服务启动后会在后台运行,不会停止,且命令行也会直接回到等待输入的状态。nohup
命令的解释如下:
- 用途:不挂断地运行命令。
- 语法:nohup Command [ Arg … ] [ & ]
- 描述:nohup命令运行由Command参数和任何相关的Arg参数指定的命令,忽略所有挂断(SIGHUP)信号。在注销后使用nohup命令运行后台中的程序。要运行后台中的nohup命令,添加&( 表示“and”的符号)到命令的尾部。
在操作系统中有三个常用的流,分别用0、1、2三个数字代替:
- 0:标准输入流,即stdin
- 1:标准输出流,即stdout
- 2:标准错误流,即stderr
一般当我们用> console.log
,实际是1 > console.log
的省略用法;< console.log
,实际是0 < console.log
的省略用法;>>
也类似。
所以在上面的命令./start.sh >> nohup.log 2>&1 &
,有如下解释:
- 使用
&
结尾的命令启动的脚本服务,即使Terminal(终端)关闭后依然会保持运行; >> nohup.log
实际是1 >> nohup.log
的省略用法,即将标准输出追加到当前路径下nohup.log文件中;2>&1
的意思是把标准错误(2)重定向到标准输出中(1),而标准输出又输出到文件nohup.log里面,所以结果是将标准错误和标准输出都输出到文件nohup.log里面了。至于为什么需要将标准错误重定向到标准输出的原因,那是因为标准错误stderr没有缓冲区,而stdout有。这就会导致> nohup.log
和2 > nohup.log
中的文件nohup.log被两次打开,而stdout和stderr将会竞争覆盖,这是错误的做法。
扩展:
/dev/null
文件的作用,这是一个无底洞,任何东西都可以定向到这里,但是却无法打开。所以一般当存在很大的stdou和stderr无用输出时,可以利用stdout和stderr定向到这里,如./command.sh > /dev/null 2>&1
。
2. service和systemctl命令
主流的Linux大多使用init.d或systemd来注册服务。
以CentOS 6.6为例,使用init.d部署和注册服务的使用方式如下:
首先将Java程序打成jar包,在build.gradle配置文件中加spring-boot-gradle-plugin插件,具体配置如下(配置完成后刷新gradle项目):
- plugins {
- id 'org.springframework.boot' version '1.5.4.RELEASE'
- }
- springBoot {
- executable = true
- }
然后在build.gradle所在的目录下运行命令gradle build
进行打包,假设我们的项目名为test,此时在/build/libs目录下应该会有test.jar和test.jar.original两个jar包;test.jar是Java程序的可执行jar包,里面含有程序所用的依赖包
然后打成的test.jar包上传到服务器,例如路径/var/app/下,然后使用命令chmod +x test.jar
将jar包设置成可执行文件。
接下来需要在在/etc/init.d下创建软链接:
- $ sudo ln -s /var/app/test.jar /etc/init.d/test
其中test就是服务名,此时就可以使用service命令来管理服务了:
service test start
:启动服务service test stop
:停止服务service test status
:服务状态chkconfig test on
:开机启动
如果出现unable to find java
提示信息,则说明缺少JAVA_HOME环境属性,可以设置服务器的环境变量,也可以制定配置文件;制定配置文件名必须和jar包的文件名相同,后缀必须是.conf
,即本例中可以使用test.conf
,将test.conf
文件和jar文件放在同一目录下,然后在其中写入JAVA_HOME的路径内容如下:
- JAVA_HOME=/opt/jdk1.8.0_121
以CentOS 7.1为例,使用systemd部署和注册服务的使用方式如下:
在/usr/lib/systemd/system/目录下新建文件test.service,填入下面内容:
- [Unit]
- Description=Test Systemctl Service Use Java
- Documentation=https://blog.coderap.com
- After=network.target
- [Service]
- User=centos
- #Type=forking
- PIDFile=/run/test.pid
- ExecStart=/bin/sh -c '/usr/bin/java -jar /var/app/test.jar >> /var/log/test.log 2>&1'
- SuccessExitStatus=143
- TimeoutStopSec=10
- Restart=on-failure
- RestartSec=5
- [Install]
- WantedBy=multi-user.target
这里需要注意的是,我们是使用centos用户来启动服务的,因此需要将test.jar和test.log两个文件的拥有者和拥有者组修改为centos
,使用命令chown centos:centos /var/app/test.jar
和chown centos:centos /var/log/test.log
。
设置之后,就可以使用systemctl命令来管理服务了:
systemctl start test
或systemctl start test.service
:启动服务systemctl stop test
或systemctl stop test.service
:停止服务systemctl status test
或systemctl status test.service
:服务状态systemctl enable test
或systemctl enable test.service
:开机启动journalctl -u test
或journalctl -u test.service
:查看服务日志
推荐阅读
Java多线程 46 - ScheduledThreadPoolExecutor详解(2)
ScheduledThreadPoolExecutor用于执行周期性或延时性的定时任务,它是在ThreadPoolExe...