java:使用supervisor优雅的管理SpringBoot进程

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: java:使用supervisor优雅的管理SpringBoot进程

目录

1、创建 SpringBoot 项目

通过 https://start.spring.io/ 创建一个 SpringBoot 项目

项目结构

$ tree -I target
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── example
    │   │           └── demo
    │   │               ├── Application.java
    │   │               └── controller
    │   │                   └── IndexController.java
    │   └── resources
    │       ├── application.properties
    │       ├── static
    │       └── templates
    └── test
        └── java
            └── com
                └── example
                    └── demo
                        └── ApplicationTests.java

完整依赖 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

项目启动类 Application.java

package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

控制器 IndexController.java

package com.example.demo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class IndexController {
    @GetMapping("/")
    public String index() {
        log.info("IndexController");
        return "Hello";
    }
}

2、手工部署项目

# 打包
$ mvn package
# 上传,此处上传至docker
$ docker cp target/demo-0.0.1-SNAPSHOT.jar centos7:/usr/local
# 运行
java -jar /usr/local/demo-0.0.1-SNAPSHOT.jar

查看容器端口号映射

$ docker port centos7
3306/tcp -> 0.0.0.0:8086
8080/tcp -> 0.0.0.0:8082

所以我们通过 8082 端口就可以访问到容器中的 SpringBoot 项目

http://localhost:8082/

如果在 Linux 环境,需要检查防火墙是否开放 8080 端口

firewall-cmd --zone=public --list-ports

3、部署优化

  • 后台运行
  • 日志输出到文件

nohup 不挂断运行

英文全称:no hang up

语法

nohup command [args...] [&]

参数说明

  • command 要执行的命令
  • args 参数
  • & 让命令后台运行

举例

# 后台运行java -jar命令,并将日志输出到文件hello.log
nohup java -jar demo-0.0.1-SNAPSHOT.jar &> hello.log &
# 查看日志
tail -f hello.log

停止 SpringBoot 程序

# 查找进程
ps -ef | grep 'java -jar'
# 结束进程
kill -9 <pid>

4、通过 shell 脚本自动部署项目

自动部署步骤

  1. 在 Linux 中安装 Git
  2. 在 Linux 中安装 maven
  3. 编写 shell 脚本(拉取代码、编译、打包、启动)
  4. 为用户授予执行 shell 脚本的权限
  5. 执行 shell 脚本

代码操作过程

本地开发环境
    -- push -->
Git仓库
    -- pull -->
Linux服务器

4.1、在 Linux 安装 Git

通过yum安装git

# 搜索git
yum list git
# 安装git
yum install -y git

克隆代码

cd /usr/local
git clone https://gitee.com/mouday/helloworld.git

4.2、在 Linux 安装 Maven

下载地址

https://maven.apache.org/download.cgi

安装步骤

# 1、下载解压
wget https://dlcdn.apache.org/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.tar.gz
tar -zxvf apache-maven-3.8.6-bin.tar.gz
# 2、添加环境变量
vim /etc/profile.d/env.sh
# maven
export MAVEN_HOME=/usr/local/apache-maven-3.8.6
export PATH=$PATH:$MAVEN_HOME/bin
# 3、执行生效
source /etc/profile.d/env.sh
# 4、查看版本号
mvn -version
Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /usr/local/apache-maven-3.8.6
Java version: 1.8.0_351, vendor: Oracle Corporation, runtime: /usr/local/jdk1.8.0_351/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "4.19.76-linuxkit", arch: "amd64", family: "unix"
# 5、修改配置
vim /usr/local/apache-maven-3.8.6/conf/settings.xml
<localRepository>/usr/local/repo</localRepository>

4.3、为用户授权

chmod 全称:change mode 控制用户对文件权限

  • 权限:读 r、写 w、执行 x
  • 调用权限:文件所有者(owner)、用户组 group、其他用户 other users
  • 只有文件的所有者和超级用户可以修改文件或目录的权限
- rwx rwx rwx
文件类型 -/d
owner
group
other users

4.4、执行 shell 脚本

bootstart.sh

#!/usr/bin/bash
# 项目名
APP_NAME=demo-0.0.1-SNAPSHOT.jar
# 1、停止运行中的项目
tpid=`ps -ef | grep ${APP_NAME} | grep -v grep | grep -v 'kill' | awk '{print $2}'`
if [[ ${tpid} ]]; then
    kill -15 ${tpid}
fi
sleep 2
tpid=`ps -ef | grep ${APP_NAME} | grep -v grep | grep -v 'kill' | awk '{print $2}'`
if [[ ${tpid} ]]; then
    kill -9 ${tpid}
fi
# 2、拉取代码
cd /usr/local/helloworld
git pull
# 3、打包
output=`mvn clean package -Dmaven.test.skip=true`
# 4、启动
nohup java -jar target/${APP_NAME} &> hello.log &
echo "启动/重启完成"

5、supervisor来管理进程

管理SpringBoot进程的方式

  • 通过nohup启动后台进程
  • 通过service/systemctl系统服务管理进程
  • 通过Python包supervisor管理进程
  • 通过Node.js包pm2管理进程

使用shell脚本的方式,不能很好的管理进程,如果进程挂掉也不会自动重启

可以采用 systemctl + supervisor的方式管理进程

  • systemctl 管理 supervisor
  • supervisor管理用户进程(SpringBoot)

一般情况下,系统都会自带Python2.7,所以我们采用Python包supervisor管理SpringBoot进程

5.1、检查Python环境

supervisor同时支持Python2.7和Python3

python -V
Python 2.7.5

5.2、检查pip

pip -V
pip 20.3.4 from /usr/lib/python2.7/site-packages/pip (python 2.7)
# 如果不存在就安装
# Python2.7
wget https://bootstrap.pypa.io/pip/2.7/get-pip.py
# 安装
python get-pip.py

5.3、安装supervisor

文档

pip install supervisor

生成配置文件

# 生成配置文件目录
mkdir -p /etc/supervisor/conf.d
# 初始化配置文件
echo_supervisord_conf > /etc/supervisor/supervisord.conf

修改配置

vim /etc/supervisor/supervisord.conf

下面几项是必须修改的

[unix_http_server]
;file=/tmp/supervisor.sock   ; (the path to the socket file)
file=/var/run/supervisor.sock ; 修改为 /var/run 目录,避免被系统删除
[supervisord]
;logfile=/tmp/supervisord.log ; (main log file;default $CWD/supervisord.log)
logfile=/var/log/supervisor.log ; 修改为 /var/log 目录,避免被系统删除
;pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
pidfile=/var/run/supervisord.pid ; 修改为 /var/run 目录,避免被系统删除
[supervisorctl]
; 必须和'unix_http_server'里面的设定匹配
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
serverurl=unix:///var/run/supervisor.sock ; 修改为 /var/run 目录,避免被系统删除
[include]
;指定应用程序配置文件目录
;files = relative/directory/*.ini
files = conf.d/*.ini

管理命令

# 查看supervisor监管的进程状态
supervisorctl status
# 启动XXX进程
supervisorctl start 进程名
# 停止XXX进程
supervisorctl stop 进程名
# 停止全部进程,注:start、restart、stop都不会载入最新的配置文件。
supervisorctl stop all
# 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl update
# 查看日志
supervisorctl tail -f spring-boot

5.4、开机启动

新建文件 supervisord.service

# supervisord.service
[Unit] 
Description=Supervisor daemon
[Service] 
Type=forking 
ExecStart=/usr/bin/supervisord -c /etc/supervisor/supervisord.conf
ExecStop=/usr/bin/supervisorctl shutdown 
ExecReload=/usr/bin/supervisorctl reload 
KillMode=process
Restart=on-failure
RestartSec=42s
[Install] 
WantedBy=multi-user.target

启动服务

cp supervisord.service /usr/lib/systemd/system/
# 开机启动服务
systemctl enable supervisord      
# 验证一下是否为开机启动
systemctl is-enabled supervisord  
# 启动服务
systemctl start supervisord
systemctl status supervisord
systemctl stop supervisord

5.5、添加www用户组和用户

一般不能以root用户来运行程序,需要单独的一个用户来运行线上程序

# 添加用户组
$ groupadd www
# 添加用户
$ useradd -g www -s /sbin/nologin www
# 查看用户
$ id www
uid=1000(www) gid=1000(www) groups=1000(www)
# 或者
$ cat /etc/group
$ cat /etc/passwd
# 赋予权限
chown -R www:www helloworld
# 查看文件属性
ls -lh
drwxr-xr-x  5 www  www   4.0K Dec 30 03:34 helloworld

5.6、项目启动配置

supervisor.conf

[program:spring-boot]
;应用启动目录
directory=/usr/local/helloworld
;使用绝对路径
command=/usr/local/jdk1.8.0_351/bin/java -jar target/demo-0.0.1-SNAPSHOT.jar
;运行用户
user=www

启动进程

# 生成软链
ln -s /usr/local/helloworld/supervisor.conf /etc/supervisor/conf.d/spring-boot.conf
# 更新配置文件
supervisorctl update
# status查看进程
supervisorctl status
spring-boot                      RUNNING   pid 238, uptime 0:21:31
# 查看运行进程
ps -ef|grep java
www        238    87 57 05:33 ?        00:00:10 /usr/local/jdk1.8.0_351/bin/java -jar target/demo-0.0.1-SNAPSHOT.jar

参考 Python编程:supervisor模块管理进程实例

6、通过Makefile整合命令

上面涉及到了很多命令,如果都记住有点困难

使用Makefile文件或者shell都可以整合命令

安装make

yum install -y make

Makefile 文件

# 操作命令
# 拉取代码
.PHONY: pull
pull:
  git pull
# maven打包
.PHONY: build
build:
  mvn clean package -Dmaven.test.skip=true
# 重启进程
.PHONY: restart
restart:
  supervisorctl restart spring-boot
# 启动进程
.PHONY: start
start:
  supervisorctl start spring-boot
# 停止进程
.PHONY: stop
stop:
  supervisorctl stop spring-boot
# 日志
.PHONY: log
log:
  supervisorctl tail -f spring-boot
# 部署
.PHONY: deploy
deploy:
  make pull
  make build
  make restart

重新部署项目

make deploy


相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
24天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
46 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
12天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
69 13
|
13天前
|
Java 对象存储 开发者
如何找出Java进程占用CPU高的元凶
本文记录了一次Java进程CPU占用率过高的问题和排查思路。
|
20天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
Java
java小知识—进程和线程
进程 进程是程序的一次执行过程,是系统运行的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程 线程,与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比
29 1
|
2月前
|
JavaScript 前端开发 Java
解决跨域问题大集合:vue-cli项目 和 java/springboot(6种方式) 两端解决(完美解决)
这篇文章详细介绍了如何在前端Vue项目和后端Spring Boot项目中通过多种方式解决跨域问题。
402 1
解决跨域问题大集合:vue-cli项目 和 java/springboot(6种方式) 两端解决(完美解决)
|
1月前
|
监控 前端开发 Java
Java SpringBoot –性能分析与调优
Java SpringBoot –性能分析与调优
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
119 2
|
2月前
|
Java 关系型数据库 MySQL
java控制Windows进程,服务管理器项目
本文介绍了如何使用Java的`Runtime`和`Process`类来控制Windows进程,包括执行命令、读取进程输出和错误流以及等待进程完成,并提供了一个简单的服务管理器项目示例。
44 1