美文网首页阿里云
一个springmvc使用不当引发的血案

一个springmvc使用不当引发的血案

作者: 黄云斌huangyunbin | 来源:发表于2018-08-09 17:07 被阅读171次

    先说结论:是@FrameworkController的坑

    一个同事和我反馈他们的health-check接口都很慢,在容器(2核)只有1000qps不到,这让我很想不通,health-check接口是没有任何逻辑的,直接返回一个ok而已
    而且重点是这个health-check接口是公司的框架提供的,应该是没问题的啊
    @FrameworkController
    public class HealthCheckController {
    
        @RequestMapping(value = "/_health_check", method = RequestMethod.GET)
        public ResponseEntity<String> healthCheck() {
            return new ResponseEntity<String>("ok", HttpStatus.OK);
        }
    }
    
    然后我自己压测看了下,确实和他说的那样,1000qps左右。用jprofile看了下
    image.png
    cpu大部分都是在AccessController.doPrivileged这个方法上,这是个native方法
    image.png
    看到调用链发现,springmvc做接口匹配的时候,会构造ProduceMediaTypeExpression,这个对象的log居然不是静态字段,每次都会创建。
    image.png
    getFactory 会拿ClassLoader
    image.png
    拿ClassLoader会做权限检查
    image.png
    看起来一切事情都非常明白了,就是ProduceMediaTypeExpression比较傻逼,log这个字段居然都是不是静态字段。

    但是health-check这种非常明确的接口,不应该做各种复杂的springmvc匹配逻辑啊。再次压测也注意到有匹配失败的


    image.png
    这个就有点想不通了,health-check是非常容易匹配的啊,然后我远程debug一下。发现是@FrameworkController的坑
    image.png
    @FrameworkController是放在FrameworkControllerHandlerMapping的,这个maping的放在最后的。
    开始要去RequestMappingHandlerMapping匹配,匹配逻辑是先从urlmap中看有不有,health_check不在urlmap中,然后就挨个尝试复杂匹配。都匹配不到才到FrameworkControllerHandlerMapping。
    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
            List<Match> matches = new ArrayList<Match>();
            List<T> directPathMatches = this.urlMap.get(lookupPath);
            if (directPathMatches != null) {
                addMatchingMappings(directPathMatches, matches, request);
            }
            if (matches.isEmpty()) {
                // No choice but to go through all mappings...
                addMatchingMappings(this.handlerMethods.keySet(), matches, request);
            }
    
            if (!matches.isEmpty()) {
                ......
            }
            else {
                return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
            }
        }
    
    
    所以,最根本的原因还是@FrameworkController的坑。
    ps:同事使用的springmvc的4.0.5,我看了下springmvc5是没有这个问题的。
    然后让同事写用@Controller再写了_health_check,qps就上去了。

    最后的问题就是:AccessController.doPrivileged这个方法为什么这么吃cpu呢?

    相关文章

      网友评论

        本文标题:一个springmvc使用不当引发的血案

        本文链接:https://www.haomeiwen.com/subject/usmnvftx.html