使用jstack确认saiku报表刷新缓存无法访问问题


title: 使用jstack确认saiku报表刷新缓存无法访问问题 tags:

  • saiku
  • Mondrian
  • jstack categories: saiku date: 2017-10-31 11:05:24

背景

运维小伙伴反映一直出现saiku服务器在刷新缓存的时候无法访问的问题因此打算定位一下原因

工具介绍

jstack是java的自带的线程堆栈查看工具

我们可以查看如下

    qixiaobo@qixiaobo.mac.pro:/Users/qixiaobo> jstack -h  17-10-30 22:16
    Usage:
        jstack [-l] <pid>
            (to connect to running process)
        jstack -F [-m] [-l] <pid>
            (to connect to a hung process)
        jstack [-m] [-l] <executable> <core>
            (to connect to a core file)
        jstack [-m] [-l] [server_id@]<remote server IP or hostname>
            (to connect to a remote debug server)
    Options:
        -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
        -m  to print both java and native frames (mixed mode)
        -l  long listing. Prints additional information about locks
        -h or -help to print this help message
复制代码

通常我们使用jstack pid来进行对应的堆栈打印

实战

执行

    jstack 12345
复制代码

可以看出来当刷新缓存时 其他线程执行到获取连接时会在get时等待监视器 很明显此时线程在等待RolapSchemaPool相关的资源

经过查看其代码如下

    class RolapSchemaPool {
        static final Logger LOGGER = Logger.getLogger(RolapSchemaPool.class);
        private static final RolapSchemaPool INSTANCE = new RolapSchemaPool();
        private final Map<SchemaKey, SoftReference<RolapSchema>> mapKeyToSchema = new HashMap();
        private final Map<ByteString, SoftReference<RolapSchema>> mapMd5ToSchema = new HashMap();
     
        private RolapSchemaPool() {
        }
     
        static RolapSchemaPool instance() {
            return INSTANCE;
        }
     
        synchronized RolapSchema get(String catalogUrl, String connectionKey, String jdbcUser, String dataSourceStr, PropertyList connectInfo) {
            return this.get(catalogUrl, connectionKey, jdbcUser, dataSourceStr, (DataSource)null, connectInfo);
        }
     
        synchronized RolapSchema get(String catalogUrl, DataSource dataSource, PropertyList connectInfo) {
            return this.get(catalogUrl, (String)null, (String)null, (String)null, dataSource, connectInfo);
        }
     
        private RolapSchema get(String catalogUrl, String connectionKey, String jdbcUser, String dataSourceStr, DataSource dataSource, PropertyList connectInfo) {
            String dialectClassName = connectInfo.get(RolapConnectionProperties.Dialect.name());
            String connectionUuidStr = connectInfo.get(RolapConnectionProperties.JdbcConnectionUuid.name());
            boolean useSchemaPool = Boolean.parseBoolean(connectInfo.get(RolapConnectionProperties.UseSchemaPool.name(), "true"));
            boolean useContentChecksum = Boolean.parseBoolean(connectInfo.get(RolapConnectionProperties.UseContentChecksum.name()));
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("get: catalog=" + catalogUrl + ", connectionKey=" + connectionKey + ", jdbcUser=" + jdbcUser + ", dataSourceStr=" + dataSourceStr + ", dataSource=" + dataSource + ", dialect=" + dialectClassName + ", jdbcConnectionUuid=" + connectionUuidStr + ", useSchemaPool=" + useSchemaPool + ", useContentChecksum=" + useContentChecksum + ", map-size=" + this.mapKeyToSchema.size() + ", md5-map-size=" + this.mapMd5ToSchema.size());
            }
     
            ConnectionKey connectionKey1 = ConnectionKey.create(connectionUuidStr, dataSource, catalogUrl, dialectClassName, connectionKey, jdbcUser, dataSourceStr);
            String catalogStr = getSchemaContent(connectInfo, catalogUrl);
            SchemaContentKey schemaContentKey = SchemaContentKey.create(connectInfo, catalogUrl, catalogStr);
            SchemaKey key = new SchemaKey(schemaContentKey, connectionKey1);
            RolapSchema schema = null;
            if (!useSchemaPool) {
                schema = RolapSchemaLoader.createSchema(key, (ByteString)null, catalogUrl, catalogStr, connectInfo, dataSource);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("create (no pool): schema-name=" + schema.name + ", schema-id=" + Integer.toHexString(System.identityHashCode(schema)));
                }
     
                return schema;
            } else if (useContentChecksum) {
                ByteString md5Bytes = new ByteString(Util.digestMd5(catalogStr));
                SoftReference<RolapSchema> ref = (SoftReference)this.mapMd5ToSchema.get(md5Bytes);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("get(key=" + key + ") returned " + toString(ref));
                }
     
                if (ref != null) {
                    schema = (RolapSchema)ref.get();
                    if (schema == null) {
                        this.mapKeyToSchema.remove(key);
                        this.mapMd5ToSchema.remove(md5Bytes);
                    }
                }
     
                if (schema == null) {
                    schema = RolapSchemaLoader.createSchema(key, md5Bytes, catalogUrl, catalogStr, connectInfo, dataSource);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("create: schema-name=" + schema.name + ", schema-id=" + System.identityHashCode(schema));
                    }
     
                    this.putSchema(schema, md5Bytes);
                }
     
                return schema;
            } else {
                SoftReference<RolapSchema> ref = (SoftReference)this.mapKeyToSchema.get(key);
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("get(key=" + key + ") returned " + toString(ref));
                }
     
                if (ref != null) {
                    schema = (RolapSchema)ref.get();
                    if (schema == null) {
                        this.mapKeyToSchema.remove(key);
                    }
                }
     
                if (schema == null) {
                    schema = RolapSchemaLoader.createSchema(key, (ByteString)null, catalogUrl, catalogStr, connectInfo, dataSource);
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("create: " + schema);
                    }
     
                    this.putSchema(schema, (ByteString)null);
                }
     
                return schema;
            }
        }
复制代码

很明显此处getConnection是synchronized方法 而其他用户登录因此也需要等待缓存刷新的线程释放才可以。

经过查看该版本的jar是

实质上其他版本的mondrian并非是同步版本的 比如

很明显该版本并非同步版本的代码

spark版本当刷新缓存时对应需要加同步

    - locked <0x00000007f0f0a438> (a com.mysql.jdbc.JDBC4Connection)
            - locked <0x00000007ea451028> (a com.mysql.jdbc.PreparedStatement)
            at com.mysql.jdbc.PreparedStatement.getMetaData(PreparedStatement.java:2890)
            - locked <0x00000007ea44f0a0> (a com.mysql.jdbc.JDBC4PreparedStatement)
            at org.apache.commons.dbcp.DelegatingPreparedStatement.getMetaData(DelegatingPreparedStatement.java:193)
            at org.apache.commons.dbcp.DelegatingPreparedStatement.getMetaData(DelegatingPreparedStatement.java:193)
            at mondrian.rolap.RolapSchema$PhysSchema.describe(RolapSchema.java:1017)
            at mondrian.rolap.RolapSchema$PhysCalcColumn.compute(RolapSchema.java:2299)
            at mondrian.rolap.RolapSchemaLoader.registerColumn(RolapSchemaLoader.java:1422)
            at mondrian.rolap.RolapSchemaLoader.registerTable(RolapSchemaLoader.java:1057)
            at mondrian.rolap.RolapSchemaLoader.validatePhysicalSchema(RolapSchemaLoader.java:715)
            at mondrian.rolap.RolapSchemaLoader.loadStage2(RolapSchemaLoader.java:376)
            at mondrian.rolap.RolapSchemaLoader.loadStage1(RolapSchemaLoader.java:336)
            at mondrian.rolap.RolapSchemaLoader.loadStage0(RolapSchemaLoader.java:272)
            at mondrian.rolap.RolapSchemaLoader.createSchema(RolapSchemaLoader.java:4305)
            at mondrian.rolap.RolapSchemaPool.get(RolapSchemaPool.java:210)
            at mondrian.rolap.RolapSchemaPool.get(RolapSchemaPool.java:62)
            - locked <0x000000070505d428> (a mondrian.rolap.RolapSchemaPool)
            at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:160)
            at mondrian.rolap.RolapConnection.<init>(RolapConnection.java:84)
            at mondrian.olap.DriverManager.getConnection(DriverManager.java:112)
            at mondrian.olap.DriverManager.getConnection(DriverManager.java:68)
            at mondrian.olap4j.MondrianOlap4jConnection.<init>(MondrianOlap4jConnection.java:153)
            at mondrian.olap4j.FactoryJdbc4Plus$AbstractConnection.<init>(FactoryJdbc4Plus.java:323)
            at mondrian.olap4j.FactoryJdbc41Impl$MondrianOlap4jConnectionJdbc41.<init>(FactoryJdbc41Impl.java:118)
            at mondrian.olap4j.FactoryJdbc41Impl.newConnection(FactoryJdbc41Impl.java:32)
            at mondrian.olap4j.MondrianOlap4jDriver.connect(MondrianOlap4jDriver.java:139)
            at java.sql.DriverManager.getConnection(DriverManager.java:571)
            at java.sql.DriverManager.getConnection(DriverManager.java:215)
            at org.saiku.datasources.connection.SaikuOlapConnection.connect(SaikuOlapConnection.java:107)
            at org.saiku.datasources.connection.SaikuOlapConnection.connect(SaikuOlapConnection.java:56)
            at org.saiku.datasources.connection.SaikuConnectionFactory.getConnection(SaikuConnectionFactory.java:29)
            at org.saiku.web.core.SecurityAwareConnectionManager.connect(SecurityAwareConnectionManager.java:293)
            at org.saiku.web.core.SecurityAwareConnectionManager.getInternalConnection(SecurityAwareConnectionManager.java:109)
            at org.saiku.web.core.SecurityAwareConnectionManager.refreshInternalConnection(SecurityAwareConnectionManager.java:146)
            at org.saiku.datasources.connection.AbstractConnectionManager.refreshConnection(AbstractConnectionManager.java:151)
            at org.saiku.service.olap.OlapDiscoverService.refreshConnection(OlapDiscoverService.java:87)
            at org.saiku.web.rest.resources.OlapDiscoverResource.refreshConnection(OlapDiscoverResource.java:115)
            at sun.reflect.GeneratedMethodAccessor308.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
复制代码

我们没有使用spark是否可以考虑使用略低版本的mondrian呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值