insights 磁力
在任何大容量事件处理系统中,例如IBM®Operational Decision Manager(ODM)中的Decision Server Insights,被数千个事件引用的实体实例都是“热实体”。 热实体减慢了处理速度,成为系统内事件的唯一使用者。 这种情况有效地减少了整个多处理网格,以等待单个线程完成。
本教程旨在帮助Decision Server Insights架构师和开发人员在没有热门实体的情况下构建解决方案。 了解热实体的原因和避免它们的提示。
当大多数入站事件进入少数几个热门实体时,事件处理系统中就会出现问题。 热门实体问题不仅仅在于单个实体被事件过载,还在于当越来越少的实体以接收事件为目标时性能逐渐下降。 在下面的图表中,您可以看到,当少于200个实体能够处理入站事件时,事件摄取(每秒的事件)呈线性下降。 该图显示了本教程中Decision Server Insights示例解决方案的性能下降。 确切的数量取决于您自己的解决方案和硬件。
设计较差的Decision Server Insights解决方案使热实体可以减慢事件接收的速度,直到网格停止为止。 在最坏的情况下,解决方案面临以下问题:
- 入站事件队列已满,迫使Decision Server Insights解决方案拒绝其他事件。
- 数百万个事件击中一个热门实体,这需要几天的时间才能解决。
本教程显示了三个示例解决方案,它们解释了如何识别热实体并研究了避免热实体的方法。 第一个解决方案没有热实体保护,第二个解决方案具有部分保护,而第三个解决方案则针对热实体提供全面保护。
热实体类型
您会遇到以下三种类型的热实体:
- 良性热实体,它们会导致轻微的性能问题,可以忽略。
- 持久的热实体,不断引起问题。
- 隐藏的热实体,偶尔会引起问题。
良性热实体需要花费几分钟来处理大量事件,这将导致接近实时的事件检测,而不是实时的检测。 除非实时事件检测非常重要,否则良性热实体通常不是问题。
持久的热实体会导致严重的性能问题,但是在部署到生产之前,可以轻松地在开发中识别并解决问题。
隐藏的热实体是最成问题的,只有在解决方案上线后才能确定。 例如,想象一下一个接收飞机事件的飞机监控系统,如下图所示。 这些事件被发送到与一个或多个飞机实体关联的飞机代理 。 在正常操作下,所有飞机都会发出状态事件,并且这些事件在所有飞机之间平均分配。 但是,如果一架飞机开始出现故障,就会向一架飞机实体实例发出警告事件。 这个实体实例成为大多数飞机事件的使用者,并且这个实体很热。
避免热门实体的提示
现在,了解有关重新设计解决方案以防止实体过热的提示。
秘诀1:分而治之
避免使用消耗复杂事件的复杂实体。 将复杂的实体和事件分成较小的部分。 如下图所示,飞机事件和飞机实体分为较小的组件实体: 机身实体 , 驾驶舱实体 , 引擎实体 , 机翼实体和齿轮实体 。 每个组件实体都接收飞机发出的事件的子集,从而减少了出现高温实体的可能性。
提示2:解决规则代理性能
当实体实例无法尽快消耗事件时,就会发生热实体。 原因之一可能是您的规则代理人速度太慢。 这可能是因为您的解决方案具有较大的事件范围。
检查是否需要较大的事件范围。 您是否可以将事件历史记录摘要存储在实体中? 例如,考虑一个计算发动机警告的规则。 与其使用事件历史记录来计算警告事件的数量,还不如在引擎实体上添加警告计数器。
提高性能的另一种方法是将规则代理重写为Java™代理。 如果您的规则是技术性的,并且将逻辑表达为业务规则并没有真正的好处,请考虑使用这种方法。
提示3:避免为每个事件进行昂贵的OSGi调用
检查您的规则,以查看每次收到事件时是否需要进行昂贵的开源网关倡议(OSGi)呼叫。 例如,如果您调用预测分析软件(例如IBM SPSS Statistics),是否需要为每个事件进行调用? 或者,是否可以通过引入另一个接收事件摘要的代理来降低呼叫频率? 本教程稍后将解释此概念。
提示4:克隆实体
如果您按照提示1-3进行操作,但仍然有热门实体,请考虑使用以下模式克隆该实体。 与技巧1中将实体拆分为逻辑组成部分的方法不同,此模式将同一个实体克隆n次。 每个克隆消耗整个对象的事件总数的1 / n 。 有关此模式的更多信息,请参见教程部分。
您的解决方案会遇到热门实体吗?
要确定您的Decision Server Insights解决方案是否容易出现热实体,请使用以下公式:
hot entity potential = inbound EPS / (instance EPS * min instances)
令inbound EPS
为每秒入站事件的持续量。
令instance EPS
为单个实体实例每秒可处理的最大事件数。
令min instances
是处理入站事件所涉及的最少实体实例(最坏的情况)。
如果您的热实体潜力大于1,则您的解决方案中就有热实体的风险。 值越高,风险越高。
酷实体示例
inbound EPS
值为100, instance EPS
值为50, min instances
值为4:
100 / (50 * 4) = 0.5
热实体电势为0.5
,表明溶液很冷。
热门实体示例
inbound EPS
值为100, instance EPS
值为50, min instances
值为1:
100 / (50 * 1) = 2
这次,热实体势为2
,表示热解。 如果您有实体过热的风险,请通过应用上一部分中的提示来解决。
下一节将展示如何将这些技巧应用于与遇到热实体的IBM ODM客户进行实际工作的示例。 深入介绍了飞机监控系统示例中的三种不同的Decision Server Insights实施。 第一个解决方案最简单,但最容易出现热实体。 第二种解决方案采用分而治之的方式来减少热量,但是仍然存在问题。 第三种解决方案得到了全面保护,免受热实体的攻击。
示例解决方案1:没有优化的飞机监控解决方案
先前的“热实体类型”部分显示了实施示例飞机监控解决方案的首次尝试。 飞机实体与飞机事件相关联。 如以下代码清单所示,飞机实体记录有关飞机的飞行数据:
清单1.飞机实体
/****** Airplane Entity ******/
an airplane is a business entity identified by an airplane id .
an airplane has an average engine exhaust temperature (integer ) .
an airplane has an average engine pressure ratio (integer ) .
an airplane has an average engine rpm (integer ) .
an airplane has an wing warnings (integer ) .
an airplane has an cockpit warnings (integer ) .
an airplane has an fuselage warnings (integer ) .
an airplane has an gear warnings (integer ) .
an airplane has an event count (integer ) .
飞机会定期发出一次飞机事件以提供飞行数据,如以下代码清单所示:
清单2.飞机事件
/****************** Airplane Event ******************/
an airplane event is a business event time-stamped by a timestamp ( date & time ) .
an airplane event has an aircraft id .
an airplane event has an engine .
an airplane event has a wing .
an airplane event has a gear .
an airplane event has a cockpit .
an airplane event has a fuselage .
a wing is a concept .
a wing has a lift ( integer ) .
a fuselage is a concept.
a fuselage has a pressure ( integer ) .
a cockpit is a concept .
a cockpit has a altitude ( integer ) .
a cockpit has a speed ( integer ) .
a gear is a concept .
a gear has a gear state ( a gear status ).
a engine is a concept .
an engine has a pressure ratio ( integer ) .
an engine has a rpm ( integer ) .
an engine has a exhaust temperature ( integer ) .
a gear status can be one of: UP, DOWN, STUCK.
飞机实体绑定到飞机代理,并且代理接收飞机事件。 飞机代理包含以下规则。
商业规则
如以下Insight Insight屏幕截图所示,有六项业务规则用于监视飞机:
有两个引擎规则。 第一个是CalcAverages
,它计算发动机参数的滚动加权平均值,如以下代码清单所示:
清单3. CalcAverages规则
when an airplane event occurs
then
define rpmAverage as ( the average engine rpm of 'the airplane' +
the rpm of the engine of this airplane event ) / 2 ;
define pressureAverage as ( the average engine pressure ratio of 'the airplane' +
the pressure ratio of the engine of this airplane event ) / 2 ;
define exhaustTempAverage as ( the average engine exhaust temperature of 'the airplane' +
the exhaust temperature of the engine of this airplane event ) / 2 ;
set the average engine rpm of 'the airplane' to rpmAverage;
set the average engine pressure ratio of 'the airplane' to pressureAverage;
set the average engine exhaust temperature of 'the airplane' to exhaustTempAverage;
set the event count of 'the airplane' to the event count of 'the airplane' + 1 ;
第二个引擎规则是EngineShutdown
,它应用在上一个代码清单中计算的平均值来预测引擎故障。 如以下代码清单所示,运行IBM SPSS Statistics分析算法以确定故障概率。 如果概率超过八,则发出发动机停机事件。
清单4. EngineShutdown规则
when an airplane event occurs
if
calculate engine failure probability ( the average engine exhaust temperature of 'the airplane' ,
the average engine pressure ratio of 'the airplane' ,
the average engine rpm of 'the airplane' ) is more than 8
then
emit a new actionable event where
the operator action is ENGINE_ERROR ,
the reason is "Engine Failing on " + the aircraft id,
the aircraft id is the aircraft id of this airplane event ,
the timestamp is now ;
在此解决方案中, 'calculate engine failure probability'
的IBM SPSS Statistics调用是模拟调用。
现在,您可以浏览Github解决方案中提供的其余规则。
运行示例解决方案1
- 前往http://github.com/ncrowther/CoolingHotEntities
- 下载示例代码。
- 将内容提取到方便的位置。
- 打开Insight Designer。
- 单击文件>导入,然后选择常规 > 现有项目到工作区 。
- 将下载的
JetSolution1
文件夹下的所有项目导入到Insight Designer中。 - 如果看到“
Generate Java Model
错误,请右键单击JetSolution项目,然后选择Configure > Migrate Solution 。 - 在您的本地计算机上启动cisDev Decision Server Insights服务器。
- 右键单击JetSolution项目,然后选择Deploy > Deployment Configurations 。
- 单击“新建”,然后创建一个名为JetSolution的部署名称。
- 选择本地服务器 。 然后单击“ 下一步” 。
- 选择“ 禁用SSL主机名验证”和“ 禁用服务器证书验证” ,然后单击“ 下一步” 。
- 选择“ 创建新的连接服务器配置” ,然后单击“ 下一步” 。
- 确保选择了所有选项(入站端点,HTTP和InboundHttpEndpoint),然后单击完成 。
- 该解决方案应部署到您的本地cisDev Decision Server Insights服务器实例。 在控制台上查看以下消息:
CWMBE1452I: Successfully deployed connectivity for the solution "JetSolution"
。 - 在Insight Designer中,转到JetStatusTester项目, 然后在“事件序列”文件夹下打开JetStatusTestSeq.eseq 。
- 在项目的顶级目录中,编辑
testdriver.properties
并确保将trustStoreLocation
设置为Decision Server Insights安装路径。 - 右键单击JetStatusTestSeq.eseq ,然后选择运行方式 > 事件序列 。
- 选择“ 启用记录” ,“ 重置解决方案状态”和“ 删除所有条目” ,然后单击“运行” 。
该脚本将运行并将一个或多个事件发送到解决方案中。 规则触发并创建可操作事件 ,供飞行控制团队处理。 记录捕获所有提交和发出的事件,并在处理每个事件之前和之后将实体的状态存储在可以在Insight Inspector中查看的文件中。 - 在Insight Inspector中打开以下记录以查看事件:
https://localhost:9443/ibm/insights/view?id=JetSolution-0.0
。 - 在Insight Inspector中,验证所有事件都集中在一个飞机实体上,并且该实体很热,如以下屏幕截图所示:
解决方案示例2:应用分而治之模式
第一个示例解决方案的问题是飞机实体很热。 该示例解决方案2对飞机事件应用了分而治之的模式,以便将其拆分为组成部分,例如引擎 , 机翼和齿轮 。
在示例代码中,您可以看到飞机实体和飞机事件都被拆分为多个部分,如以下屏幕截图所示:
将飞机事件分为多个组件事件,不仅可以提高性能,还可以在不更改事件结构的情况下配置飞机的组件数量。
运行示例解决方案2
遵循JetSolution1
所有构建和运行说明,但是这次,导入JetSolution2
。
- 在Insight Inspector中打开以下记录以查看事件:
https://localhost:9443/ibm/insights/view?id=JetSolution-0.0
。 - 您应该在Insight Inspector中的以下屏幕截图中看到显示的实体:
从Insight Inspector验证事件现在已分散到不同的组件中,从而提高了性能并减少了出现高温实体的可能性。 可以肯定的是,您可以运行性能测试器,如下一节所述。
运行性能测试器作为示例解决方案2
现在,运行Java程序对引擎组件进行压力测试。
要运行性能测试器,请完成以下步骤:
- 打开在HttpPerformanceTester项目
JetSolution2
。 - 转到
src/dsi
文件夹,然后打开DSISendEvent.java
。 - 在
main()
方法的开头,设置以下值:NUMBER_OF_AIRPLANES = 50; NUMBER_OF_ENGINES = 2; NUMBER_OF_EVENTS = 500;
- 检查入站HTTP端点上的端口号对于您的安装是否正确:
urlStr = "http://localhost:9080/jetstatus/InboundHttpEndpoint";
- 通过右键单击
DSISendEvent.java
并选择Run as Java Application来保存更改并运行程序 。
在此处检查日志中的引擎代理活动:
Decision_Server_Insights_installation_directory \
Decision_Server_Insights_installation_directory \runtime\wlp\usr\servers\cisDev\logs\trace.log
在此处通过REST API检查引擎实体:
https://localhost:9443/ibm/ia/rest/solutions/JetSolution/entity-types/entityModel.Engine
不出所料,引擎实体将在几秒钟内更新为最新的引擎数据。
- 现在,更改以下常量以模拟引发事件风暴的单个引擎故障:
NUMBER_OF_AIRPLANES = 1;
NUMBER_OF_ENGINES = 1;
NUMBER_OF_EVENTS
= 500;
- 再次运行该程序,并检查跟踪日志。 这次只需要几分钟即可处理500个事件。 为什么? 因为所有事件都定向到单个引擎实体实例,并且该实例很热,所以如以下屏幕截图所示:
解决方案示例3:改进解决方案
在示例解决方案2中,引擎实体很热。 当引擎即将发生故障时,它接收了所有引擎事件。 现在,在最后的示例3中,您将应用克隆模式来冷却飞机解决方案。 现在,每个引擎实例的引擎事件由n个引擎克隆实体之一使用。 每个克隆都会汇总数据,并按定义的时间间隔将摘要传递给引擎代理。 引擎规则代理中的业务规则决定引擎是否即将发生故障。 该代理仅接收事件的子集,因此其绑定的实体并不热。
发生引擎事件风暴时,您将在解决方案中看到以下活动:
- 引擎事件被发送到引擎克隆代理 ,该代理绑定到多个引擎克隆实体 。
- 每隔30秒,每个引擎克隆实体都会向引擎规则代理发送引擎摘要事件 。
- 引擎规则代理绑定到引擎实体 。 规则使用引擎摘要事件来确定引擎是否发生故障。
以下屏幕截图显示了此序列:
克隆模式的实现
克隆模式的基础是EngineCloneJavaAgent.java
。 它为多个克隆实体之间的单个引擎分配了传入事件风暴,以分配事件负载。 每个克隆每隔30秒就会向引擎实体发出一次缓慢的摘要事件滴答声,因此它不再炙手可热。 代理Java类称为EngineCloneJavaAgent.java
。
EngineCloneJavaAgent.java
Java类内部包含以下流程事件方法:
清单5.流程事件方法
@Override
public void process(Event event) throws AgentException {
if (event instanceof EngineEvent) {
// Summarize the Engine event
summarizeEngineEvent((EngineEvent) event);
}
}
如果事件是一个实例EngineEvent
,那么下面summarizeEngineEvent
方法被称为:
清单6. summaryEngineEvent方法
/**
* Summarize the Engine event
*
* @param engineEvent the engine event to be summarized
* @throws AgentException
*/
private void summarizeEngineEvent(EngineEvent engineEvent) throws AgentException,
EntityTypeException {
EngineClone engineClone = (EngineClone) getBoundEntity();
String EngineCloneName = engineEvent.getEngineCloneId();
String engineName = engineEvent.getEngineId();
if (conceptFactory == null) {
conceptFactory = getConceptFactory(ConceptFactory.class);
}
if (engineClone == null) {
printToLog(Level.INFO, "Creating a new engine Clone: "
+ EngineCloneName + " associated to engine: " + engineName);
engineClone = (EngineClone) createBoundEntity();
engineClone.setEngineId(engineEvent.getEngineId());
engineClone.setEngineCloneId(EngineCloneName);
engineClone.setAircraftId(engineEvent.getAircraftId());
engineClone.setAverageExhaustTemperature(engineEvent.getExhaustTemperature());
engineClone.setAverageRpm(engineEvent.getRpm());
engineClone.setAveragePressureRatio(engineEvent.getPressureRatio());
engineClone.setEventCount(1);
engineClone.set$CreationTime(engineEvent.getTimestamp());
// Load the bound entity back into the grid
updateBoundEntity(engineClone);
} else {
printToLog(Level.INFO,
"Calculate averages in engine Clone: " + EngineCloneName);
int eventCount = engineClone.getEventCount() + 1;
engineClone.setEventCount(eventCount);
int averagePressureRatio = (engineClone.getAveragePressureRatio() +
engineEvent.getPressureRatio()) / 2;
engineClone.setAveragePressureRatio(averagePressureRatio);
int averageRpm = (engineClone.getAverageRpm() + engineEvent.getRpm()) / 2;
engineClone.setAverageRpm(averageRpm);
int averageExhaustTemperature = (engineClone.getAverageExhaustTemperature() +
engineEvent.getExhaustTemperature()) / 2;
engineClone.setAverageExhaustTemperature(averageExhaustTemperature);
}
// Schedule call back to emit summary event after n seconds
if (!engineClone.isTimerRunning()) {
engineClone.setTimerRunning(true);
printToLog(Level.INFO,
"Timer started for : " + engineClone.getEngineCloneId());
final int TIMER_INTERVAL = 30;
schedule(TIMER_INTERVAL, TimeUnit.SECONDS, "");
}
updateBoundEntity(engineClone);
}
此summarizeEngineEvent
方法总结了EngineEvent
通过创建发动机参数的加权平均值。 然后,它安排在30秒内(如果尚未安排)回叫以发出摘要事件。
每三十秒调用一次以下计时器回调方法:
清单7.计时器回调方法
@Override
// Timer callback method
public void process(String key, String cookie) throws AgentException {
EngineClone engineClone = (EngineClone) getBoundEntity();
if (engineClone != null) {
// Emit summary event to Engine Entity
emitSummaryEvent(engineClone);
// Delete the entity as its job is done
deleteBoundEntity();
}
}
然后,此计时器回调方法将调用下面的emitSummaryEvent
方法来发送引擎摘要事件:
清单8. glowSummaryEvent方法
/**
* Emit an Engine Summary Event
*
* @param EngineClone the Engine clone bound entity
*/
private void emitSummaryEvent(EngineClone EngineClone) {
if (conceptFactory == null) {
conceptFactory = getConceptFactory(ConceptFactory.class);
}
EngineSummaryEvent engineSummaryEvent =
conceptFactory.createEngineSummaryEvent(ZonedDateTime.now());
engineSummaryEvent.setEngineId(EngineClone.getEngineId());
engineSummaryEvent.setAircraftId(EngineClone.getAircraftId());
engineSummaryEvent.setAveragePressureRatio(EngineClone.getAveragePressureRatio());
engineSummaryEvent.setAverageRpm(EngineClone.getAverageRpm());
engineSummaryEvent.setAverageExhaustTemperature(EngineClone.getAverageExhaustTemperature());
engineSummaryEvent.setEventCount(EngineClone.getEventCount());
try {
printToLog(Level.INFO,
"Emit Engine Summary Event from : " +
EngineClone.getEngineCloneId() + " to " +
EngineClone.getEngineId());
emit(engineSummaryEvent);
} catch (AgentException e) {
printToLog(Level.SEVERE, "Error emitting Engine Summary Event : "
+ engineSummaryEvent.get$Id());
e.printStackTrace();
}
}
发送摘要事件后,摘要代理会删除绑定的实体。 代理仅在收到更多引擎事件时才创建新的克隆实体。
以这种方式再次删除和创建克隆会产生内存弹性,这意味着克隆仅在出现大量事件时才存在于内存中。 当没有事件风暴时,克隆较少,而没有事件时,则没有克隆。
调整克隆参数
如果应用克隆模式,则在实时响应和内存消耗之间需要权衡。
您可以使用两个参数NUMBER_OF_CLONES
和TIMER_INTERVAL
来控制实时响应和内存消耗的变量。
NUMBER_OF_CLONES个参数
为了获得最佳性能,每个实体使用10个克隆。 超过10个可能消耗过多的内存,而少于10个可能仍然允许热实体。 但是,您可以调整克隆数以适合您的解决方案。
例如,如果您有一些总是很热的实体,请增加克隆数。 如果您有很多偶尔变热的实体,请减少克隆数以节省内存。
要在示例解决方案3中更改克隆的数量, DsiEventXmlFactory.java
在HttpPerformanceTester项目中编辑DsiEventXmlFactory.java
。 编辑NUMBER_OF_CLONES
常数,如以下代码清单所示:
清单9.更改克隆数
final int NUMBER_OF_CLONES = 10;
final int engineCloneId = (int) (Math.random() * NUMBER_OF_CLONES);
Timer_Interval参数
计时器间隔指定接收引擎事件与发送引擎摘要事件之间的时间延迟。 延迟时间越长,摘要事件越少。
如果您的解决方案需要更快的响应时间,则可以减少计时器延迟。 但是,请理解,这种方法意味着更多摘要事件,这可能导致引擎实体再次变热。
为了在摘要事件的数量与近乎实时的情况检测之间取得良好的平衡,请使用30秒的延迟。
要在解决方案3中更改计时器间隔, EngineCloneJavaAgent.java
在EngineCloneJavaAgent项目中编辑EngineCloneJavaAgent.java
。 更改TIMER_INTERVAL
常量,如以下代码清单所示:
清单10.更改计时器间隔
final int TIMER_INTERVAL = 30;
schedule(TIMER_INTERVAL, TimeUnit.SECONDS, "");
运行示例解决方案3
要为示例解决方案3运行很酷的实体示例代码,请完成以下步骤:
- 使用
--clean
选项停止并重新启动cisDev Decision Server Insights服务器:server stop cisDev server start cisDev --clean
- 遵循
JetSolution1
所有构建和部署说明,但是这次导入JetSolution3
。 - 打开HttpPerformanceTester项目
- 导航到
src/dsi
文件夹,然后打开DSISendEvent.jav
a
。 - 在
main()
方法开始时,设置以下值以模拟引发事件风暴的单个引擎故障:
NUMBER_OF_AIRPLANES = 1;
NUMBER_OF_ENGINES = 1;
NUMBER_OF_EVENTSNUMBER_OF_AIRPLANES = 1;
NUMBER_OF_ENGINES = 1;
NUMBER_OF_EVENTS= 500;
- 查看日志。
这次,当您检查活动日志时,无论是使用多个平面还是仅使用一个平面运行样本,都应该看到一致的性能。 但是,请注意,发出的事件不再是实时的,而是延迟了计时器间隔,在这种情况下为30秒。
在此处检查活动日志:
Decision_Server_Insights_installation_directory \runtime\wlp\usr\servers\cisDev\logs\trace.log
通过REST API检查引擎克隆实体。 您应该看到十个实体:
https://localhost:9443/ibm/ia/rest/solutions/JetSolution/entity-types/entityModel.EngineClone
请注意,引擎克隆实体仅在内存中存在很短时间。 在将其摘要信息发送给引擎实体后,它们将被删除。
通过REST API检查引擎实体。 您应该看到一个单个实体,其中包含来自十个克隆的每一个的所有信息:
https://localhost:9443/ibm/ia/rest/solutions/JetSolution/entity-types/entityModel.Engine
结论
在本教程中,您学习了如何识别热实体的原因以及哪些设计技巧可帮助您避免它们。 您看到了三个示例Decision Server Insights解决方案。 第一个解决方案没有热实体优化,第二个解决方案具有部分优化,第三个解决方案具有完整优化。
现在,您可以识别出IBM ODM Decision Server Insights解决方案何时出现热实体带来的性能问题,并且为您提供了预防将来出现问题的技巧。
致谢
作者要感谢Pierre Berlandier,Dan Selman和Ben Cornwell审阅了本教程。
翻译自: https://www.ibm.com/developerworks/mobile/library/mw-1611-crowther-trs/1611-crowther.html
insights 磁力