基于 JSch 实现服务的自定义监控解决方案

JSch Java SSH开发实战:连接池、密钥认证与生产级故障排查 SSH 是 Linux 系统远程管理的核心协议,而 JSch 作为纯 Java 实现的 SSH 客户端库,解决了 Runtime.exec 调用系统 ssh 命令带来的环境依赖、权限失控和连接不可控等工程痛点。其底层基于 RFC 4251–4254 协议栈,支持会话复用、通道管理、密钥交换与流式 I/O 控制,具备企业级可监控、可熔断、可审计的技术能力。在自动化运维、金融对账、CI/CD 执行等场景中,JSch 被广泛用于安全执行远程命令、SFTP 文件传输及 SSH 端口转发。本文聚焦 JSch 的生产就 阅读详情

一、基于 JSch 实现服务的自定义监控

JSch 是 SSH2 的一个纯 Java 实现。它允许你连接到一个 sshd 服务器,使用端口转发, X11 转发,文件传输等等。你可以将它的功能集成到你自己的 程序中。

既然可以通过 SSH 连接到服务器,那就可以执行一些 命令 ,例如我们要监控一个服务是否正在运行,或者服务有无僵死,可以通过查看服务进程是否存在,访问接口是否正常来判断,如果不正常,我们可以通过 JSch 连接到该服务器中,执行重启的脚本。

现在对于新的项目相信大家都已经放在 k8s 中部署了,在 k8s 中有完善的服务检测机制,可以实现服务宕机的重起,服务僵死重启等功能,那为什么博主还要写这篇博客呢,相信大家应该都遇到过一些比较老的项目吧,由于项目比较老不容易打包成镜像放在 k8s 中运行,但是这种项目还依然运行着一些比较重要的功能,对其可用性还是需要保障。或者公司中有项目并不是放在容器中运行的,一时也不想迁移,针对这种情况下就可以参考本篇文章的内容。

下面我们将实现一个简单的场景,服务器中运行着一个普通的 java 项目,我们需要保障其运行的可用性,如果出现宕机需要及时的进行启动。

这里博主就有两种实现方案了:

第一种是我们在另一台服务器中准备一个监控服务,该服务通过 JSch 连接到服务器中,定时查看是否存在 java 项目进程,如果进程不存在则进行重启指令。同时也可以通过指令监控服务的内存、磁盘等使用大小。

第二种就是借助 zookeeper 的事件通知机制,第一种方式通过定时的方式,势必会有一定的时差。如果需要服务一宕机,监控服务立马可以检测到的话,可以借助 zookeeper 的事件通知机制,被检测的项目在运行的时候去 zookeeper 建立一个属于该服务的临时节点,如果服务宕机则会因为 session 连接终断,临时节点自动移除,此时监控该节点的 session 会立马收到通知。但这种方式需要被检测服务操作 zookeeper 有一定的侵入性,另外有可能因为网络的震荡,导致连接中断,因此在收到删除事件通知时,建议再去服务中查看下进程是否真的宕机。

以上两种方案都是简单的说了下思路,具体实施还是有很多注意点,本篇文章就基于第一种方式实现自定义监控。

环境准备:

首先准备一个 java 项目,这里为了方便我准备了一个 SpringBoot 项目,并运行在了服务器中:

下面开始监控服务的搭建:

二、监控服务搭建

首先新建一个 SpringBoot 项目,在 pom 中引入 JSch 的依赖:

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

创建一个 SSHVO 存放主机信息:

@Data
public class SSHVO {
    private String host;
    private String userName;
    private String password;
    private Integer port;
}

下面便是本篇文章的主要代码, 通过 JSch 进行远程主机的连接获得连接 Session ,并通过 Session 执行命令:

@Slf4j
@Data
public class SSHUtil {

    private SSHVO sshVo;
    private Session session;

    public SSHUtil(SSHVO sshVo) {
        this.sshVo = sshVo;
    }

    public void connect() throws Exception {
        ValidResult validResult = ValidationUtil.fastFailValidate(sshVo);
        if (validResult.isHasError()) {
            throw new Exception(validResult.getErrMessage());
        }
        JSch jsch = new JSch();
        session = jsch.getSession(sshVo.getUserName(), sshVo.getHost(), (sshVo.getPort() == null || sshVo.getPort() == 0) ? 22 : sshVo.getPort());
        session.setPassword(sshVo.getPassword());
        java.util.Properties config = new java.util.Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setTimeout(3000);
        session.connect();
        log.info("SSH 连接成功 > {}", sshVo.toString());
    }

    public boolean isConnect() {
        if (session == null) {
            return false;
        }
        return session.isConnected();
    }

    public String command(String command) throws Exception {
        if (session == null){
            connect();
        }
        log.info("SSH 执行命令 > {} , {} ", sshVo.toString(), command);
        Channel channel = null;
        try {
            channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);
            channel.setInputStream(null);
            ((ChannelExec) channel).setErrStream(System.err);
            channel.connect();
            InputStream in = channel.getInputStream();
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")))) {
                StringBuilder stringBuffer = new StringBuilder();
                String buf = "";
                while ((buf = reader.readLine()) != null) {
                    stringBuffer.append(buf);
                }
                log.info("SSH 执行命令 > {} ,返回 >>  {} ", sshVo.toString(), stringBuffer.toString());
                return stringBuffer.toString();
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (channel != null) {
                channel.disconnect();
            }
        }
    }

    public boolean close() {
        if (session == null) {
            return false;
        }
        session.disconnect();
        return true;
    }

}

上面实现了对远程主机的连接和执行命令操作,如果每次都创建一个新的 Session 肯定会造成资源浪费,下面我们做一个对 Session 缓存的操作,这里使用了 guava 中的缓存 Api ,需要引入 guava 的依赖:

<dependency>
     <groupId>com.google.guava</groupId>
     <artifactId>guava</artifactId>
     <version>18.0</version>
 </dependency>

下面使用 Cache 缓存连接对象:

@Slf4j
@Service
public class SSHService {

    private Cache<String, SSHUtil> sshConnectCache = CacheBuilder.newBuilder()
            .maximumSize(2000)
            .expireAfterWrite(2, TimeUnit.DAYS).build();

    /**
     * 执行命令
     */
    public String command(SSHVO sshVo, String command) {
        try {
            if (StringUtils.isEmpty(sshVo.getHost())) {
                throw new Exception("host is null !");
            }
            SSHUtil tool = sshConnectCache.getIfPresent(sshVo.getHost());
            if (tool == null) {
                tool = new SSHUtil(sshVo);
                tool.connect();
                sshConnectCache.put(sshVo.getHost(), tool);
            }
            return tool.command(command);
        } catch (Exception e) {
            log.error("执行SSH 失败!", e);
            return null;
        }
    }
}

下面创建一个 定时任务,定时获取进程 ID,如果ID不存在则进行启动:

@Slf4j
@Component
@EnableScheduling
public class SSHTask {
    @Autowired
    SSHService sshService;

    @Scheduled(cron = "0/5 * * * * *")
    public void sshTask() throws InterruptedException {
        SSHVO sshvo = new SSHVO();
        sshvo.setHost("192.168.40.170");
        sshvo.setUserName("root");
        sshvo.setPassword("bxc");
        sshvo.setPort(22);
        String command = "ps aux |grep java-server-0.0.1.jar |grep -v grep | awk '{print $2}'";
        // 执行命令
        String resCommand = sshService.command(sshvo, command);
        log.info("主机:{},指令:{},返回:{}", sshvo.getHost(), command, resCommand);
        if (StringUtils.isEmpty(resCommand)) {
            //重启
            String startCommand = "nohup java -jar /opt/java/java-server-0.0.1.jar > /opt/java/nohup.out 2>&1 &";
            String resstartCommand = sshService.command(sshvo, startCommand);
            log.info("主机:{},指令:{},返回:{}", sshvo.getHost(), startCommand, resstartCommand);
        }
    }
}

上面每5秒进行检测一次,启动项目查看打印日志:

可以看到打印出服务的进程 ID ,下面我们手动去服务中将该进程杀掉:

下面再观看打印的日志:

可以看到服务已经自动启动起来了,进入主机中查看下进程:

服务已经成功被启动起来。

Java利用JSCH库远程连接Linux服务器以及操作多条Shell命令 为了实现DHCP服务器的IP存储、回收和查询机制,我们需要将服务器中LXD容器的网卡IP查询出来,并且存储到服务器中的Mysql中。所以,下面介绍如何通过Java远程连接Linux服务器以及操作多条Shell命令。 阅读详情

相关推荐

JSch库入门实战应用,推荐大家学习

JSch是一个用于在Java平台上实现SSH连接的库。它提供了一个Java实现的SSH2协议客户端,可以用于在Java应用程序中进行SSH连接、文件传输和远程命令执行等操作。 JSch库提供了以下关键功能: 1. SSH连接:JSch允许建立到SSH服务器的安全连接。它支持密码认证、公钥认证和密钥交换等多种身份验证方法。 2. 文件传输:JSch可以执行SCP(Secure Copy)和SFTP...

自强不息,厚德载物,未来可期 1160

深入浅出jschJava开发者必备的SSH2开源库详解与实战

本文详细介绍了jsch这一Java开发者必备的SSH2开源库,包括其特点、基本使用步骤和实例代码。通过本文,相信你已经对jsch有了更深入的了解。接下来,你可以尝试在实际项目中使用jsch,提高服务器远程管理的效率。让我们一起探索jsch的更多功能,为自动化运维贡献力量! (本文篇幅限制,未能详细展开更多高级功能和使用技巧,敬请谅解。如有疑问,请随时关注后续文章更新。)

u013558123的博客 1126

Hutool SFTP实战:手把手教你搭建一个带进度条和断点续传的文件上传服务

本文详细介绍了如何使用Hutool SFTP模块构建企业级文件传输服务,重点解决大文件传输的可靠性、实时进度反馈和异常恢复机制。通过实战案例,展示了如何实现断点续传、进度监控以及与Spring Boot的集成,帮助开发者打造高效、安全的文件上传解决方案

weixin_30696427的博客 283

SSH安全文件传输实战:JSCH使用指南

本文还有配套的精品资源,点击获取 简介:SSH协议提供安全的远程服务,而JSCH库则是Java实现这些服务的工具,包括安全文件传输和命令执行。本文介绍如何使用JSCH库进行安全的文件传输,包括添加依赖、初始化、创建会话、配置、文件操作以及资源关闭等步骤。JSCH支持SFTP和多种网络功能,适用于多种远程管理任务,开发者可以利用提供的jar包和源码进行深度开发。实践时应关注...

weixin_42128315的博客 2950

JSch - 深入理解与探索SSH连接库

是一个强大的Java库,用于实现Secure Shell (SSH2) 协议,提供了在Java应用中进行远程操作的能力,如文件传输、命令执行等。这个开源项目由Marc Wiede 创建并维护,已经在多个大型项目中被广泛应用,是Java开发者进行 SSH 连接的标准选择之一。 ## 项目简介 JSch 提供了全面的 SSH 功能,包括但不限于: - 建立安全的SFTP(Secure File

gitblog_00067的博客 872

基于JSch的实时日志流读写与安全传输系统实现

你有没有想过,当你第一次连接一台新服务器时,终端弹出的那个警告:这其实就是SSH的主机身份验证机制在工作。JSch默认行为是,意味着它不会自动接受未知主机的公钥。但在自动化系统中,显然不能让人去点“yes”。怎么办?答案是预注册信任列表。你可以提前收集所有目标服务器的SSH公钥指纹,写入这个文件。格式如下:# known_hosts 示例这样,每次连接都会自动比对指纹。一旦发现不匹配(比如有人冒充服务器),连接立即中断!当然,静态文件也有局限。

weixin_35949153的博客 328

JSch技术深度解析:现代Java SSH架构实践指南

在当今企业级应用开发中,安全远程访问已成为基础设施的关键组件。随着OpenSSH 8.8版本默认禁用RSA/SHA1签名算法,许多依赖传统SSH库的Java应用面临着兼容性挑战。JSch作为纯Java实现的SSH2协议库,通过持续演进不仅解决了这一技术痛点,更在密码学安全、协议兼容性和开发者体验方面提供了全面的解决方案。 ## 架构演进与密码学现代化 JSch的架构设计体现了对现代密码学趋势的

gitblog_00679的博客 241

Java实现FTP/SFTP文件传输的实战指南

文件传输协议(FTP)和基于SSH的安全文件传输协议(SFTP)是企业级应用中常见的数据交换技术。FTP协议以其简单高效著称,适用于服务器间批量文件传输;而SFTP则通过SSH加密通道提供更高的安全性。在Java生态中,Apache Commons Net和JSch库分别提供了成熟的FTP/SFTP实现方案。通过合理的连接池管理、异常重试机制和缓冲区优化,可以构建高可靠的文件传输服务。这些技术广泛应用于订单数据同步、报表文件推送等企业集成场景,特别是在需要实现断点续传、大文件传输等需求时展现其技术价值。

weixin_30697239的博客 442

FreeSSHd实战:5分钟在Windows Server上搭建带Java代码示例的SFTP服务

本文详细介绍了如何在Windows Server上使用FreeSSHd快速搭建企业级SFTP服务,并提供Java代码示例实现深度集成。内容涵盖安全配置、权限管理、性能优化等关键环节,特别适合需要在Windows平台部署文件服务器开发者和运维人员。

css33的专栏 868

Java实现FTP与SFTP文件传输协议详解

文件传输协议(FTP)和安全文件传输协议(SFTP)是网络通信中实现文件交换的核心技术。FTP作为传统协议采用明文传输,通过21端口建立控制连接,20端口进行数据传输;而SFTP基于SSH加密通道,仅需22端口即可完成所有操作。在Java开发中,Apache Commons Net和JSch库分别提供了完整的FTP/SFTP客户端实现方案,支持断点续传、进度监控等企业级功能。针对不同场景需求,FTP适合内网非敏感数据传输,SFTP则是公网传输和合规场景的首选方案。通过连接池管理、异常处理机制和安全加固措施,

weixin_30954265的博客 359

SpringBoot整合SpringSecurity与SSH:构建企业级安全应用骨架实战

在构建现代企业级应用时,权限控制与安全传输是保障系统安全的两大基石。权限控制基于RBAC(基于角色的访问控制)模型,通过用户、角色、权限的关联,实现从菜单到按钮的精细化访问管理,其核心原理在于前后端协同校验,前端负责体验优化,后端通过注解拦截器进行强制校验,构筑了完整的防护体系。安全传输则利用SSH协议,通过公钥认证和加密隧道,为管理接口或服务间通信提供点对点的安全保障,有效提升了内网应用的安全水位。这两项技术的结合,为后台管理系统、运营平台等高敏感度应用场景提供了从身份认证、访问控制到数据传输的全链路安全

weixin_30607029的博客 478

FinalShell高级版合规获取与SSH客户端技术深度解析

SSH(Secure Shell)协议是远程连接和管理服务器的核心技术,通过加密通道实现安全的命令执行与文件传输。其工作原理基于客户端-服务器模型,利用非对称加密进行身份验证,确保通信的机密性与完整性。在工程实践中,一款优秀的SSH客户端能极大提升运维与开发效率,尤其在服务器集群管理、批量操作和实时监控等场景下价值显著。本文聚焦于广泛使用的FinalShell工具,深入探讨其高级版功能的技术实现与授权机制,并系统梳理了包括官方购买、开源替代在内的多种合规获取路径。针对网络流传的破解版等高风险方案,文章结合J

anvt77205的博客 398

Java实现轻量级网络诊断工具集开发指南

网络诊断工具是运维开发中的基础组件,其核心原理是通过封装底层网络协议实现连通性检测。Java语言凭借其跨平台特性和丰富的网络API,非常适合开发此类工具。从技术实现看,利用InetAddress.isReachable()实现ICMP检测、通过Socket建立TCP连接、结合URLConnection处理HTTP请求,构成了网络工具的技术三角。这类工具在服务器监控、故障排查等场景具有重要价值,特别是当需要批量检测网络设备状态时。本文以Ping、Telnet、Wget三个典型功能为例,详细讲解如何使用Java

weixin_30800987的博客 382

告别日志混乱:Nushell中同时捕获标准输出与错误流的3种实战技巧

是否还在为命令行工具的输出和错误信息混杂而烦恼?当运行复杂脚本时,标准输出(stdout)和错误输出(stderr)交织在一起,既难以阅读又不易排查问题。本文将带你掌握Nushell中处理输出流的核心技巧,通过实用示例和可视化操作,让你轻松实现"鱼与熊掌兼得"——既在终端实时查看输出,又能完整保存日志。 读完本文你将学会: - 使用`tee`命令实现输出分流与实时监控 - 利用管道和文件重定向...

gitblog_00761的博客 377

DBeaver连接PostgreSQL数据库的3个实战技巧与深度优化指南

DBeaver作为一款功能强大的开源数据库管理工具,支持连接超过100种数据库,其中PostgreSQL作为最受欢迎的开源关系数据库之一,与DBeaver的结合使用极为普遍。然而在实际使用中,许多用户会遇到连接异常、界面灰显等问题。本文将为你提供完整的解决方案和优化技巧。 ## 🎯 核心挑战:为什么PostgreSQL连接会出问题? 当你尝试在DBeaver中连接PostgreSQL数据库时

gitblog_00083的博客 259

Alibaba Cloud Toolkit轻量部署插件:从零实现IDE内一键自动化发布

自动化部署是现代软件工程实践的核心环节,旨在通过工具和流程替代重复、易错的手动操作,实现应用发布的标准化与高效化。其基本原理通常基于SSH/SFTP协议进行文件传输,并结合远程命令执行来完成应用的生命周期管理。这项技术的核心价值在于将开发、测试与部署环节无缝衔接,显著缩短交付周期,降低人为失误风险,尤其适合追求快速迭代的开发场景。对于个人开发者、创业团队或微服务架构中的独立服务,通过IDE插件实现轻量级一键部署,能有效解决传统部署方式中的上下文切换成本高、操作繁琐、缺乏标准化等问题。Alibaba Clou

weixin_28455801的博客 67

工作中使用到的单词(软件开发)_第五版

本文摘要: 本文为软件开发相关的术语与技术要点整理,主要包含2020-2025年间四版内容更新(No.01-41)。重点包括: 证书文件格式(PEM/P12)差异 外部API通信注意事项(Accept头设置、HTTPS连接问题) Postman工具使用技巧(Cookie管理、请求头设置) WAS配置相关经验(JVM设置、SSL连接问题) 数据库操作命令(DB2表结构修改) IBM安全管理组件(TAM/iv-user机制) 网络通信细节(chunked传输编码特性) 常用开发工具(curl、Postman)的

sun0322 2286
上一篇: Java并发之ThreadLocal
下一篇: 从面试官的角度,聊聊java面试流程
一头狒狒
博客等级 码龄4年 66粉丝 · 122原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值