如何让Java应用成为杀不死的小强?(中篇)
各位坐稳扶好,我们要开车了。不过在开车之前,我们还是例行回顾一下上期分享的要点。
上期我们抛了一个砖:“如何实现 Java 应用进程的状态监控,如果被监控的进程 down 掉,是否有机制能启动起来?”并结合 Resin 应用服务器背后启动的进程,更详细的阐述了一下问题。
我们依然不考虑自己怎么去实现,而是先看看 Resin 这款技术轮子,是不是按照我们的猜想设计的呢?是不是可以模仿一二?
好了,熟读唐诗三百首,不会作诗也会吟,抱着疑问,我们再深入一次 Resin 的源码,如果不感兴趣,或者脑仁疼,那建议跳到下篇直接撸码实战。
1.
我们从 ResinBoot 的 main 函数开始,一步一步来看看怎么实现,目标是提取里面的关键核心思想,细枝末节莫纠结。
ResinBoot 的 main 函数是 Resin 应用服务器入口,大概流程如下:
创建 ResinBoot 实例 boot; 然后根据传入的 args 参数获取对应的 XxCommand 对象; 接着调用 ResinBoot 的 start 函数,完成服务的启动; 最后退出 ResinBoot 的进程。
那接下来不妨再深入看看创建 ResinBoot 对象时,构造方法中都干了啥?
发现 ResinBoot 创建对象时,构造方法中创建了 WatchdogArgs 对象,WatchdogArgs 里面到底又做了什么呢?
发现 WatchdogArgs 静态代码块中提前预制了一堆命令执行的对象实例,其中就包括 StartCommand,再回头看看它的构造方法,会发现会进行解析咱们 main 函数传入的 args 入参,然后根据入参获取对应的命令执行对象。
其中格式化命令行入参的方法 parseCommandLine 会匹配一堆预制的参数,实在匹配不到就从静态的 _commandMap 中去匹配对应的命令执行对象,当然咱们传入的参数是 start,所以会匹配成功 StartCommand。
那么我们再回头看看 ResinBoot 的 main 函数,发现又调用了 ResinBoot 的 start 方法。
那我们也一起看看 ResinBoot 的 start 方法做了些什么操作?发现方法中获取对应的 command,然后调用 command.doCommand() 方法。
我们知道此时的 command 为 StartCommand,那 StartCommand 中的 doCommand() 到底做了什么事情呢?会发现 doCommand 方法中调用了 WatchdogClient 的 startWatchdog 的方法。
那我们看看 startWatchdog 方法中又做了哪些事情?重点要来了,重点要来了,重点要来了。发现调用了 launchManager 方法,那 launchManager 又是干什么的呢?
仔细深入会发现,launchManager 方法主要用 ProcessBuilder 来实现启动 WatchdogManager 的进程。
并且第 539 行有一句日志输出,和咱们在控制台输入 ./resin.sh start 命令启动 Resin 服务时的日志不谋而合。
至此,ResinBoot 通过 ProcessBuilder.start() 成功触发启动 WatchdogManager 进程,也就是咱们猜测的大总管进程,哪丫鬟进程是否也存在呢?丫鬟进程又是怎么启动的呢?
2.
此时我们跟随源码设计的脚步,继续向下刨一刨 WatchdogManager,发现 WatchdogManager 程序入口 main 函数中,根据传入参数构建了 WatchdogManager 对象,并通过参数获取对应的 XxCommand(似曾相识的感觉),然后通过 XxCommand 调用 doWatchdogStart 函数完成服务的启动。
再深入去跟踪,发现 doWatchdogStart 方法中会调用 WatchdogManager 的 startServer 方法。
那 startServer 方法中又干了什么事情呢?很显然是通过配置找到要启动的子服务,然后调用重载的 startServer 方法。
接着就开始调用 WatchdogChild 的 start 方法,方法干了什么事情呢?
WatchdogChild 的 start 方法中创建了 WatchdogChildTask 任务对象,并调用 start 方法完成任务启动。
其中 WatchdogChildTask 的 start 方法很简单,就是起了一个线程开始跑任务。
重点再一次来临,会发现线程体中创建了一个 WatchdogChildProcess 对象实例,接着调用对象的 run 方法。此处就是保证了 Resin 应用为什么一直杀不死的原因,有个循环调度,一旦子进程有问题,立即再次进行创建子进程。
我们看看 run 方法的实现,会发现创建了一个 socket 用于通讯;然后把端口传入 createProcess 方法构建 Resin 进程对象。
接着会发现 WatchdogProcess 的创建进程的方法 createProcess 中定义要启动的类为 com.caucho.server.resin.Resin;然后封装一系列的参数;紧接着用 ProcessBuilder 完成 Resin 进程的启动。
然后 connectToChild 方法主要用于等待子进程的连接。这不就是大总管开辟的实时通讯的端口么!
至此,我们知道 WatchdogManager 会创建 WatchdogTask 任务,用于创建WatchdogChildProcess 对象,此对象会触发启动 Resin 进程,并提供 socket 通讯服务。
3.
那 Resin 进程又干了啥?我们依然从 main 函数开始看起。一目了然根据传入参数创建 Resin 实例,然后重点关注一下 waitForExit,这个是不是和咱们猜测的丫鬟进程与大总管进程通讯不上就退出,是不是这么回事呢?
然后深入 Resin 的 waitForExit 方法发现通过 pingSocket 参数构建 ResinWaitForExitService,用于启动 ResinActor(这个 Actor 模型前期的分享咱们提过一嘴),然后调用 waitForExit 方法。
到这大概也就到了最后,根据蓝色框中的日志输出约莫也就是那么回事儿。
...... 此处省略一万图(不刨了,点到为止)......
至此,丫鬟进程 Resin 也启动完毕了,并且与父进程建立了实时通讯。源码看了七七八八,细枝末节没细谈,主要是能明白梗概,梳理个大致脉略,能大致清晰 Resin 服务启动时启动了 ResinBoot 进程、WatchdogManager 进程、Resin 进程,当进程启动完成后 ResinBoot 进程就正常退出了,所以当我们用 jps 命令看时,就发现只有 WatchdogManager、Resin 两个进程啦,其中用到的核心技术为 ProcessBuilder、Socket 通讯。
好了,能坚持看到这儿的,那绝对都是铁粉,希望我不是一人在饮酒醉,独醉不如众醉,独乐乐不如众乐乐,希望这期的分享能帮你打通任督二脉,以后如果真用到时,不妨以本文作为参考,说不定会有点价值。
下期我们将站在 Resin 的肩膀上进行实战,请各位期待。

如何让Java应用成为杀不死的小强?(中篇)的更多相关文章
- 如何让Java应用成为杀不死的小强?(上篇)
各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 项庄舞剑意在沛公,而咱们上期主要借助应用服务器 Resin 的源码,体验了一次 JMX 的真实应用.鉴于 9012 年 ...
- 如何让Java应用成为杀不死的小强?(下篇)
各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 经过前两期的铺垫及烧脑的分享,我们大概对「如何实现 Java 应用进程的状态监控,如果被监控的进程 down 掉,是否 ...
- 一个杀不死的小强,kill进程无效的原因 记录故障排查过程中kill进程无效的分析过程
今天在处理一个机器异常负载(1000+)的问题,碰到了一个从未碰到过的情况,遇到了一个异常顽固的分子.我使用了所能想到的所有杀进程的方法,却始终无法干掉这个顽固分子,最后终于在谷歌大神的指引下,干掉了 ...
- Linux中杀不死的进程
前段时间,一哥们,去杀Linux服务器的进程,发现kill命令失灵了,怎么杀都杀不死. 然后上网查了下资料,原来是要被杀的进程,成为了僵尸进程. 僵尸进程的查看方法: 利用命令ps,可以看到有标记为Z ...
- paip.杀不死进程的原因--僵尸进程的解决.txt
paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...
- 手把手教你写LKM rookit! 之 杀不死的pid&root后门
......上一节,我们编写了一个基本的lkm模块,从功能上来说它还没有rootkit的特征,这次我们给它添加一点有意思的功能.我们让一个指定的进程杀不死, 曾经,想写一个谁也杀不死的进程,进程能捕捉 ...
- Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程
Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程 原因: 一般造成这种原因是因为项目中有非守护线程的存在: 解决方案: 一.从Tomcat上解决 方案1:(推荐的方案:因为一台 ...
- 不死的小强 .net core 微服务 快速开发框架 Viper 限流
1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...
- Android设备直接运行java项目?还杀不死?
思路:拿到dex可执行文件,使用android执行 使用idea创建java类库,写相关逻辑代码 使用idea导出该类库jar包 使用android dx工具 将jar文件转换为dex可执行文件 dx ...
随机推荐
- A. New Building for SIS Codeforce
You are looking at the floor plan of the Summer Informatics School's new building. You were tasked w ...
- iTerm2 都不会用,还敢自称老司机?(上)
对于需要长期与终端打交道的工程师来说,拥有一款称手的终端管理器是很有必要的,对于 Windows 用户来说,最好的选择是 Xshell,这个大家都没有异议.但对于 MacOS 用户来说,仍然毋庸置疑, ...
- 树莓派上搭建唤醒词检测引擎 Snowboy
Snowboy 是一款高度可定制的唤醒词检测引擎,可以用于实时嵌入式系统,并且始终监听(即使离线).当前,它可以运行在 Raspberry Pi.(Ubuntu)Linux 和 Mac OS X 系统 ...
- Simulink仿真入门到精通(十一) 模块的封装
当用户编写了自定义的S函数或者使用Simulink标准库中的模块搭建子系统后,可以通过封装为其设计显示外观,追加参数对话框. 封装是构建一个以对话框为接口的交互界面的过程,它将复杂的模块逻辑关系隐藏起 ...
- CSRF攻击原理及预防手段
CSRF全程 Cross Site Request Forgery, 跨站域请求伪造.这种攻击方式相对于XSS,SQL注入等攻击方式比较晚被发现,今天就来讲解下这种攻击方式以及避免方式. 攻击过程 ...
- fastdfs的入门到精通(引言和单机安装)
引言: FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服 ...
- C++ 回调函数,拷贝文件
#include <iostream> #include <windows.h> using namespace std; unsigned long long transla ...
- strongsan基本用法
0x01 安装 ====> CentOS RPM安装 下载:https://pkgs.org/download/strongswanwget http://download-ib01.fedor ...
- Git&Github入门
Github: 仓库repository: 存放项目代码,每个项目对应一个项目 收藏star: 收藏 复制克隆项目(Fork): 发起请求Pull Reques: 别人改进你的代码,如果觉得不错可以合 ...
- 使用new Image()可以针对单单请求,不要返回数据的情况
使用new Image()可以针对单单请求,不要返回数据的情况,比如我这里写了一个Demo,请求百度的Logo一个示例: <html> <head> </head> ...