JBoss 7/WildFly 以 domain 模式启动时会启动多个 JVM,例如如下通过启动脚本启动 domain 模式:
./domain.sh
[kylin@localhost tdump]$ jps -l
23655 /home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar
23671 /home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar
23736 /home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar
domain.sh 脚本中如下信息:
eval \"$JAVA\" -D\"[Process Controller]\" $PROCESS_CONTROLLER_JAVA_OPTS \
\"-Dorg.jboss.boot.log.file=$JBOSS_LOG_DIR/process-controller.log\" \
\"-Dlogging.configuration=file:$JBOSS_CONFIG_DIR/logging.properties\" \
-jar \"$JBOSS_HOME/jboss-modules.jar\" \
-mp \"${JBOSS_MODULEPATH}\" \
org.jboss.as.process-controller \
-jboss-home \"$JBOSS_HOME\" \
-jvm \"$JAVA_FROM_JVM\" \
-mp \"${JBOSS_MODULEPATH}\" \
-- \
\"-Dorg.jboss.boot.log.file=$JBOSS_LOG_DIR/host-controller.log\" \
\"-Dlogging.configuration=file:$JBOSS_CONFIG_DIR/logging.properties\" \
$HOST_CONTROLLER_JAVA_OPTS \
-- \
-default-jvm \"$JAVA_FROM_JVM\" \
'"$@"'
JBOSS_STATUS=$?
org.jboss.as
jboss-as-process-controller
7.2.0.Final-redhat-8
PROCESS_CONTROLLER_JAVA_OPTS="$PROCESS_CONTROLLER_JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8788,server=y,suspend=y"
HOST_CONTROLLER_JAVA_OPTS="$HOST_CONTROLLER_JAVA_OPTS -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=y"
对照之前的启动脚本,main 方法传入的参数如下:
-jboss-home, /home/kylin/work/eap/jboss-eap-6.1,
-jvm, /usr/java/jdk1.7.0_21/bin/java,
-mp, /home/kylin/work/eap/jboss-eap-6.1/modules,
--,
-Dorg.jboss.boot.log.file=/home/kylin/work/eap/jboss-eap-6.1/domain/log/host-controller.log,
-Dlogging.configuration=file:/home/kylin/work/eap/jboss-eap-6.1/domain/configuration/logging.properties,
-server, -Xms63m, -Xmx512m, -XX:MaxPermSize=256m, -Djava.net.preferIPv4Stack=true, -Djboss.modules.system.pkgs=org.jboss.byteman,
-Djava.awt.headless=true, -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=y,
--,
-default-jvm, /usr/java/jdk1.7.0_21/bin/java
下图描述 domain 模式启动的过程:
根据上图描述,我们将 domain 模式启动描述为以下步骤:
Process Controller 和 Host Controller 属于不同的 JVM,Process Controller 启动 Host Controller 是在一个 JVM 中启动另一个 JVM,启动代码位于 `org.jboss.as.process.ManagedProcess` 如下图所示:
我们可以通过如下代码模拟:
public static void main(String[] args) throws IOException {
List command = new ArrayList();
command.add("/usr/java/jdk1.7.0_21/bin/java");
command.add("-jar");
command.add("/home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar");
command.add("-version");
ProcessBuilder builder = new ProcessBuilder(command);
builder.directory(new File("/home/kylin/tmp"));
Process process = builder.start();
final InputStream stdout = process.getInputStream();
Thread stdoutThread = new Thread(new ReadTask(stdout, System.out));
stdoutThread.start();
}
运行如上代码输出JBoss EAP 6.1 所使用的 JBoss Module 的版本号:
[Host Controller] JBoss Modules version 1.2.0.Final-redhat-1
/usr/java/jdk1.7.0_21/bin/java, -D[Host Controller],
-Dorg.jboss.boot.log.file=/home/kylin/work/eap/jboss-eap-6.1/domain/log/host-controller.log,
-Dlogging.configuration=file:/home/kylin/work/eap/jboss-eap-6.1/domain/configuration/logging.properties,
-server, -Xms63m, -Xmx512m, -XX:MaxPermSize=256m, -Djava.net.preferIPv4Stack=true, -Djboss.modules.system.pkgs=org.jboss.byteman,
-Djava.awt.headless=true, -agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=y,
-jar, /home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar,
-mp, /home/kylin/work/eap/jboss-eap-6.1/modules,
-jaxpmodule, javax.xml.jaxp-provider, org.jboss.as.host-controller,
-mp, /home/kylin/work/eap/jboss-eap-6.1/modules,
--pc-address, 127.0.0.1,
--pc-port, 50396,
-default-jvm, /usr/java/jdk1.7.0_21/bin/java,
-Djboss.home.dir=/home/kylin/work/eap/jboss-eap-6.1
`org.jboss.as.host.controller.Main` 中传入的参数如下:
-mp, /home/kylin/work/eap/jboss-eap-6.1/modules,
--pc-address, 127.0.0.1,
--pc-port, 45210,
-default-jvm, /usr/java/jdk1.7.0_21/bin/java,
-Djboss.home.dir=/home/kylin/work/eap/jboss-eap-6.1
Process Controller 启动 Server 过程完全类似,只是要启动的 Server 信息是通过 Host Controller传递过来的,传递过来的 ProcessBuilder 传入的参数如下:
/usr/java/jdk1.7.0_21/bin/java, -D[Server:server-one],
-XX:PermSize=256m, -XX:MaxPermSize=256m, -Xms1303m, -Xmx1303m, -server, -D[Host Controller]=true,
-Djava.awt.headless=true, -Djboss.modules.system.pkgs=org.jboss.byteman, -Djboss.home.dir=/home/kylin/work/eap/jboss-eap-6.1,
-Djava.net.preferIPv4Stack=true, -Djboss.server.log.dir=/home/kylin/work/eap/jboss-eap-6.1/domain/servers/server-one/log,
-Djboss.server.temp.dir=/home/kylin/work/eap/jboss-eap-6.1/domain/servers/server-one/tmp,
-Djboss.server.data.dir=/home/kylin/work/eap/jboss-eap-6.1/domain/servers/server-one/data,
-Dlogging.configuration=file:/home/kylin/work/eap/jboss-eap-6.1/domain/servers/server-one/data/logging.properties,
-jar, /home/kylin/work/eap/jboss-eap-6.1/jboss-modules.jar,
-mp, /home/kylin/work/eap/jboss-eap-6.1/modules, -jaxpmodule, javax.xml.jaxp-provider, org.jboss.as.server
PC 是指 Process Controller,HC 是指 Host Controller(与 HC 相对应的是 Domain Controller,简称 DC),Server 指的是 JBoss 服务器。
从功能层面来说,PC 用来启动和停止 HC 和 Server,且PC 启动停止 Server 首先需要得到 HC 发来的指令,domain 模式启动完成后会启动如下线程用来停止 HC 和 Servers:
"reaper for Host Controller" prio=10 tid=0x7fc3b000 nid=0x770f in Object.wait() [0x803ab000]
"reaper for Server:server-one" prio=10 tid=0x8320b400 nid=0x7750 in Object.wait() [0x7fdfe000]
"stdout for Host Controller" prio=10 tid=0x7fc3a400 nid=0x770e runnable [0x803fc000]
"stderr for Host Controller" prio=10 tid=0x7fc36000 nid=0x770d runnable [0x8087d000]
"stdout for Server:server-one" prio=10 tid=0x83209c00 nid=0x774f runnable [0x7ff5c000]
"stderr for Server:server-one" prio=10 tid=0x83208400 nid=0x774e runnable [0x7ffad000]
Server 是指 JBoss 服务器平台,为 JEE 应用提供容器。
本部分演示通过 OS 信号关闭 Server 时 PC 和 HC 相关的 Action。我们通过如下步骤演示:
观察日志,我们看到如下日志输出:
21:39:08,800 INFO [org.jboss.as.process.Server:server-one.status] (reaper for Server:server-one) JBAS012010: Process 'Server:server-one' finished with an exit status of 137
[Host Controller] 21:39:08,801 INFO [org.jboss.as.host.controller] (ProcessControllerConnection-thread - 2) JBAS010926: Unregistering server server-one
[Host Controller] 21:39:08,806 INFO [org.jboss.as.host.controller] (Remoting "localhost.localdomain:MANAGEMENT" read-1) JBAS010926: Unregistering server server-one
public void run() {
final Process process;
synchronized (lock) {
process = ManagedProcess.this.process;
}
int exitCode;
for (;;) try {
exitCode = process.waitFor();
log.processFinished(processName, Integer.valueOf(exitCode));
break;
} catch (InterruptedException e) {
// ignore
}
boolean respawn = false;
boolean slowRespawn = false;
boolean unlimitedRespawn = false;
int respawnCount = 0;
synchronized (lock) {
final long endTime = System.currentTimeMillis();
processController.processStopped(processName, endTime - startTime);