【问题标题】:CPU usage going 100% on making any transaction进行任何交易时 CPU 使用率将达到 100%
【发布时间】:2019-09-03 06:31:10
【问题描述】:

最近我遇到了一个奇怪的场景,我可以看到应用程序在某个时间点后速度变慢,导致我无法加载应用程序。

所以我开始监控服务器,发现对于某些场景,GC 活动超过 60%,并且直接影响应用程序性能,因此为了修复它,我尝试将堆内存增加到 2.5G从 2GB 开始,但我仍然可以找到同样的问题,任何人都可以帮助我进一步增加堆大小是一种理想的方法或我可以做的其他事情。

系统内存容量:6 GB

以下是 VisualVm 监控截图:

如果需要进一步的信息进行分析,请告诉我。

线程转储:

http-apr-8080-exec-15" - Thread t@110
   java.lang.Thread.State: RUNNABLE
        at java.util.regex.Pattern$BnM.match(Pattern.java:5464)
        at java.util.regex.Matcher.search(Matcher.java:1248)
        at java.util.regex.Matcher.find(Matcher.java:637)
        at java.util.regex.Matcher.replaceAll(Matcher.java:951)
        at java.lang.String.replace(String.java:2240)
        at com.srik.security.SecureTrace.maskOther(SecureTrace.java:135)
        at com.srik.security.SecureTrace.maskJsonData(SecureTrace.java:102)
        at com.srik.mbweb.manager.MUSR.printResponse(MUSR.java:261)
        at com.srik.mbweb.manager.MUSR.invokeService(MUSR.java:212)
        at com.srik.mbweb.manager.MU.invokeCacheableService(MU.java:30)
        at com.srik.mbweb.manager.MU$$FastClassBySpringCGLIB$$45933c60.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.cache.interceptor.CacheInterceptor$1.invoke(CacheInterceptor.java:52)
        at org.springframework.cache.interceptor.CacheAspectSupport.invokeOperation(CacheAspectSupport.java:345)
        at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:408)
        at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:327)
        at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:61)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
        at com.srik.mbweb.manager.MU$$EnhancerBySpringCGLIB$$36289a8f.invokeCacheableService(<generated>)
        at com.srik.mbweb.manager.ChannelUnitedServiceManagerProxy.invokeService(ChannelUnitedServiceManagerProxy.java:35)
        at com.srik.mbweb.controller.MobileUnitedController.processRequest(MobileUnitedController.java:32)
        at com.srik.mbweb.controller.MobileUnitedControllerBase.invokeService(MobileUnitedControllerBase.java:58)
        at sun.reflect.GeneratedMethodAccessor216.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.statemachine.web.AbstractStateMachineAwareFilter.doFilterInternal(AbstractStateMachineAwareFilter.java:63)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.mbweb.common.PreAuthenticationFilter.doFilterInternal(PreAuthenticationFilter.java:137)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.mbweb.common.StatelessCSRFFilter.doFilterInternal(StatelessCSRFFilter.java:51)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.mbweb.common.LoggerFilter.doFilterInternal(LoggerFilter.java:30)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.mbweb.multitenant.filter.FITenantFilter.doFilterInternal(FITenantFilter.java:110)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at com.srik.mbweb.multitenant.filter.FITenantFilter.doFilterInternal(FITenantFilter.java:110)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:528)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1100)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:687)
        at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2521)
        at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2510)
        - locked <1e41e77c> (a org.apache.tomcat.util.net.AprEndpoint$AprSocketWrapper)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

   Locked ownable synchronizers:
        - locked <5896885f> (a java.util.concurrent.ThreadPoolExecutor$Worker)

SecureTrace 方法:

private static Pattern PWD_XML_PATTERN = Pattern.compile("^(<.*?(?:(?i)Aomn|Amn|amn|aamn)>)(.*?)(<\\/.*?(?:(?i)Aomn|Amn|amn|aamn)>)");
 public static String maskData(String data) {
       try {
         for(Matcher m = PWD_XML_PATTERN.matcher(data); m.find(); data = m.replaceAll("AA****BB")) {

             ;
         }
       } catch (Exception var2) {
       var2.printStackTrace();
       }

      return maskOther(data);
   }

  private static String maskOther(String data) {
       String mask = null;
       int groupLen = false;
      Matcher matcher = null;
       try {
        matcher = MASK_PATTERN.matcher(data);
        while(matcher.find()) {
           mask = "****";
           String group = matcher.group();
            int groupLen = group.length();
            if (groupLen > 5) {
              mask = mask + group.substring(groupLen - 4);
                data = data.replace(group, mask);
             }
          }
      } catch (Exception var5) {
         ;      }

      return data;
   }

【问题讨论】:

  • 显示com.srik.security.SecureTrace
  • @user7294900 我已经更新了 SecureTrace 代码
  • MASK_PATTERN 中未显示的问题
  • 您在代码中使用MASK_PATTERN,但您没有显示它的价值,这可能是您需要更改的扩展正则表达式
  • 首先,你不应该吞下所有的异常。如果有异常,请修复错误。如果没有,请不要编写过时的 try … catch 构造。那么,1.6% 的 CPU 负载与 100% 相差甚远。但是您的代码正在浪费性能。当你有一个Matcher 时,为什么不按预期使用它,而是对字符串执行多次replace 调用?同样,在您的maskData 中,您为什么重复 执行相同的replaceAll 操作?

标签: performance java-8 heap-memory tomcat8 visualvm


【解决方案1】:

目前尚不清楚发布的代码与 CPU 使用率的峰值有多大关系,因为看起来您在 CPU 负载接近于零时创建了快照。您应该使用采样器/分析器来收集有关实际瓶颈的数据。

但值得考虑的是,CPU 使用率达到 100% 的峰值并非不自然。除了空闲 (0%) 或处理代码 (100%) 之外,单个 CPU 内核不知道其他模式。工具显示的任何中间数字都是平滑多个 0% 和 100% 值的结果。当看到 100% 的峰值时,这仅意味着“执行代码”阶段持续的时间比用于平滑的时间窗口长。

但是垃圾收集器的活动看起来确实很高,而且内存使用模式似乎很合适。因此,您可以测试在为其提供更多堆内存时行为如何变化。但是不要使用小到 25% 的增量,这只是为了得到矛盾的结果。当您有 6 G 可用时,将堆翻倍至 4 G 甚至提升至 5 G。如果您仍然看到相同的模式,那么您就有问题了。检查您的代码中是否没有明确的 System.gc() 调用或类似调用。如果那个大堆内存解决了问题,则在该数字和旧堆大小之间寻找最佳折衷方案(注意二分搜索的工作原理)。

不过,您发布的代码仍然存在问题。首先,有问题的try … catch 块。由于在这段不涉及外部条件的代码中,任何异常都是编程错误的指标,因此您应该解决任何现有的错误,而不是捕获异常。

关于性能,你做了很多重复的工作。

在maskData 中,您正在执行以下循环:

for(Matcher m = PWD_XML_PATTERN.matcher(data); m.find(); data = m.replaceAll("AA****BB"))

首先,您调用m.find(),如果没有匹配,这很好,但如果匹配,您调用data = m.replaceAll("AA****BB"),这是一个独立的操作,即不使用的结果以前的find()。之后,您再次调用find(),这是没有意义的,因为Matcher 仍然引用原始字符串。由于replaceAll 没有重置匹配器,因此您不会陷入无限循环,而是总是得到false。

所以改为使用

public static String maskData(String data) {
    return maskOther(PWD_XML_PATTERN.matcher(data).replaceAll("AA****BB"));
}

更糟糕的是,maskOther 方法正在执行替换循环,但它不是使用 Matcher 来执行替换操作,而是在每个匹配的字符串上调用 replace。当替换操作每次都会创建一个新字符串时,这很容易就匹配数乘以源字符串长度达到二次时间复杂度。

但由于replace 也替换了所有出现的搜索字符串(与replaceAll 的区别在于它不做正则表达式模式),这取决于实际模式,是否while(matcher.find()) 循环的后续迭代将处理已经被替换的匹配项。

与您的方法¹结果相同的直接线性替换操作可能如下所示:

private static String maskOther(String data) {
    Matcher matcher = MASK_PATTERN.matcher(data);
    if(!matcher.find()) return data;
    StringBuilder sb = new StringBuilder(data.length()*2);
    int pos = 0;
    do {
        if(matcher.end() - matcher.start() <= 5) continue;
        sb.append(data, pos, matcher.start()).append("****");
        pos = matcher.end() - 4;
    } while(matcher.find());
    return pos == 0? data: sb.append(data, pos, data.length()).toString();
}

¹ 只要您的replace 操作的结果不创建新匹配项。否则,您的方法的结果几乎无法预测。

【讨论】:

  • @Hogler 感谢您提供宝贵的详细输入,上面报告的方法用于生成用于记录的数据,因此如果我们使其异步并记录它,以及优化上述方法。你认为制作 Async 可以增加即兴表演吗?
  • 异步进行日志记录,无需等待其完成,可能会改善请求的延迟。但优化后的版本可能运行时间太短,以至于不再有显着差异。这取决于输入数据和您未显示的实际MASK_PATTERN。在尝试异步日志记录之前,您可以尝试优化版本(并且如前所述,检查更多堆 RAM)。
  • 好的,当然@Hogler 谢谢你,将尝试优化并尝试提到的堆变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-01
相关资源
最近更新 更多