JAVA执行远端服务器的脚本
问题描述
工作中遇到这样一个问题,我们的应用为了实现高可用会采取双机部署,拓扑图大致如下:

这种方案可以简单的保证高可用,即便应用服务器或者数据库服务器其中一台宕机,整个系统的功能还是不会受到影响,但是这里会出现一个问题:例如当应用服务器1宕机了,所有的负载集中到应用服务器2上以后,因为系统功能是正常的,而作为产品交付客户后也没有现场的实施或运维人员在,我们并不知道有一台服务器已经宕机了,所以,我们要实现一个简单的监控,去查看每个服务器上的每个应用程序是否正常的启动着,当异常的时候可以通过网页重新启动一下.
实现思路
在我们的数据库中建立两张表,一张服务器表,一张应用表,服务器表作为主表
在服务器对应位置为每一个需要监控的应用放置一个监控的SHELL脚本,一个重启的SHELL脚本
在WEB服务中增加定时任务,采用轮询的方式执行监控脚本,如果返回值正常,则更新应用表中的状态字段,同时在WEB页面中加入一个监控页面,可以在应用状态异常的通过按钮点击完成重启操作
技术要点
基本的增删改查并没有什么问题,在我的设计思路中有两个点需要注意
- SHELL脚本的编写
这个领域我并不了解,交由负责实施的同事解决 - JAVA任务调度
这部分我可能会单独写一篇博客来记录一下我自己学习Spring Boot中的 @Scheduled注解和比较常用的Quartz框架的过程和对比 - JAVA链接服务器并执行SHELL
这里我采用的依赖包是:
<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>262</version>
</dependency>
在有了这个依赖包之后,我就只用提供两个共通的工具方法就可以了,一个是登录一下服务器,看看服务器是否宕机,一个是执行SELL脚本的方法,根据SHELL的返回值确定监控的服务是否正常的方法就好了
代码实现
因为执行SHELL脚本的时候可能是给出正常的返回值,也可能是异常的信息,这里需要一个JAVA Bean来接收这两个消息,代码如下:
import java.io.Serializable;
/**
* shell脚本执行结果<br/>
* 先通过getSuccess方法判断命令是否执行成功<br/>
* 执行成功的时候采用result作为返回值<br/>
* 执行不成功采用errorOut作为返回值<br/>
*
* @author weizj
*/
public class ShellResult implements Serializable {
private static final long serialVersionUID = -110281463872334425L;
/** 脚本输出结果 */
private String result;
/** 异常输出结果 */
private String errorMsg;
/** 回话退出状态 */
private int exitStatus;
public ShellResult() {
}
public ShellResult(String result, String errorOut, int exitStatus) {
this.result = result.trim();
this.errorMsg = errorOut.trim();
this.exitStatus = exitStatus;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result.trim();
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg.trim();
}
public int getExitStatus() {
return exitStatus;
}
public void setExitStatus(int exitStatus) {
this.exitStatus = exitStatus;
}
/** 是否成功关闭会话 */
public boolean getSuccess() {
return this.exitStatus == 0;
}
}
工具类方法代码如下:
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* java执行shell脚本的工具类
*
* @author weizj
*/
public class GanymedUtils {
private static final Logger logger = LoggerFactory.getLogger(GanymedUtils.class);
/** 超时时间 */
private static final int TIME_OUT = 1000 * 5 * 60;
/**
* 登录远端服务器
*
* @param ip 主机地址
* @param userName 用户名
* @param password 密码
* @return 当前的连接
* @throws IOException
*/
public static Connection login(String ip, String userName, String password) throws IOException {
Connection connection = new Connection(ip);
connection.connect();
return connection.authenticateWithPassword(userName, password) ? connection : null;
}
/**
* 执行一个命令
*
* @param ip 主机ip
* @param userName 用户名
* @param password 密码
* @param scripts 需要执行的脚本
* @param charset 字符编码
* @return ShellResult类
* @throws Exception
*/
public static ShellResult exec(String ip, String userName, String password, String scripts, Charset charset) throws IOException {
Connection connection = login(ip, userName, password);
if (connection == null) {
throw new RuntimeException("登录远程服务器出现异常,ip为:" + ip);
}
// Open a new {@link Session} on this connection
Session session = connection.openSession();
try (InputStream stdOut = new StreamGobbler(session.getStdout()); InputStream stdErr = new StreamGobbler(session.getStderr())) {
// Execute a command on the remote machine.
session.execCommand(scripts);
String outStr = processStream(stdOut, charset.name());
String outErr = processStream(stdErr, charset.name());
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
int exitStatus = session.getExitStatus();
return new ShellResult(outStr, outErr, exitStatus);
}
}
/**
* 执行脚本
*
* @param in 输入流
* @param charset 字符编码
* @return
* @throws IOException
*/
private static String processStream(InputStream in, String charset) throws IOException {
byte[] buf = new byte[1024];
StringBuilder sb = new StringBuilder();
while (in.read(buf) != -1) {
sb.append(new String(buf, charset));
}
return sb.toString();
}
public static void main(String[] args) {
try {
ShellResult status = exec("10.0.0.1", "root", "root", "ipconfig", StandardCharsets.UTF_8);
System.out.println(">>>>>>Result>>>>>>>");
System.out.println(status.getResult());
System.out.println(">>>>>>ErrorMsg>>>>>>>>");
System.out.println(status.getErrorMsg());
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过这两个类再配合任务调度就可以基本的实现对应用的监控了.
JAVA执行远端服务器的脚本的更多相关文章
- java执行hive命令或者脚本
java执行脚本 import java.io.*; import java.text.DateFormat; import java.text.SimpleDateFormat; import ja ...
- Jenkins执行远程服务器的脚本-Hudson SCP publisher plugin插件
1.搜索插件 2.配置远程服务器账号密码 3.配置远程服务器 4.构建配置
- java远程执行linux服务器上的shell脚本
业务场景:需要从服务器A中新增的文件同步至本地服务器,服务器A中内存有限,需同步成功之后清除文件. Java调用远程shell脚本,需要和远程服务器建立ssh链接,再调用指定的shell脚本. 1.创 ...
- Java代码调用服务器上的Shell脚本
Java代码调用服务器上的Shell脚本 这里主要是因为我们报表平台有用到用户手工录入的数据作为结果数据且需要纳入saiku去展示 如我们所知,saiku不会自动刷新,所以需要在数据更新接口中调用服务 ...
- Java执行Dos-Shell脚本
Java执行Dos-Shell脚本 1.介绍 2.调用shell脚本 2.1 获取键盘输入 2.2 构建指令 2.3 Java代码 3.Java调用Shell并传入参数 4.Java调用远程的Shel ...
- java ssh远程服务器并执行多条shell命令
java ssh远程服务器并执行多条命令 import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...
- Java 执行 SQL 脚本文件
转自:http://blog.csdn.net/hongmin118/article/details/4588941 package com.unmi.db; import java.io.FileI ...
- Java执行JavaScript脚本破解encodeInp()加密
一:背景 在模拟登录某网站时遇到了用户名和密码被JS进行加密提交的问题,如图: 二:解决方法 1.我们首先需要获得该JS加密函数,一般如下: conwork.js var keyStr = " ...
- java执行shell脚本并输出执行情况
1.脚本test.sh,置于/Users/hdwang目录下 #!/bin/sh cd /Users/hdwang echo ls:`ls` ;i<=;i++)); do + ); sleep ...
随机推荐
- ARTS打卡计划第一周-Review
本周分享的文章来自于medium的 Testing Best Practices for Java + Spring Apps 这个文章主要讲的是java测试的一些最佳实践 1.避免函数返回void, ...
- JS应用猜数游戏
(function(){ let rs = require("readline-sync"); let guessNumber = new Set(); function getN ...
- CSS 背景图像 填充整个页面示例
background-image 属性可以设置背景图像. 背景图像可以填充整个页面的,也可以填写一部分. background-image 属性的使用很简单:background-image:url( ...
- jQuery-UI的使用
使用效果图: 源码: <!DOCTYPE html><html lang="en"><head> <meta charset=" ...
- program_options
[program_options] The program_options library allows program developers to obtain program options, t ...
- Python Selenium系列学习
以下记录刚接触Python Selenium操作Web UI的学习问题: 1.python selenium三种等待方式: ①强制等待:time.sleep(value):设置等待最简单的方法就是强制 ...
- (3)Linux的哲学思想
1. 一切皆文件 把几乎所有资源统统抽象为文件形式,包括硬件设备,甚至通信接口等,便于统一管理和定义: 对文件的操作有:open,read,write,close,delete,create 2. 由 ...
- django xadmin查找当前用户所在组
self.request.user:获取当前登录用户用户名 qs = Group.objects.get(user=self.request.user)获取当前登录用户所在组qs.name 获取当前登 ...
- Python中的计时器对象
计时器对象用于特定时间运行的操作.往往被安排到特定的单独的线程上运行, 但是计时器初始化的时间间隔可能不是解释器实际执行操作时的实际时刻, 因为线程调度程序负责实际调度与计时器对象相对应的线程. Ti ...
- Linux静态设置CentOS 7虚拟机的IP
进入root ,输入命令:# vi /etc/sysconfig/network-scripts/ifcfg-ens33 .将DHCP协议获取IP,改为static静态,加上想要设置的IPADDR即可 ...