JVM排错

问题:网关Gateway过一段时间会很卡

问题排查:

  步骤:

  1)jps 查看进程号

  2)jmap -heap pid 查看堆信息

     查看jvm空间是否满,对象情况

  3)jstack -l PID >1.txt   线程快照

     jmap -dump:format=b,file=heapdump.phrof pid 生成堆转储快照dump文件(profilter需要的文件)

     查看当前线程情况

  发现:com.alibaba.nacos.client.naming.updater这个线程数量过多,上万个

问题定位:

 

 

 

  通过swagger文档生成ios、android代码时,需调用网关接口根据路由获取所有的服务信息,重复调用了NamingFactory.createNamingService(properties)。

  

        Flux<Route> routeFlux = routeLocator.getRoutes();
        // 获取所有可用的host:serviceId
        routeLocator.getRoutes().filter(route -> route.getUri().getHost() != null).filter(route -> !self.equals(route.getUri().getHost())).subscribe(route -> {
            // update-begin---author:zyf ---date:20220413 for:过滤掉无效路由,避免接口文档报错无法打开
            boolean hasRoute = checkRoute(route.getId());
            if (hasRoute) {
                routeHosts.add(route.getUri().getHost());
            }
            // update-end---author:zyf ---date:20220413 for:过滤掉无效路由,避免接口文档报错无法打开
        });

  

    /**
     * 检测nacos中是否有健康实例
     *
     * @param routeId
     * @return
     */
    private Boolean checkRoute(String routeId) {
        Boolean hasRoute = false;
        try {
            // 修复使用带命名空间启动网关swagger看不到接口文档的问题
            Properties properties = new Properties();
            properties.setProperty("serverAddr", serverAddr);
            if (namespace != null && !"".equals(namespace)) {
                properties.setProperty("namespace", namespace);
            }
            NamingService naming = NamingFactory.createNamingService(properties);

            List<Instance> list = naming.selectInstances(routeId, nacosGroupName,true);
            if (ObjectUtil.isNotEmpty(list)) {
                hasRoute = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hasRoute;
    }

  

  在createNamingService过程中,nacos的HostReactor会创建线程池并启动名为com.alibaba.nacos.client.naming.updater的线程来更新服务信息,默认线程数为1~CPU核心数的一半。而HostReactor是通过new来获取对象的,所以每调用一次createNamingService都会创建一次线程池。最终导致每调一次生成代码,就会创建一次线程池。日积月累线程数就多了。

  

   

 

 

问题解决:

  NamingService namingService = NamingFactory.createNamingService(properties);

  将将创建的namingService作为一个springbean交个spring管理,这样只是在程序启动时创建了nacos命名空间一次。 

  

posted @ 2023-02-11 10:31  joel1889  阅读(22)  评论(0)    收藏  举报