javaweb问题集锦: java服务使用linux命令重启自身服务

一.前言

      最近server服务隔个两天就出现"卡死"的现象,   必须要手动重启服务,   才能正常使用;  后来各种查日志, 查百度,可以复现问题, 主要原因是Hikari数据库连接池中的连接用完了,   其他Client 访问Server中的API时候, 一直在等待Hikari连接, 出现了超时的现象;

只能通过暴力重启server服务,释放连接,API接口才能正常访问;  百度了一圈,解决这种问题方案总结如下:

    1.增加服务器硬件配置,  从而增大Hikari pool size , 优化Hikari参数配置, 参考HikariCP 连接池配多大合适

    2.Server API接口优化, 优化sql语句,限制sql语句查询条件,比如time, limit,等;   限制接口频繁调用等等;

    3.Server服务负载均衡,并发优化等(好高端,目前还没有涉及到)

    4.服务器自己检测自己API接口,出现超时,自动重启服务器

接下来这篇文章,就讲讲JAVA服务怎么使用linux命令重启自身服务,中间遇到了多少坑,流下了多少猿泪!

二.linux执行重启java服务脚本

     由于对linux脚本不是很熟悉,  在网上加了一个qq群,  感谢群里的"小科"大神, 帮我写了一个重启脚本,   还帮我分析了一下午问题,最后按照"小科"大神提供的线索"进程"问题,  顺藤摸瓜,  终于解决问题!   在此感谢素昧相识的"小科"大神,  好人一生平安!

将此脚本文件放在服务器文件夹中, 最好放在你程序的目录中,  这样不会出现环境,路径的问题;

    restart.sh

#!/bin/bash
#Time: 2018-12-21 13:36:19

PID=`netstat -nlpt|grep -w "8082"|awk '{print $7}'|grep -oE "[0-9]+"`
if [ -z ${PID} ];then
    echo "进程不存在!开始重新启动。。" 
    nohup java -Dlog4j.configurationFile=log4j2.xml -Dvertx.disableDnsResolver=true  -Dio.vertx.ext.auth.prng.algorithm=NativePRNGNonBlocking  -jar mx-appserver-1.1-fat.jar -conf config.json & 2>&1
else
    echo "开始结束${PID}进程,重新启动。。。"
    kill -9 ${PID}
    nohup java -Dlog4j.configurationFile=log4j2.xml -Dvertx.disableDnsResolver=true  -Dio.vertx.ext.auth.prng.algorithm=NativePRNGNonBlocking  -jar mx-appserver-1.1-fat.jar -conf config.json & 2>&1
fi

三.Java程序中执行linux命令,调用restart.sh脚本,重启自身

     参考链接在java程序中开启另一个java程序

     参考链接Java执行shell遇到的各种问题

     方法一:可以正常执行linux  restart.sh脚本文件  ,但是日志文件不能持续输出和保存

主要运用  Runtime.getRuntime().exec(command) 执行linux命令

    private void executeCmd() {
        try {
            String cmd = "restart.sh";
            //String[] command = {"/bin/sh", "-c", cmd};
            String[] command = {"/bin/sh", cmd};
            //String[] command = {"/bin/nohup","sh", cmd, "&"};
            System.out.println("sout服务器重启response data:" +Arrays.toString(command));
            _LOG.info("服务器重启request data:{}" , Arrays.toString(command));
            Process ps = Runtime.getRuntime().exec(command);
            BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
            StringBuffer sb = new StringBuffer();
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            String result = sb.toString();
            System.out.println("sout服务器重启response data:" + result);
            _LOG.error("服务器重启response data:" + result);
        } catch (IOException e) {
            _LOG.error("execute(Tuple, BasicOutputCollector)", e);
            e.printStackTrace();
        }
    }

     方法二: 可以正常执行linux  restart.sh脚本文件  ,但是日志文件不能持续输出和保存

主要运用  ProcessBuilder pb = new ProcessBuilder("nohup","sh","restart.sh","&");执行linux命令

    private void executeCmd2() {
        try {
            String cmd = "restart.sh";
            //String[] command = {"/bin/sh", "-c", cmd};
            String[] command = {"/bin/sh", cmd};
            //String[] command = {"/bin/nohup","sh", cmd, "&"};
            System.out.println("sout服务器重启response data:" +Arrays.toString(command));
            _LOG.info("服务器重启request data:{}" , Arrays.toString(command));
            ProcessBuilder pb = new ProcessBuilder("nohup","sh","restart.sh","&");
            pb.start();
        } catch (IOException e) {
            _LOG.error("execute(Tuple, BasicOutputCollector)", e);
            e.printStackTrace();
        }
    }

    方法三: 可以正常执行linux  restart.sh脚本文件  ,日志文件nohup.out可以正常输出和保存

主要涉及到linux程序进程问题 File是你的日志文件

    private void executeCmd3() {
        // 不使用Runtime.getRuntime().exec(command)的方式,因为无法设置以下特性
        // Java执行本地命令是启用一个子进程处理,默认情况下子进程与父进程I/O通过管道相连(默认ProcessBuilder.Redirect.PIPE)
        // 当服务执行自身重启的命令时,父进程关闭导致管道连接中断,将导致子进程也崩溃,从而无法完成后续的启动
        // 解决方式,(1)设置子进程IO输出重定向到指定文件;(2)设置属性子进程的I/O源或目标将与当前进程的相同,两者相互独立
        try {
            File file = null;
            ProcessBuilder pb = new ProcessBuilder("sh","restart.sh");
            if (file == null || !file.exists()) {
                // 设置属性子进程的I/O源或目标将与当前进程的相同,两者相互独立
                pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
                pb.redirectError(ProcessBuilder.Redirect.INHERIT);
                pb.redirectInput(ProcessBuilder.Redirect.INHERIT);
            } else {
                // 设置子进程IO输出重定向到指定文件
                // 错误输出与标准输出,输出到一块
                pb.redirectErrorStream(true);
                // 设置输出日志
                pb.redirectOutput(ProcessBuilder.Redirect.appendTo(file));
            }
            // 执行命令进程
            pb.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

最后采取的是方法三,可以正常重启自己,并且日志正常写入和输出!

每个项目的环境及需求不一样,所以此篇文章只是记录我的环境下的解决方法,  大家可以参考,  万变不离其宗!

猜你喜欢

转载自blog.csdn.net/mawei7510/article/details/85232114