Esper學習 -- 第一章 Esper初體驗
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應用。
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來快速的產生、編譯程式碼。