各位坐稳扶好,我们要开车了。不过在开车之前,我们还是例行回顾一下上期分享的要点。

上期我们抛了一个砖:“如何实现 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应用成为杀不死的小强?(中篇)的更多相关文章

  1. 如何让Java应用成为杀不死的小强?(上篇)

    各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 项庄舞剑意在沛公,而咱们上期主要借助应用服务器 Resin 的源码,体验了一次 JMX 的真实应用.鉴于 9012 年 ...

  2. 如何让Java应用成为杀不死的小强?(下篇)

    各位坐稳扶好,我们要开车了.不过在开车之前,我们还是例行回顾一下上期分享的要点. 经过前两期的铺垫及烧脑的分享,我们大概对「如何实现 Java 应用进程的状态监控,如果被监控的进程 down 掉,是否 ...

  3. 一个杀不死的小强,kill进程无效的原因 记录故障排查过程中kill进程无效的分析过程

    今天在处理一个机器异常负载(1000+)的问题,碰到了一个从未碰到过的情况,遇到了一个异常顽固的分子.我使用了所能想到的所有杀进程的方法,却始终无法干掉这个顽固分子,最后终于在谷歌大神的指引下,干掉了 ...

  4. Linux中杀不死的进程

    前段时间,一哥们,去杀Linux服务器的进程,发现kill命令失灵了,怎么杀都杀不死. 然后上网查了下资料,原来是要被杀的进程,成为了僵尸进程. 僵尸进程的查看方法: 利用命令ps,可以看到有标记为Z ...

  5. paip.杀不死进程的原因--僵尸进程的解决.txt

    paip.杀不死进程的原因--僵尸进程的解决.txt 作者Attilax  艾龙,  EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn ...

  6. 手把手教你写LKM rookit! 之 杀不死的pid&root后门

    ......上一节,我们编写了一个基本的lkm模块,从功能上来说它还没有rootkit的特征,这次我们给它添加一点有意思的功能.我们让一个指定的进程杀不死, 曾经,想写一个谁也杀不死的进程,进程能捕捉 ...

  7. Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程

    Linux下tomcat的shutdown命令可以关闭服务但是杀不死进程 原因: 一般造成这种原因是因为项目中有非守护线程的存在: 解决方案: 一.从Tomcat上解决 方案1:(推荐的方案:因为一台 ...

  8. 不死的小强 .net core 微服务 快速开发框架 Viper 限流

    1.Viper是什么? Viper 是.NET平台下的Anno微服务框架的一个示例项目.入门简单.安全.稳定.高可用.全平台可监控.底层通讯可以随意切换thrift grpc. 自带服务发现.调用链追 ...

  9. Android设备直接运行java项目?还杀不死?

    思路:拿到dex可执行文件,使用android执行 使用idea创建java类库,写相关逻辑代码 使用idea导出该类库jar包 使用android dx工具 将jar文件转换为dex可执行文件 dx ...

随机推荐

  1. 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 ...

  2. iTerm2 都不会用,还敢自称老司机?(上)

    对于需要长期与终端打交道的工程师来说,拥有一款称手的终端管理器是很有必要的,对于 Windows 用户来说,最好的选择是 Xshell,这个大家都没有异议.但对于 MacOS 用户来说,仍然毋庸置疑, ...

  3. 树莓派上搭建唤醒词检测引擎 Snowboy

    Snowboy 是一款高度可定制的唤醒词检测引擎,可以用于实时嵌入式系统,并且始终监听(即使离线).当前,它可以运行在 Raspberry Pi.(Ubuntu)Linux 和 Mac OS X 系统 ...

  4. Simulink仿真入门到精通(十一) 模块的封装

    当用户编写了自定义的S函数或者使用Simulink标准库中的模块搭建子系统后,可以通过封装为其设计显示外观,追加参数对话框. 封装是构建一个以对话框为接口的交互界面的过程,它将复杂的模块逻辑关系隐藏起 ...

  5. CSRF攻击原理及预防手段

      CSRF全程 Cross Site Request Forgery, 跨站域请求伪造.这种攻击方式相对于XSS,SQL注入等攻击方式比较晚被发现,今天就来讲解下这种攻击方式以及避免方式. 攻击过程 ...

  6. fastdfs的入门到精通(引言和单机安装)

    引言: FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的在线服 ...

  7. C++ 回调函数,拷贝文件

    #include <iostream> #include <windows.h> using namespace std; unsigned long long transla ...

  8. strongsan基本用法

    0x01 安装 ====> CentOS RPM安装 下载:https://pkgs.org/download/strongswanwget http://download-ib01.fedor ...

  9. Git&Github入门

    Github: 仓库repository: 存放项目代码,每个项目对应一个项目 收藏star: 收藏 复制克隆项目(Fork): 发起请求Pull Reques: 别人改进你的代码,如果觉得不错可以合 ...

  10. 使用new Image()可以针对单单请求,不要返回数据的情况

    使用new Image()可以针对单单请求,不要返回数据的情况,比如我这里写了一个Demo,请求百度的Logo一个示例: <html> <head> </head> ...