Jenkins+jmeter 多线程测试java接口时爆错,导致无法生成html报告。

先介绍下场景:

在Jenkins中新建了一个Job,假设你在一些列Build Step之前/之后,启动了一个进程,打个比方说启动一个Jboss进程。等到Build完成,你去Console Output中查看显示启动成功,甚至PID也有了。但是当你去后台查看的时候,发现其实这个进程根本不存在,并没有启动成功。

不过如果你使用的是较早的Hudson版本(Ver 1.136),并且是直接在页面中的Build Session中(如Excute Shell)执行命令的话,你可能会得到如下的提示:

Process leaked file descriptors. See http://wiki.hudson-ci.org/display/HUDSON/Spawning+processes+from+build for more information

如果你看过这篇文章,那么你就会明白造成这种问题的原因是什么:Jenkins默认会在Build结束后Kill掉所有的衍生进程,用官方的话来说就是:

To reliably kill processes spawned by a job during a build, Jenkins contains a bit of native code to list up such processes and kill them.

问题分析:

The reason this problem happens is because of file descriptor leak and how they are inherited from one process to another. Jenkins and the child process are connected by three pipes (stdin/stdout/stderr.) This allows Jenkins to capture the output from the child process. Since the child process may write a lot of data to the pipe and quit immediately after that, Jenkins needs to make sure that it drained the pipes before it considers the build to be over. Jenkins does this by waiting for EOF.

When a process terminates for whatever reasons, the operating system closes all the file descriptors it owned. So even if the process didn't close stdout/stderr, Jenkins will nevertheless get EOF.

The complication happens when those file descriptors are inherited to other processes. Let's say the child process forks another process to the background. The background process (AKA daemon) inherits all the file descriptors of the parent, including the writing side of the stdout/stderr pipes that connect the child process and Jenkins. If the daemon forgets to close them, Jenkins won't get EOF for pipes even when the child process exits, because daemon still have those descriptors open. That's how this problem happens.

从官方的说明中可以看出,造成这种问题的原因,是由于文件描述符的丢失以及子进程是如何继承的。

Jenkins和子进程之间的通信使用三根管道进行:stdin,stdout,stderr,由于Jenkins可以捕捉到子进程的输出,而子进程可能往stdout中写入大量数据然后立即退出,Jenkins为了完整的读取子进程的输出,会在用于子进程stdout的管道上等待EOF。这样,无论子进程由于什么原因退出,系统将关闭进程使用的文件描述符,因而Jenkins总是可以收到EOF。

但是当子进程在后台fork出另一个进程的时候(比如A fork出了B,启动一个daemon进程),情况就出现一些变化。由于进程B会继承进程A的文件描述 符,如果进程B没有关闭这些描述符,即使进程A退出,这些描述符依然是打开的,Jenkins将不会在相应管道上收到EOF。

通常一个实现良好的daemon会关闭所有文件描述符以避免这个问题,但是总有一些实现没有遵循这个规则。在更旧版本的Hudson上,这个问题甚至将导致Job无法结束,Jenkins一直在那等待EOF。

解决办法:

现在我们知道,Jboss之所以没有启动成功,是因为它没有关闭继承的文件描述符,Jenkins在Job构建过程结束后认为Jboss进程未终止,因而将其kill掉了。

1. 使用daemonize工具

在这个页面中https://wiki.jenkins-ci.org/display/JENKINS/Spawning+processes+from+build介绍了一种方法:

On Unix, you can use a wrapper like this to make the daemon behave.

在Unix上,你可以使用daemonize工具将程序作为实现良好的daemon进程运行以避免这个问题:

安装daemonize工具包,使用daemonize命令wrap 相应进程的启动指令,类似于:

  1. daemonize ${your.process} start

另外,页面中也给出了如何在Windows平台解决这个问题的方法,具体的看页面中的介绍就可以了。

2. 重设环境变量BUILD_ID

在研究这个问题的时候,找到了另外一篇文章:https://wiki.jenkins-ci.org/display/JENKINS/ProcessTreeKiller,这篇文章进一步描述了Hudson杀掉衍生进程的情况:

The ProcessTreeKiller takes advantage of the fact that by default a new process gets a copy of the environment variables of its spawning/creating process.

It sets a specific environment variable in the process executing the build job. Later, when the user requests to stop the build job's process it gets a list of all processes running on the computer and their environment variables, and looks for the environment variable that it initially set for the build job's process.

Every job with that environment variable in its environment is then terminated.

意思就是说,Jenkins会在执行Job时设置一系列的环境变量,这些环境变量将被Job衍生出的进程所继承。Jenkins在Kill掉衍生进程的时候会查看进程的环境变量,如果找到它之前设置的环境变量,就将其杀掉。

因此,Wiki中也给出了另外一个简单的方法来避免进程被杀掉:

A convenient way to achieve that is to change the environment variable BUILD_ID which Jenkins's ProcessTreeKiller is looking for. This will cause Jenkins to assume that your daemon is not spawned by the Jenkins build.

修改Hudson设置的环境变量BUILD_ID的值,从而让Jenkins认为此进程不是由Job的构建过程衍生的,如:

  1. BUILD_ID=dontKillMe /usr/apache/bin/httpd

后面的"/usr/apache/bin/httpd"可以省略,即只需要在parameter build trigger中加入一个string parameter,变量名为BUILD_ID,值为dontKillMe即可。

3. 启动时添加禁用参数

除以上两种方式以外,上面的Wiki页面中还提到了第三种解决办法,个人觉得这种方案最靠谱最彻底,不需要再去配置每个Job了:

you can disable this feature by setting a Javaproperty named "hudson.util.ProcessTree.disable" to the value "true". This can be done as a parameter to the "Java" binary when starting Jenkins:

在启动Jenkins的时候直接通过Java选项来关闭Jenkins杀掉所有衍生进程的这个功能:

  1. java -Dhudson.util.ProcessTree.disable=true -jar jenkins.war
 
0

修改Jenkins启动衍生进程的生命周期的更多相关文章

  1. 修改jenkins启动的默认用户

    # 背景 通过yum命令安装的jenkins,通过service jenkins去启动jenkins的话,默认的用户是jenkins,但jenkins这个用户是无法通过su切换过去的 ,在某些环节可能 ...

  2. jenkins 杀死衍生进程

    解决方法-1: 在execute shell输入框中加入BUILD_ID=DONTKILLME,即可防止jenkins衍生进程 解决方法-2: 修改/etc/sysconfig/jenkins配置,在 ...

  3. Android进程的生命周期

    Android系统想要永久的保留一个应用进程差点儿是不可能的.所以系统就须要不断的释放老的或者不太重要的进程以便腾出足够的内存空间来执行新的或者更重要的进程,那么系统怎样决定哪个进程应该保留哪个应该杀 ...

  4. SpringBean容器启动流程+Bean的生命周期【附源码】

    如果对SpringIoc与Aop的源码感兴趣,可以访问参考:https://javadoop.com/,十分详细. 目录 Spring容器的启动全流程 Spring容器关闭流程 Bean 的生命周期 ...

  5. 【IOS6.0 自学瞎折腾】(五)应用程序的启动过程和Application生命周期

    一 :main函数入口 看下项目资源结构,其实程序的入口也是在main.m里面. #import <UIKit/UIKit.h> #import "BvinAppDelegate ...

  6. JAVA Eclipse的Android的进程和生命周期是什么

    安卓程序的生命周期是不受自己控制的,安卓的程序根据不同的重要性做了一些区分,最重要的进程仅仅在安卓已经崩溃或者卡死的情况下才会终止前台进程.   Activity就是表现层的界面,它有三种常见的状态, ...

  7. iOS启动原理及应用生命周期

    ios程序启动原理及生命周期图: ios应用程序的入口是main.m 1 #import <UIKit/UIKit.h> 2 3 #import "WYSAppDelegate. ...

  8. jenkins:通过execute shell启动的进程会被杀死的问题

    [问题]在jenkins中配置自动更新部署项目时,如果采取用execute shell启动/关闭tomcat,会发现可以进行关闭tomcat,但是无法启动tomcat,虽然构建会显示执行成功,但是查看 ...

  9. jenkins中通过execute shell启动的进程会被杀死的问题

    在jenkins中配置自动更新部署项目时,如果采取用execute shell启动/关闭tomcat,会发现可以进行关闭tomcat, 但是无法启动tomcat,虽然构建会显示执行成功,但是查看进程, ...

随机推荐

  1. 2.Nexus更新索引

    1.手动更新1.  下载索引文件在http://repo.maven.apache.org/maven2/.index/ 中下载nexus-maven-repository-index.gznexus ...

  2. 利用递归生成组合数C(n,m)

    /*===================================== 数的组合问题.从1,2,…,n中取出m个数,将所有组合按照字典顺序列出. 如n=3,m=2时,输出: 1 2 1 3 2 ...

  3. java 获取实体类对象属性值的方法

    在java中我们要获得实体类对象的属性,一般情况是将实体类中的属性私有化,然后再对外提供get()与set()方法,然后再获取实体类对象的属性的时候先把对象new出来,再用变量名.get()的方法得到 ...

  4. Keepalived+MySQL实现高可用(转)

    http://www.cnblogs.com/wingsless/p/4033093.html   MHA高可用 http://www.cnblogs.com/gomysql/p/3856484.ht ...

  5. iptables基础信息介绍

    在linux系统下,网络安全,除了有SElinux,另外就是iptables防火墙了,这个是用的最多也是功能非常强大的一个工具,今天就对其简单的架构上技术进行概要描述.让自己后续能够逻辑清晰的处理云环 ...

  6. php访问mysql工具类

    本文转载自:http://www.cnblogs.com/lida/archive/2011/02/18/1958211.html <?php class mysql { private $db ...

  7. 【VNC】Ubuntu14.04LTS下安装VNC View

    # apt-get install tightvncserver vnc4server gnome-panel gnome-settings-daemon metacity nautilus gnom ...

  8. MySQL压缩包安装

    1.解压缩 2.添加环境变量 3.添加配置文件 my.ini 4.以管理员身份初始化数据库 mysqld --initialize --user=mysql --console 5.以管理员身份将My ...

  9. Python 通过print将数据保存到文件中

    1. Print them to screen man = [] other = [] try: data = open('sketch.txt') for each_line in data: tr ...

  10. ros的相关link

    http://markzhang.cn/blog/2014/08/19/ros-basic-setup/ http://blog.csdn.net/boliang319/article/details ...