`
taupo
  • 浏览: 28474 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

BAC Business Rule分析之二

    博客分类:
  • BAC
阅读更多

 

BaseRule中execute方法是规则计算的开始,但是,execute又是被谁调用的呢,特别是sample是如何从bus中取得的呢?

 

 

通过追中代码,发现,在NodeCalculatorImpl中,通过calculateDimension调用了execute,但是在calculateDimension方法中,没有做过多的逻辑处理,直接调用了excute。但是在成功调用了execute后回做一些处理,比如保存KPI的状态和结果,但是这不是今天的重点,暂时忽略。。。。

 

重点在calculateNode方法中,该方法调用了calculateDimension。calculateNode首先取得该CI的所有KPI,然后通过selecter获取sample。

 

因为rule是15秒被调用一次,所以,selecter获得sample应该是15秒之内到达bus的(可能是多个,也可能是0个),比如,BPM每1分钟运行一次,那么selecter会有3次取不到数据,所以,传入execute的sample容器有可能为空。

 

sample视乎已经取到了,但是我们的Rule如何利用这些sample呢。于是我们的另一个主角Accumulator登场了,它就好像KPI的荷包,装了和该KPI相关的sample,我们的rule就是从这个荷包里去取得sample做计算,然后把结果又保存到KPI的另外一个地方,当然这个荷包也有可能为空,什么时候为空呢,也许你已经猜到了,no data time out,right!!这个参数就是控制荷包是否为空的。比如,BPM每3分钟运行一次,如果no data timeout=30的话,那么当sample到达bus 30秒后,荷包就会被清空,也就是rule调用两次后,会发现荷包为空了,KPI状态应该为no data,也就是蓝色。。。。。。。 所以我们一般不能设置no data timeout小于DC的运行频率。

 

Accumulator分为2种:

1.SampleBasedAccumulator

2.TimeBasedAccumulator

 

第一种Accumulator我们在sample rule中已经分析了,它只保存最近的(或者根据需要保存最近的几个)sample。而

TimeBasedAccumulator会根据duration参数保存sample,比如,duration=1000,那么就保存最后一次计算到1000秒之前这段时间里的sample。

 

也许你不仅要问,KPI的荷包(Accumulator)是哪来的?现在我们来揭开神秘面纱,

我们知道BaseRule是Rule的最高父类,其子类有

                                                      ---DummyRule

                                                      ---FilterRule

                                                      ---GroupAndSiblingRule

                                                      ---LeafRule

                                                      ---TimeBasedDummyRule

 

 

这里我们以LeafRule为例作分析,因为在execute真正执行计算之前,会调用,initRuleIfNeeded对Rule做一些初始化,你也许预感到了Accumulator就是在初始化的过程中生成的。在这个方法中,首先判断Rule是否被初始化,如果已经初始化,就什么也不做(从该方法名就能看出来了。。。。),如果没有初始化,会在initRuleIfNeeded中调用internalInit方法,因为LeafRule复写了该方法,所以这里调用的是LeafRule.internalInit,代码如下

void internalInit(RuleTrinityModelAccess access, RuleNode node, RuleDimension kpi) {
        super.internalInit(access, node, kpi);
        Accumulator accumulator = getAccumulator(kpi);//第一次返回null
          if (accumulator == null) {
            accumulator = createAccumulator(access, node, kpi);//创建Accumulator,这个方法会被LeafRule的子类重写,如果是与时间相关的子类返回的就是TimeBasedAccumulator,同时就会把duration到该accumulator 种,如果不是与时间相关的accumulator ,就会创建SampleBasedAccumulator
            kpi.setStateValue(ACCUMULATOR_KPI_STATE_KEY, accumulator);//保存accumulator 到KPI中
        }
        else {
           initializeAccumulatorParameters(access, node, kpi, accumulator);//继续复用以前的accumulator ,但是会更新duration或者需要保存的sample数
        }
    }

 

显然,在该方法中,如果Accumulator 为空,根据Rule的种类创建Accumulator。不为空,就复用它。

 

 当internalInit返回后,initRuleIfNeeded继续调用init方法,该方法会根据Rule的不同类型做不同的动作,因为Rule的类型实在太多,所以就不分析了。。。最后初始化完了。

最后,就是设置KPI为 初始化 ,免得下次再初始化,然后设置初始化的时间。

 

到这里,Accumulator 创建了,Rule也已经初始化了,我们可以开始计算了,于是BaseRule.calculate被调用,因为LeafRule复写了该方法,所以这里实际调用的是LeafRule.calculate,让我们看看LeafRule.calculate到底干了什么。

 

也许你要问,sample在哪呢?在初始化的时候我们只是创建了Accumulator而已,还没把sample放到荷包呢!对,所以在LeafRule.calculate中,我们得先把荷包填满,呵呵。

 

执行这个填满荷包动作的是LeafRule.processSamples,从方法名就可以感觉到它是干什么的了,对处理sample,处理selecter千辛万苦从Bus中过滤出来的sample。

 

处理逻辑大致是:

 

如果原始sample容器(selecter选择出来的sample)不为空,会把原始容器里的所有sample加入Accumulator,你不用担心Accumulator会装不下,因为这里在加入同时,会删除过期的sample,这里的过期,可能是时间过期,也可能是个数过期(通过参数设定的最大个数),当然这是根据Accumulator的种类来判断到底是删除时间过期的sample 还是删除个数过期的。

 

如果原始sample容器(selecter选择出来的sample)为空,也要删除过期的sample。

 

 处理完sample后,rule以后就到Accumulator中去拿sample来用了,此时你发现真正的计算逻辑还是展开,对,因为我们还没判断是否是no data, 判断是否是no data就是用Accumulator里面最新的sample做时间对比了,逻辑挺简单。。。

 

如果判断是no data,就调用handleNoData做处理,如果有data,接着调用calculateKpi,计算开始啦。。。。。。。

 

 我们一般情况下也只要复写calculateKpi就OK了,至于怎么去计算,你想怎么玩就怎么玩。。。。。。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics