Esper 参考
翻译自:Esper Version 7.1.0 参考手册,详情可以查询:EsperTech Inc. (http://www.espertech.com)
Author:saillen
第一章 起始
1.1 复杂事件处理(CEP)简介
Esper引擎被应用程序用来分析和处理事件。它的一些典型应用场景如下:
- 业务流程管理和自动化处理(处理监控事件、BAM、报告一些异常等);
- 金融领域:交易行为、欺诈检测、风险控制;
- 网络和应用监控:入侵检测、SLA监测;
- 基于传感器的应用:RFID应用、航空管制、制造业流水线的调度、管理;
这些应用场景中有一些共同的需求就是需要实时或者近实时的处理事件或者消息。这种处理方式被称为复杂事件处理
、系列事件分析
。这些场景都需要考虑的一些共有问题:吞吐量
、延迟性
和复杂的逻辑处理
;
- 高吞吐量:应用需要在短时间内处理大量事件(需要具备每秒1000到100K的消息处理能力);
- 低延迟:应用需要在短时间内给出响应结果;
- 复杂的计算逻辑:应用程序需要在事件间检测模式(检测事件的相关性),过滤不必要的事件,在事件上做一些基于时间、长度的聚合统计等。
Esper引擎的设计目标就是:可以很容易的构建一个CEP应用。
更多的关于CEP的信息可以参考:http://www.espertech.com/esper/esperfaq#whatiscep
1.2 HelloWord工程
1.2.1 第一步:设置Classpath;
如果不使用Maven的话,需要将Esper和它依赖的jar文件加入到classpath中,这些jar包需要自行下载:
- Esper 核心jra包: esper-version.jar;
- ANTLR 分析用jar包:antlr-runtime-4.7.jar;
- CGLIB 代码产生jar包:cglib-nodep-3.2.5.jar;
- SFG4J 日志哭:slf4j-api.1.7.25.jar;
- Janino Java编译器:janino-3.0.7.jar 和 commons-compiler-3.0.7.jar
如果你的项目想使用Log4j作为日志框架,可以添加slf4j-log3jl2-1.2.25.jar
和 log4j-1.2.17.jar
相关包。
如果你还需要使用Apache的Avro
,可以添加 epser-avro-version.jar
。
如果你使用Maven的话,可以加入如下的Maven依赖:
<dependency>
<groupId>com.espertech</groupId>
<artifactId>esper</artifactId>
<version>7.1.0</version>
</dependency>
1.2.2 第二步:获取引擎实例
在应用中可以通过调用EPServiceProvierManager
类的静态方法:getDefaultProvier
获取一个引擎实例。
EPServiceProvider engine = EPServiceProviderManager.getDefaultProvider();
上面的示例中没有使用配置对象,这样引擎会使用默认配置。引擎默认的URI配置为:default
。
PS : 这里提到的URI可以先忽略,真正Esper使用的时候,会使用Configuration对象配置下事件的命名空间等概念。
1.2.3 第三步:为输入事件(Input Event)提供信息;
获取引擎instance后需要向引擎注册一个Event Type
,Evenet Type
用来告诉引擎一个Event
的数据结构是什么样的。当创建一个EPL
语句后,引擎会检查注册过的Event Type
,然后选择一个合适的类型来表示事件的数据结构。
下面的例子使用的是Java类再来定义Event Type
。PersonEvent
类表示的是事件类型(即事件具有的属性和结构),每个PersonEvent
的实例表示的具体的事件。Esper不要求每个Event Type
都创建一个java类,它支持多种数据结构。具体使用哪种数据结构可以根据自己的应用的实际情况来决定。
package com.saillen.esper.demo;
public class PersonEvent{
private String name;
private int age;
public PersonEvent(String name, int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
在程序里面可以通过调用Configuration
对象的 addEventType
方法来注册一个Event Type
,这个方法是一个运行时配置接口的方法。
engine.getEpAdministrator().getConfiguration().addEventType(PersonEvent.class);
通过调用addEventType
方法来告诉引擎Event type
,引擎基于java的反射API会自动分析事件的属性信息。比如上面的代码,我们告诉引擎事件类型为PersonEvent
。PersonEvent
有两个符合JavaBean标准的getter
方法。这样引擎就知道,PersonEvent
有两个属性:一个string
类型的name
属性,一个int
类型的age
属性。
现在,引擎已经知道了有一个 PersonEvent
类型的事件,然后在应用程序中就可以创建EPL
语句给引擎,然后EPL
就可以使用到事件的属性信息。
除了可以定义Java Class
类型的事件Type外,Esper还支持使用Apache Avro
模式或者XML
格式、Map
、属性名数组
的方式来定义event type
。
定义event type是用过 Configuration
对象完成的,除了可以调用api接口,还可以使用 EPL语句,类似:create schema
的方式。
1.2.4 第四步:创建EPL语句并且添加回调
在起始章节,一个EPL
语句非常简单,仅仅用来查询每个person event中的name和age属性,eg:
select name,age from PersonEvent
在应用程序中可以通过administrative
接口的createEPL
方法来创建一个EPL statement。
String epl = "select name , age from PersonEvent";
EPStatement statement = engine.getEPAdministrator().createEPL(epl);
上面调用createEPL
方法后,引擎会校验from
子句中出现的PersonEvent
是否存在,引擎还会校验select
子句中出现的 name
和age
属性在PersonEvent
中是否存在。
当引擎校验成功后,引擎会向内部维护的一个 filter index tree
(基于索引结构的过滤树?)添加一个对象,这个tree结构的对象会保证每个Person Event
来的时候会被这个statement
处理。
应用程序中也可以添加一个EPStatement
的回调,这个回调用来接收语句的处理结果,类似如下:
//这里用的是JDK 8的lamad表达式,实际上就是一个UpdateListener接口的匿名实现。
statement.addListener( (newData,oldData) -> {
String name = (String)newData[0].get("name");
int age = newData[0].get("age");
System.out.pritnln(String.format("Name: %s, Age : %d",name, age));
} )
PS: EPL语句其实就是Esper定义的一种事件处理规则类似Sql语句,statement可以作为Esper的一个术语看待,Esper的参考文档第二章专门讲述了Esper语句里面的各种概念,使用Esper的核心有很大一部分就是写EPL语句。
1.2.5 第五步:发送事件(Events)
在应用程序中可以通过sendEvent
方法来发送一个事件:
engine.getEpRuntime().sendEvent(new PersonEvent("Peter",10));
然后你的程序会看见如下的输入内容:
Name: Peter, Age:10
当调用sendEvent
发送事件的时候,引擎会询问内部维护的 filter index tree
,来决定是否有EPL statement
对这个事件感兴趣。EPL语句作为Person事件的一部分,引擎会把这个event
委托给statement
处理。EPL statement
通过调用getName
和getAge
方法来获取name
、age
属性。
最后,下面是完整的事件处理代码:
EPServiceProvider engine = EPServiceProvierManager.getDefaultProvider();
engein.getEPAdministraotr().getConfiguration().addEventType(PersonEvent.class);
String epl = " select name, age from PersonEvent ";
EPStatement statement = engine.getEPAdministrator().createEPL(epl);
statement.addListener( (newData,oldData)-> {
String name = (String)newData[0].get("name");
int age = (int) newData[0].get("age");
System.out.println(String.format("Name: %s, Age: %d",name,age));
});
engine.getEPRuntime().sendEvent(new PersonEvent("Peter",10));
1.3 需要的第三方库
Esper需要下面的第三方库来支撑它的运行:
- ANTLR:全称ANother Tool for Language Recognition,是一种语言识别工具,Esper用它来解析EPL语句;
- CGLIB:用来织入二进制代码的工具,Esper为了提升处理效率会产生很多高校的class;
- SLF4J:日志框架,可以和Log4j一起工作,slf4j仅仅是一个门面,不影响具体日志框架的选择;
- Janino:一个小巧快速的java编译器,Esper为了提升效率,使用janino来快速的产生、编译代码。