Skip to content

Commit ca28204

Browse files
zhucegepxcaspar
authored andcommitted
- 支持触发jvm full gc实验
Signed-off-by: shizhi.zhu <shizhi.zhu@qunar.com>
1 parent 0beb568 commit ca28204

File tree

5 files changed

+291
-0
lines changed

5 files changed

+291
-0
lines changed

chaosblade-exec-plugin/chaosblade-exec-plugin-jvm/src/main/java/com/alibaba/chaosblade/exec/plugin/jvm/JvmConstant.java

+6
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,10 @@ public interface JvmConstant {
8282

8383
String ACTION_THREAD_WAIT = "wait";
8484
String ACTION_THREAD_RUNNING = "running";
85+
86+
87+
String FLAG_FULL_GC_INTERVAL = "interval";
88+
String FLAG_FULL_GC_TOTAL_COUNT = "effect-count";
89+
String ACTION_FULL_GC_NAME = "full-gc";
90+
String ACTION_FULL_GC_ALIAS = "fgc";
8591
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.alibaba.chaosblade.exec.plugin.jvm.gc;
2+
3+
import com.alibaba.chaosblade.exec.common.aop.EnhancerModel;
4+
import com.alibaba.chaosblade.exec.common.aop.PredicateResult;
5+
import com.alibaba.chaosblade.exec.common.constant.CategoryConstants;
6+
import com.alibaba.chaosblade.exec.common.model.FlagSpec;
7+
import com.alibaba.chaosblade.exec.common.model.Model;
8+
import com.alibaba.chaosblade.exec.common.model.action.ActionModel;
9+
import com.alibaba.chaosblade.exec.common.model.action.BaseActionSpec;
10+
import com.alibaba.chaosblade.exec.common.model.action.DirectlyInjectionAction;
11+
import com.alibaba.chaosblade.exec.plugin.jvm.JvmConstant;
12+
import com.alibaba.chaosblade.exec.plugin.jvm.StoppableActionExecutor;
13+
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
17+
/**
18+
* @author shizhi.zhu@qunar.com
19+
*/
20+
public class FullGCActionSpec extends BaseActionSpec implements DirectlyInjectionAction {
21+
22+
public FullGCActionSpec() {
23+
super(new FullGCExecutor());
24+
}
25+
26+
@Override
27+
public String getName() {
28+
return JvmConstant.ACTION_FULL_GC_NAME;
29+
}
30+
31+
@Override
32+
public String[] getAliases() {
33+
return new String[]{JvmConstant.ACTION_FULL_GC_ALIAS};
34+
}
35+
36+
@Override
37+
public String getShortDesc() {
38+
return "JVM full gc";
39+
}
40+
41+
@Override
42+
public String getLongDesc() {
43+
return "JVM full gc";
44+
}
45+
46+
@Override
47+
public List<FlagSpec> getActionFlags() {
48+
List<FlagSpec> flagSpecs = new ArrayList<FlagSpec>();
49+
flagSpecs.add(new FullGCIntervalFlagSpec());
50+
flagSpecs.add(new FullGCEffectCountFlagSpec());
51+
return flagSpecs;
52+
}
53+
54+
@Override
55+
public PredicateResult predicate(ActionModel actionModel) {
56+
return PredicateResult.success();
57+
}
58+
59+
@Override
60+
public String[] getCategories() {
61+
return new String[]{CategoryConstants.JAVA_RESOURCE_MEMORY, CategoryConstants.JAVA_RESOURCE_CPU};
62+
}
63+
64+
@Override
65+
public void createInjection(String uid, Model model) throws Exception {
66+
EnhancerModel enhancerModel = new EnhancerModel(EnhancerModel.class.getClassLoader(), model.getMatcher());
67+
enhancerModel.merge(model);
68+
getActionExecutor().run(enhancerModel);
69+
}
70+
71+
@Override
72+
public void destroyInjection(String uid, Model model) throws Exception {
73+
EnhancerModel enhancerModel = new EnhancerModel(EnhancerModel.class.getClassLoader(), model.getMatcher());
74+
enhancerModel.merge(model);
75+
((StoppableActionExecutor) getActionExecutor()).stop(enhancerModel);
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.alibaba.chaosblade.exec.plugin.jvm.gc;
2+
3+
import com.alibaba.chaosblade.exec.common.model.FlagSpec;
4+
import com.alibaba.chaosblade.exec.plugin.jvm.JvmConstant;
5+
6+
/**
7+
* @author shizhi.zhu@qunar.com
8+
*/
9+
public class FullGCEffectCountFlagSpec implements FlagSpec {
10+
@Override
11+
public String getName() {
12+
return JvmConstant.FLAG_FULL_GC_TOTAL_COUNT;
13+
}
14+
15+
@Override
16+
public String getDesc() {
17+
return "total count of full gc actions";
18+
}
19+
20+
@Override
21+
public boolean noArgs() {
22+
return false;
23+
}
24+
25+
@Override
26+
public boolean required() {
27+
return false;
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package com.alibaba.chaosblade.exec.plugin.jvm.gc;
2+
3+
import com.alibaba.chaosblade.exec.common.aop.EnhancerModel;
4+
import com.alibaba.chaosblade.exec.common.util.ConfigUtil;
5+
import com.alibaba.chaosblade.exec.plugin.jvm.JvmConstant;
6+
import com.alibaba.chaosblade.exec.plugin.jvm.StoppableActionExecutor;
7+
import org.slf4j.Logger;
8+
import org.slf4j.LoggerFactory;
9+
10+
import javax.management.*;
11+
import java.lang.management.ManagementFactory;
12+
import java.util.Set;
13+
import java.util.concurrent.Executors;
14+
import java.util.concurrent.ScheduledExecutorService;
15+
import java.util.concurrent.ThreadFactory;
16+
import java.util.concurrent.TimeUnit;
17+
import java.util.concurrent.atomic.AtomicBoolean;
18+
import java.util.concurrent.atomic.AtomicInteger;
19+
20+
/**
21+
* @author shizhi.zhu@qunar.com
22+
*/
23+
public class FullGCExecutor implements StoppableActionExecutor {
24+
25+
private static final Logger LOGGER = LoggerFactory.getLogger(FullGCExecutor.class);
26+
27+
private volatile ScheduledExecutorService scheduledExecutorService;
28+
private AtomicInteger fullGCCounter = new AtomicInteger();
29+
private final AtomicBoolean started = new AtomicBoolean(false);
30+
31+
private final MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
32+
33+
@Override
34+
public synchronized void run(EnhancerModel enhancerModel) throws Exception {
35+
if (started.compareAndSet(false, true)) {
36+
final int interval = ConfigUtil.getActionFlag(enhancerModel, JvmConstant.FLAG_FULL_GC_INTERVAL, 0);
37+
final int totalCount = ConfigUtil.getActionFlag(enhancerModel, JvmConstant.FLAG_FULL_GC_TOTAL_COUNT, 0);
38+
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
39+
@Override
40+
public Thread newThread(Runnable r) {
41+
return new Thread(r, "chaosblade-fgc-thread");
42+
}
43+
});
44+
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
45+
@Override
46+
public void run() {
47+
try {
48+
if (totalCount > 0 && fullGCCounter.get() >= totalCount) {
49+
doStop();
50+
return;
51+
}
52+
doGc();
53+
} catch (Exception e) {
54+
LOGGER.error("do gcClassHistogram error", e);
55+
}
56+
}
57+
}, 0, interval, TimeUnit.MILLISECONDS);
58+
} else {
59+
LOGGER.warn("another executor is running now");
60+
}
61+
}
62+
63+
@Override
64+
public synchronized void stop(EnhancerModel enhancerModel) throws Exception {
65+
doStop();
66+
}
67+
68+
private void doStop() {
69+
if (started.compareAndSet(true, false)) {
70+
if (scheduledExecutorService != null && !scheduledExecutorService.isShutdown()) {
71+
try {
72+
scheduledExecutorService.shutdownNow();
73+
} catch (Exception e) {
74+
LOGGER.error("shutdown executor error", e);
75+
}
76+
scheduledExecutorService = null;
77+
fullGCCounter = new AtomicInteger();
78+
LOGGER.info("jvm full gc stopped");
79+
}
80+
}
81+
}
82+
83+
private void doGc() throws MalformedObjectNameException, IntrospectionException, ReflectionException, InstanceNotFoundException, MBeanException {
84+
if (jvmBefore8()) {
85+
doGCHistogramInSeparateProcess();
86+
} else {
87+
doGcHistogramInMbean();
88+
}
89+
}
90+
91+
private void doGcHistogramInMbean() throws MalformedObjectNameException, IntrospectionException, InstanceNotFoundException, ReflectionException, MBeanException {
92+
Set<ObjectName> objectNames = mbeanServer.queryNames(new ObjectName("com.sun.management:type=DiagnosticCommand"), null);
93+
if (objectNames == null || objectNames.isEmpty()) {
94+
LOGGER.warn("no mBean found, exit");
95+
return;
96+
}
97+
for (ObjectName name : objectNames) {
98+
MBeanInfo mBeanInfo = mbeanServer.getMBeanInfo(name);
99+
MBeanOperationInfo[] operations = mBeanInfo.getOperations();
100+
for (MBeanOperationInfo op : operations) {
101+
if (op.getName().equals("gcClassHistogram")) {
102+
String[] emptyStringArgs = {};
103+
Object[] dcmdArgs = {emptyStringArgs};
104+
String[] signature = {String[].class.getName()};
105+
Object invoke = mbeanServer.invoke(name, op.getName(), dcmdArgs, signature);
106+
int count = fullGCCounter.getAndIncrement();
107+
LOGGER.debug("do gc class histogram count:{} \n, {}", count, invoke);
108+
}
109+
}
110+
}
111+
}
112+
113+
private void doGCHistogramInSeparateProcess() {
114+
int pid = getPid();
115+
String cmd = null;
116+
try {
117+
String javaHome = System.getenv("JAVA_HOME");
118+
if (javaHome.endsWith("/")) {
119+
javaHome = javaHome.substring(0, javaHome.length() - 1);
120+
}
121+
cmd = javaHome + "/bin/jmap";
122+
ProcessBuilder pb = new ProcessBuilder(cmd, "-histo:live", String.valueOf(pid));
123+
Process start = pb.start();
124+
int count = fullGCCounter.getAndIncrement();
125+
start.waitFor();
126+
LOGGER.debug("do gc class histogram in separate process count:{} cmd:{}", count, cmd);
127+
} catch (Exception e) {
128+
LOGGER.error("exec jmap error, cmd:{}", cmd, e);
129+
}
130+
}
131+
132+
private static int getPid() {
133+
byte pid = 0;
134+
try {
135+
String name = ManagementFactory.getRuntimeMXBean().getName();
136+
return Integer.parseInt(name.substring(0, name.indexOf('@')));
137+
} catch (Throwable e) {
138+
return pid;
139+
}
140+
}
141+
142+
private boolean jvmBefore8() {
143+
String javaVersion = System.getProperty("java.version");
144+
String[] versions = javaVersion.split("\\.");
145+
if (Integer.parseInt(versions[1]) >= 8) {
146+
return false;
147+
}
148+
return true;
149+
}
150+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.alibaba.chaosblade.exec.plugin.jvm.gc;
2+
3+
import com.alibaba.chaosblade.exec.common.model.FlagSpec;
4+
import com.alibaba.chaosblade.exec.plugin.jvm.JvmConstant;
5+
6+
/**
7+
* @author shizhi.zhu@qunar.com
8+
*/
9+
public class FullGCIntervalFlagSpec implements FlagSpec {
10+
@Override
11+
public String getName() {
12+
return JvmConstant.FLAG_FULL_GC_INTERVAL;
13+
}
14+
15+
@Override
16+
public String getDesc() {
17+
return "Interval between full gc actions";
18+
}
19+
20+
@Override
21+
public boolean noArgs() {
22+
return false;
23+
}
24+
25+
@Override
26+
public boolean required() {
27+
return false;
28+
}
29+
}

0 commit comments

Comments
 (0)