• 【原创】大叔问题定位分享(14)Kylin频繁OOM问题


    公司一个kylin集群,每到周二下午就会逐个节点OOM退出,非常有规律,kylin集群5个节点,每个节点分配的内存已经不断增加到70多G,但是问题依旧;


    经排查发现,每周二下午kylin集群的请求量确实会多一些,有可能是kylin的bug,也可能是其他原因,当节点kylin进程内存占用上升时,打印线程堆栈发现,有很多线程都被卡住,synchronized,各种Manager,比如CubeManager、DictionaryManager、MetadataManager,以MetadataManager为例查看kylin代码发现,这些Manager的套路差不多,都有clearCache、getInstance(synchronized),然后getInstance中会调用Constructor,Constructor中会加载一堆东西,这个加载过程比较慢,所以getInstance会长时间synchronized:


    org.apache.kylin.metadata.MetadataManager

        public static void clearCache() {
            CACHE.clear();
        }
        
        public static MetadataManager getInstance(KylinConfig config) {
            MetadataManager r = CACHE.get(config);
            if (r != null) {
                return r;
            }
    
            synchronized (MetadataManager.class) {
                r = CACHE.get(config);
                if (r != null) {
                    return r;
                }
                try {
                    r = new MetadataManager(config);
                    CACHE.put(config, r);
                    if (CACHE.size() > 1) {
                        logger.warn("More than one singleton exist");
                    }
    
                    return r;
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to init MetadataManager from " + config, e);
                }
            }
        }
    
        private MetadataManager(KylinConfig config) throws IOException {
            init(config);
        }
    
        private void init(KylinConfig config) throws IOException {
            this.config = config;
            this.srcTableMap = new CaseInsensitiveStringCache<>(config, "table");
            this.srcTableExdMap = new CaseInsensitiveStringCache<>(config, "table_ext");
            this.dataModelDescMap = new CaseInsensitiveStringCache<>(config, "data_model");
            this.extFilterMap = new CaseInsensitiveStringCache<>(config, "external_filter");
    
            reloadAllSourceTable();
            reloadAllTableExt();
            reloadAllDataModel();
            reloadAllExternalFilter();
    
            // touch lower level metadata before registering my listener
            Broadcaster.getInstance(config).registerListener(new SrcTableSyncListener(), "table");
            Broadcaster.getInstance(config).registerListener(new SrcTableExtSyncListener(), "table_ext");
            Broadcaster.getInstance(config).registerListener(new DataModelSyncListener(), "data_model");
            Broadcaster.getInstance(config).registerListener(new ExtFilterSyncListener(), "external_filter");
        }

    查看了kylin各个版本的代码,发现都是这个套路,看来kylin不认为这是一个问题,这确实会导致一些潜在的问题,比如高负载时,忽然要刷新,这时就会有大量的请求被synchronized,这个会导致OOM吗?


    进一步检查线程堆栈发现,当时tomcat的线程池几乎被占满,这个也很容易理解,之前的请求被synchronized,还不断有新的请求进来,然后线程池就满了,忽然想到,一旦synchronized结束,所有的请求都开始同时处理,而且其中一些请求可能会占用比较多的内存,这样内存可能瞬间就扛不住了,这是一个雪崩效应,上面的场景其实和压测的场景差不多,即服务器满负荷运转,线程池所有的线程都在处理请求,如果tomcat配置的线程池数量太大了,服务器就撑不住了,OOM就是因为这个,如果不改这个配置,内存配置的再大也没用,还是会OOM,把tomcat线程池配置小一些即可;

    另外还有一种方法,就是在Load Balancer上加控制,一旦响应很慢,就标记unhealthy,把请求分给其他节点,这样就不会在synchronized的节点上堆积大量请求,也可以避免问题;

  • 相关阅读:
    Vue cmd命令操作
    迭代器和生成器
    10-外键的变种 三种关系
    09-完整性约束
    08-数据类型(2)
    07-数据类型
    06-表的操作
    05-库的操作
    04-基本的mysql语句
    03-MySql安装和基本管理
  • 原文地址:https://www.cnblogs.com/barneywill/p/10113105.html
Copyright © 2020-2023  润新知