暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

将OLAP用到极致——Mondrian非功能优化

rocsky 2021-04-20
215

多维数据分析的过程,是指数时间复杂度的立方体计算过程。因此,多维分析系统是CPUMemory密集型系统。本文介绍了影响Mondrian非功能指标的几个典型问题,主要包括:资源异常使用问题、资源未被充分使用问题、线程死锁问题、长时间占用资源问题、热点方法问题等。

资源异常使用问题

现象:当并发数超过系统最大查询线程池的处理能力时,触发流量控制,系统直接返回超出处理能力异常。但是,存在一种场景,即并发数瞬间增大,持续一段时间之后,停止发送请求,却存在一段时间的CPU空跑时间,在此期间并没有新的请求,并且CPU空跑时间的长短与并发持续时间成正比。

原因:对于每个请求,系统生成一个执行任务,并将执行任务添加到执行任务列表和执行线程池。超出流量控制的请求不会被添加到执行线程池,却被添加到了执行任务列表。从而造成执行任务引用的对象,需要等待其生命周期结束后才能被释放,造成了内存浪费,并且增加了执行任务列表的循环执行开销。原代码如下:

        tasks.add(pair);

        try {

            executor.execute(task);

            return task.get();

        } catch (Throwable e) {

解决:对于超出流量控制的请求,不添加到执行任务列表。修改后的代码如下:

        try {

            executor.execute(task);

            tasks.add(pair);

            return task.get();

        catch (Throwable e) {


资源未被充分使用问题

现象:随着并发用户数的增大,CPU维持在10%以下,TPS明显偏低。

原因:系统中SchemaPool,MonitorMap,MemberReader等相关实现代码,存在着大量的临界区操作,造成了资源争用和线程等待。

解决:改造成读写锁,或者修改实现方式,提升系统吞吐量。

线程死锁问题

现象:存在某一次的清理Segment缓存操作,导致系统无法处理任何请求。

原因:系统将与Segment相关的操作命令,比如添加,更新,删除等操作命令,添加到一个执行队列。如果清理Segment缓存的命令,对SchemaPool加锁后,被添加到执行队列,因为其不在队列头而无法执行;与此同时,队列头的命令要运行,必须获取SchemaPool锁,则队列头命令等待,从而造成死锁。

解决:清理Segment缓存操作命令不再加入执行队列,直接执行,避免获取锁之后,被放入队列,而又无法立即执行,使正在执行的操作命令无法获取锁的情况。

长时间占用资源问题

现象:每个MDX查询都设置了最大执行时间,但是,存在查询,其执行时间明显超过最大执行时间,程序却并没有报告超时异常,长时间占用CPU和内存资源。

原因:一个MDX查询可能需要多次SQL查询,或者除了SQL查询之外,还需要大量的内存计算。系统在每个SQL执行前做超时检查,却没有给SQL执行设置最大执行时间,因此,存在SQL执行时间超时,却没有被取消的情况。

解决:动态计算并设置SQL的最大执行时间。代码如下:

      statement.setQueryTimeout(queryTimeout);

热点方法问题

现象:在压力测试中,成员的getName方法占据超过40%CPU资源。

原因getName是一个被高频调用的方法,但是,其内部实现却有一段临界区计算。

解决:成员名称在主题加载之后就不会变化,因此,定义成员名称为私有变量,主题加载之后第一次调用给变量赋值,此后调用直接返回变量值。类似的还有系统的Properties配置项,采用了HashTable加上动态计算的实现方式,影响了系统的非功能指标,改造成Zookeeper加本地缓存的实现方式。

 

本文介绍了几个影响Mondrian非功能指标的典型问题。其实,除了从技术角度解决Mondrian的非功能问题外,少用strToSetstrToMember等函数,甚至简单修改业务实现思路,有时候会事半功倍。

 


文章转载自rocsky,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论