zoukankan      html  css  js  c++  java
  • spring-boot 1.4.x遇到的cpu高的问题

    如果你的spring-boot应用里tomcat线程耗cpu较高,并主要耗在做读取jar的操作上(堆栈类似下面),可能跟我们遇到同样的问题。

        CRC32.update(byte[], int, int) line: 76
        JarInputStream(ZipInputStream).read(byte[], int, int) line: 200
        JarInputStream.read(byte[], int, int) line: 207
        JarInputStream(ZipInputStream).closeEntry() line: 140
        JarInputStream(ZipInputStream).getNextEntry() line: 118
        JarInputStream.getNextEntry() line: 142
        JarInputStream.getNextJarEntry() line: 179
        JarWarResourceSet.getArchiveEntries(boolean) line: 112
        JarWarResourceSet(AbstractArchiveResourceSet).getResource(String) line: 256
        StandardRoot.getResourceInternal(String, boolean) line: 280
        CachedResource.validateResource(boolean) line: 95
        Cache.getResource(String, boolean) line: 69
        StandardRoot.getResource(String, boolean, boolean) line: 215
        StandardRoot.getResource(String) line: 205
        Mapper.internalMapWrapper(Mapper$ContextVersion, CharChunk, MappingData) line: 1027
        Mapper.internalMap(CharChunk, CharChunk, String, MappingData) line: 842
        Mapper.map(MessageBytes, MessageBytes, String, MappingData) line: 698
        CoyoteAdapter.postParseRequest(Request, Request, Response, Response) line: 672
        CoyoteAdapter.service(Request, Response) line: 344
        Http11Processor.service(SocketWrapperBase<?>) line: 784
        Http11Processor(AbstractProcessorLight).process(SocketWrapperBase<?>, SocketEvent) line: 66
        AbstractProtocol$ConnectionHandler<S>.process(SocketWrapperBase<S>, SocketEvent) line: 802
        NioEndpoint$SocketProcessor.doRun() line: 1410
        NioEndpoint$SocketProcessor(SocketProcessorBase<S>).run() line: 49
        ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1142
        ThreadPoolExecutor$Worker.run() line: 617
        TaskThread$WrappingRunnable.run() line: 61
        TaskThread(Thread).run() line: 745  

    这种情况只发生在 spring-boot 1.4.x版本(及1.3.x版本,更早的没有确认),1.5.x已经没有这个问题。

    主要的改变在org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory的内部类StoreMergedWebXmlListeneronStart方法:

    // TomcatEmbeddedContext 启动时触发了该监听器
    private void onStart(Context context) {
        ServletContext servletContext = context.getServletContext();
        if (servletContext.getAttribute(MERGED_WEB_XML) == null) {
            servletContext.setAttribute(MERGED_WEB_XML, getEmptyWebXml());
        }
        // 注意最后这句,1.5.3版本已经去掉了这句,它导致变慢
        TomcatResources.get(context).addClasspathResources(); 
    }
    

    addClasspathResources方法里对于jar资源的处理,不同的tomcat版本方式有所不同,spring-boot 中如果使用嵌入式的 tomcat8 的话这些jar资源会记录到StandardRoot里的jarResources集合里,它们会被定时清理。

    tomcat容器的后台线程(ContainerBackgroundProcessor)会触发StandardRoot里的清理逻辑

        public void backgroundProcess() {
            cache.backgroundProcess();
            gc();
        }
    
        public void gc() {
            for (List<WebResourceSet> list : allResources) {
                for (WebResourceSet webResourceSet : list) {
                    webResourceSet.gc();
                }
            }
        }
        
        // JarWarResourceSet里的gc方法
        public void gc() {
            synchronized (archiveLock) {
                if (archive != null && archiveUseCount == 0) {
                    try {
                        archive.close();
                    } catch (IOException e) {
                        // Log at least WARN
                    }
                    archive = null;
                    archiveEntries = null;
                }
            }
        }
    

    请求过来时,Mapper阶段会根据请求路径去找映射的资源,Cache不管命中还是未命中,都会对资源进行validate,在validateResource时要去遍历WebResourceRoot里所有的资源(包括所有的jar资源),若应用依赖的jar比较多时,会导致cpu较高。

    spring-boot 1.5 版本里不会再将 BOOT-INF/lib 下的所有jar添加到tomcat的WebResourceRoot里,升级到1.5.3后这个情况没有再发生。

    http://hongjiang.info/spring-boot-1-4-bug/

  • 相关阅读:
    Spinnerd的功能和用法
    vagrant up ----失败 问题解决
    Yii2.0基础框架
    linux上nginx新建站点
    vagrant(二)配置文件vagrantfile详解 以及安装php、nginx、mysql
    vagrant(一)初识与安装
    cmd 使用gii的命令行用法
    mysql 使用shell时出现 ERROR 2006 (HY000): MySQL server has gone away 解决方法
    c++ virtual总结
    kartikgridGridView 合计,多选,导出excel,header修改 等方法集合!
  • 原文地址:https://www.cnblogs.com/softidea/p/9724645.html
Copyright © 2011-2022 走看看