r2wee 发表于 2014-8-6 08:39:39

一次Tomcat溢出的临时处理

公司服务器上Tomcat不知哪个项目有隐患代码,经常溢出,不停的重启!    起初打算用Jprofiler监控下内存(回头会准备个完整的例子),但发现线上环境bin目录下的.sh被修改的乱七八糟,导致某些.sh无法运行,所以就打算写个RMI的定时gc程序,现用虚拟机模拟下线上环境
    环境信息如下:
      Red Hat Enterprise Linux Server release 6.3 (Santiago)   
      Java(TM) SE Runtime Environment (build 1.6.0_45-b06)
      apache-tomcat-6.0.41
      jprofiler7 linux-x64
      ip:    10.211.55.4

------------------------------------------------------------------------------------------------------------------------

1.配置Tomcat RMI

    Tomcat打开RMI

1
JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=9999 -Djava.rmi.server.hostname=10.211.55.4 -Dcom.sun.management.jmxremote.authenticate=true -Dcom.sun.management.jmxremote.ssl=false"




    配置hostname
1
hostname 10.211.55.4




    防火墙开放端口

1
-A INPUT -m state --state NEW -m tcp -p tcp --dport 9999 -j ACCEPT




   重启防火墙
1
/etc/init.d/iptables restart




    配置授权
      a.拷贝jmxremote.password.template到本地目录,名为jmxremote.password

1
2
cd /usr/java/jdk1.6.0_45/jre/lib/management
cp jmxremote.password.template jmxremote.password




      b.编辑jmxremote.access文件,添加用户和权限


1
2
3
tango         readwrite \
            create javax.management.monitor.*,javax.management.timer.* \
            unregister




      c.编辑jmxremote.password文件,设置用户密码

1
tango   rmipassword




      d.修改jmxremote.password文件为只读

1
chmod 600 jmxremote.password




    用Jconsole测试RMI
      a.启动Tomcat

1
./startup.sh




      b.测试RMI,客户端键入如下命令,前提是java安装目录配置到PATH中




            显示以上画面,则说明rmi连接成功!


2.编写程序
      需求:

                1.定时通过RMI通知remote jvm 执行gc任务,

                2.执行次数和运行时间


      代码片段如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public static void main(String[] args) throws IOException, MalformedObjectNameException {
      Properties properties = Console.parseArguments(args);
      //
      final String host = properties.getProperty(HOST, "localhost");
      final String port = properties.getProperty(PORT, "1099");
      final String interval = properties.getProperty(INTERVAL);
      final String tryCount = properties.getProperty(TRY);
      final String rmiServer = getRMIServer(host, port);
      final String user = properties.getProperty(USER);
      final String pass = properties.getProperty(PASS);
      final String report = properties.getProperty(REPORT, "./gc.out");
      //
      final Invoke invoke = new Invoke() {
            @Override
            public Object execute(JMXConnector connector) throws IOException, MalformedObjectNameException {
                MBeanServerConnection mBeanServerConnection = connector.getMBeanServerConnection();
                MemoryMXBean memoryMXBean = JMX.newMBeanProxy(mBeanServerConnection, ObjectName.getInstance("java.lang:type=Memory"), MemoryMXBean.class);
                memoryMXBean.gc();
                return null;
            }
      };
      if (interval == null) {
            execute(rmiServer, user, pass, invoke);
      } else {
            final int i = interval.matches("\\d+") ? Integer.parseInt(interval) : 6000;
            final int t = tryCount.matches("\\d+") ? Integer.parseInt(tryCount) : 3;

            final File reportFile = new File(report);
            if (!reportFile.exists()) {
                reportFile.createNewFile();
            } else if (reportFile.isDirectory()) {
                throw new RuntimeException(new MessageFormat("can`t write file {0},file is directory!").format(new String[]{reportFile.getAbsolutePath()}));
            } else if (!reportFile.canWrite()) {
                throw new RuntimeException(new MessageFormat("can`t write file {0},file is readonly!").format(new String[]{reportFile.getAbsolutePath()}));
            }
            new Thread(new Runnable() {

                private final ThreadLocal<AtomicInteger> error = new ThreadLocal<AtomicInteger>();
                private final ThreadLocal<AtomicInteger> local = new ThreadLocal<AtomicInteger>();
                private final ThreadLocal<Date> start = new ThreadLocal<Date>();

                @Override
                public void run() {
                  local.set(new AtomicInteger(0));
                  error.set(new AtomicInteger(0));
                  start.set(new Date());
                  while (true) {
                        AtomicInteger errorAtomic = error.get();
                        try {
                            if (errorAtomic.get() > t) {
                              return;
                            }
                            execute(rmiServer, user, pass, invoke);
                            Thread.sleep(i);
                        } catch (Exception e) {
                            e.printStackTrace();
                            errorAtomic.addAndGet(1);
                        }
                        report();
                  }
                }

                private void report() {
                  AtomicInteger runAtomic = local.get();
                  AtomicInteger errorAtomic = error.get();
                  Date date = start.get();
                  runAtomic.addAndGet(1);
                  try {
                        FileOutputStream fileOutputStream = new FileOutputStream(reportFile);
                        PrintWriter writer = new PrintWriter(fileOutputStream, false);
                        writer.write("run : ".concat(String.valueOf(runAtomic.get())));
                        writer.write("\r\n");
                        long l = (new Date().getTime() - date.getTime()) / 1000;
                        writer.write("run time: ".concat(String.valueOf(l).concat("s")));
                        writer.write("\r\n");
                        writer.write("error : ".concat(String.valueOf(errorAtomic.get())));
                        writer.write("\r\n");
                        writer.flush();
                        writer.close();
                  } catch (FileNotFoundException e) {
                        System.err.println(e.getMessage());
                        throw new RuntimeException(e);
                  }
                }
            }).start();
      }
    }





   get start:


1
java -classpath "..." org.tango.tools.Gc --host=10.211.55.4 --port=9999 --interval=10000 --try=10 --user=tango --pass=rmipassword





   



此方法是被逼无奈,最好还是检查工程代码,查看溢出原因!
下回说Jprofiler监控Tomcat

本文完!(下附工程代码,maven构建)



页: [1]
查看完整版本: 一次Tomcat溢出的临时处理