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 ...
随机推荐
- [原创]如果软件在网络磁盘中或移动磁盘中运行时需要解决 exception C0000006 异常问题
//如果软件在网络磁盘中或移动磁盘中运行时需要利用下面这句命令来解决 exception C0000006 异常问题 {$SetPEFlags IMAGE_FILE_REMOVABLE_RUN_FRO ...
- PeopleSoft通过status汇总进程运行情况
下面SQL可以按照run_status汇总进程的运行状态 SELECT RQST.RUNSTATUS, RQST.PRCSTYPE, (SELECT XLAT.XLATLONGNAME FROM PS ...
- CentOS6.3上搭建expect无交互开发环境
1.背景 在面向shell编程时对于需要交互的场合则必须通过人工来干预,而对于这种方式是违反无人职守的原则:现在expect就解决了这个问题, Expect是一个免费的编程工具语言,用来实现自动和交互 ...
- parallel Stream 学习
首先,我们需要了解下ForkJoinPool.ForkJoin框架是从jdk7中新特性,它同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口.它使 ...
- Python对象迭代与反迭代相关问题与解决技巧
1.如何实现可迭代对象和迭代器对象(1)¶ In [1]: # 列表和字符串都是可迭代对象 l = [1,2,3,4] In [2]: s = 'abcde' In [3]: for x in l ...
- python之元组及其方法---整理集
元组: 区别:与列表类似,是对列表的二次加工:用小括号包括起来:元素不可修改:不可增加.删除 技巧:创建元组的时候,一般在最后一个元素后面加一个逗号:为了与方法区分:并且这个逗号不算元素例如: tu= ...
- Json常用代码
以下使用的都是fastJson. 先创建Person类,如下: public class Person { @JSONField(name = "AGE") private int ...
- Android 如何避免运行时奔溃
奔溃问题 android运行的时候难免会有一些空指针(NullPointerException)或者下标越界(IndexOutOfBoundsException),用户使用的过程操作某一个按钮的时候, ...
- H-Modify Minieye杯第十五届华中科技大学程序设计邀请赛现场赛
题面见 https://ac.nowcoder.com/acm/contest/700#question 题目大意是有n个单词,有k条替换规则(单向替换),每个单词会有一个元音度(单词里元音的个数)和 ...
- 学习日记--用Vector(向量)实现动态数组
Vector的使用方法: 能在添加元素时增加长度的数组称为动态数组或可变长数组.相对地,必须事先指定长度,只能容纳一定数量元素的数组称为静态数组.下面分享一下如何借助STL(标准模板库)中的Vecto ...