這篇文章使用了一個通俗的具體的例子來講解Esper。在文末有兩個版本的代碼連結。通過這篇文章,你將會瞭解如何使用Esper,瞭解如何整合Esper到Spring架構中,瞭解如何使用Apache Active MQ和JMS來為Esper提供事件數目據。
以下是一個非常簡單的事件流處理樣本(使用ESPER引擎)。在GitHub上可以看到一個完整的代碼, ~ 連結在文末 ~。 什麼是複雜事件處理(CEP)。
複雜事件處理(CEP)或事件流流處理(ESP)是事件驅動系統中常用的技術。這些類型的系統即時響應事件數目據流。通常情況下,常常應用於金融交易,欺詐識別和流程監控 - -需要識別、理解並快速響應資料事件流中的模式。 CEP系統的關鍵組件
CEP系統就像典型資料庫模型顛倒過來一樣。一個典型的資料庫儲存資料,並對資料執行查詢,而CEP儲存`查詢語句,對即時資料流進來的資料進行匹配查詢或者說過濾和匹配。
要做到這一點基本上需要: 資料 - 以“事件”的形式,常見地以普通java類表示。 查詢 - 使用EPL(’事件處理語言’) 監聽器 - 如果有結果返回,那麼它會被觸發從而“執行某些操作”。(回呼函數) 一個簡單的例子 - 一座核電站
以核電站為例..
現在,這隻是一個例子 - 假設你最關心的是核電站的臨界溫度等的資訊。 監測核心溫度
假設我們的發電站有一個發電站,而且如果太熱的話 - 非常糟糕的事情會發生。所以檢測核電站核心地溫度並在異常情況下發出警告資訊是很重要地。
這裡寫圖片描述
假設我們有溫度計,每秒鐘讀取核心溫度 - 並將資料發送到中央監控系統。 有什麼要求。
當發現3種類型的事件時,我們需要警告:
監控
只需告訴我們每10秒鐘的平均溫度 - 供參考
警告
警告我們,如果我們有2個連續的溫度超過一定的閾值
危急
提醒我們,如果我們有4個連續事件,第一個事件超過一定的閾值,並且每個後續事件都大於最後一個 - 最後一個比第一個大1.5倍。這意味著有一個突然的不斷升高的溫度峰值 - 有點像下圖。讓我們假設這是一件非常糟糕的事情。
使用Esper
我們可以通過多種方式構建系統來處理這些需求。這篇文章將使用Esper來解決這個問題。
Esper大體這樣處理: 使用Esper建立3個查詢(使用EPL - Esper查詢語言)來對這些事件模式進行建模。 然後,我們為每個查詢附加一個接聽程式(listener) - 當EPL檢測到事件的匹配模式時,會觸發此接聽程式。 建立一個Esper服務,把上面的listener和它綁定,完成註冊。
當有匹配的資料的時候,Esper服務會向相關的listener發送訊息。
我們簡單的ESPER解決方案 系統的核心是用於檢測事件的3個查詢。 查詢1 - MONITOR(只監視平均溫度)
select avg(value) as avg_val from TemperatureEvent.win:time_batch(10 sec)
查詢2 - 警告(告訴我們,如果我們有2個連續事件違反閾值)
select * from TemperatureEvent " match_recognize ( measures A as temp1, B as temp2 pattern (A B) define A as A.temperature > 400, B as B.temperature > 400)
查詢3 - 關鍵 - 連續4個上升值超過100,第四個值比第一個大1.5倍
select * from TemperatureEvent match_recognize ( measures A as temp1, B as temp2, C as temp3, D as temp4 pattern (A B C D) defineA as A.temperature < 100, B as (A.temperature < B.value), C as (B.temperature < C.value), D as (C.temperature < D.value) and D.value > (A.value * 1.5))
一些程式碼片段 TemperatureEvent 假設我們的傳入資料以TemperatureEvent POJO的形式到達 可以通過JMS隊列傳入esper訊息資料,接聽程式再將其轉換為POJO。這樣使用JMS可以將我們從傳入的資料結構中分離出來,提高項目地靈活性。這裡只使用了普通地Java類。下面是我們的POJO的一個例子,表示事件類型。
package com.cor.cep.event;import java.util.Date;/** * Immutable Temperature Event class. * The process control system creates these events. * The TemperatureEventHandler picks these up * and processes them. */public class TemperatureEvent { /** Temperature in Celcius. */ private int temperature; /** Time temerature reading was taken. */ private Date timeOfReading; /** * Single value constructor. * @param value Temperature in Celsius. */ /** * Temerature constructor. * @param temperature Temperature in Celsius * @param timeOfReading Time of Reading */ public TemperatureEvent(int temperature, Date timeOfReading) { this.temperature = temperature; this.timeOfReading = timeOfReading; } /** * Get the Temperature. * @return Temperature in Celsius */ public int getTemperature() { return temperature; } /** * Get time Temperature reading was taken. * @return Time of Reading */ public Date getTimeOfReading() { return timeOfReading; } @Override public String toString() { return "TemperatureEvent [" + temperature + "C]"; }}處理這個事件 主要處理常式類在TemperatureEventHandler.java中,初始化了Esper服務。 建立了3個語句並為每個語句添加了一個接聽程式
/** * Auto initialise our service after Spring bean wiring is complete. */@Overridepublic void afterPropertiesSet() throws Exception { initService();}/** * Configure Esper Statement(s). */public void initService() { Configuration config = new Configuration(); // Recognise domain objects in this package in Esper. config.addEventTypeAutoName("com.cor.cep.event"); epService = EPServiceProviderManager.getDefaultProvider(config); createCriticalTemperatureCheckExpression(); createWarningTemperatureCheckExpression(); createTemperatureMonitorExpression();} 建立臨界溫度警告並註冊接聽程式。
/** * EPL to check for a sudden critical rise across 4 events, * where the last event is 1.5x greater than the first. * This is checking for a sudden, sustained escalating * rise in the temperature */ private void createCriticalTemperatureCheckExpression() { LOG.debug("create Critical Temperature Check Expression"); EPAdministrator epAdmin = epService.getEPAdministrator(); criticalEventStatement = epAdmin.createEPL(criticalEventSubscriber.getStatement()); criticalEventStatement.setSubscriber(criticalEventSubscriber); } 最後 - 一個關鍵事件監聽器的例子。
package com.cor.cep.subscriber;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.cor.cep.event.TemperatureEvent;/** * Wraps Esper Statement and Listener. No dependency on Esper libraries. */@Componentpublic class CriticalEventSubscriber implements StatementSubscriber { /** Logger */ private static Logger LOG = LoggerFactory.getLogger(CriticalEventSubscriber.class); /** Minimum starting threshold for a critical event. */ private static final String CRITICAL_EVENT_THRESHOLD = "100"; /** * If the last event in a critical sequence is this much greater * than the first - issue a critical alert. */ private static final String CRITICAL_EVENT_MULTIPLIER = "1.5"; /** * {@inheritDoc} */ public String getStatement() { // Example using 'Match Recognise' syntax. String criticalEventExpression = "select * from TemperatureEvent " + "match_recognize ( " + "measures A as temp1, B as temp2, C as temp3, D as temp4 " + "pattern (A B C D) " + "define " + " A as A.temperature > " + CRITICAL_EVENT_THRESHOLD + ", " + " B as (A.temperature < B.temperature), " + " C as (B.temperature < C.temperature), " + " D as (C.temperature < D.temperature) " + "and D.temperature > " + "(A.temperature * " + CRITICAL_EVENT_MULTIPLIER + ")" + ")"; return criticalEventExpression; } /** * Listener method called when Esper has detected a pattern match. */ public void update(Map<String, TemperatureEvent> eventMap) { // 1st Temperature in the Critical Sequence TemperatureEvent temp1 = (TemperatureEvent) eventMap.get("temp1"); // 2nd Temperature in the Critical Sequence TemperatureEvent temp2 = (TemperatureEvent) eventMap.get("temp2"); // 3rd Temperature in the Critical Sequence TemperatureEvent temp3 = (TemperatureEvent) eventMap.get("temp3"); // 4th Temperature in the Critical Sequence TemperatureEvent temp4 = (TemperatureEvent) eventMap.get("temp4"); StringBuilder sb = new StringBuilder(); sb.append("***************************************"); sb.append("n* [ALERT] : CRITICAL EVENT DETECTED! "); sb.append("n* " + temp1 + " > " + temp2 + " > " + temp3 + " > " + temp4); sb.append("n***************************************"); LOG.debug(sb.toString()); }}代碼運行
運行示範的完整說明可以在這裡找到:
這裡有兩個GitHub代碼,它們在Esper的部分是一樣的,區別在於,第一個使用一個POJO類產生Esper訊息,比較簡單。第二個在第一個地基礎之上做了拓展,增加了JMS和Apache ActiveMQ。也就是使用JMS來產生Esper訊息。如果要順利執行第二個代碼,需要額外安裝Apache ActiveMQ。具體情況請閱讀每一個項目地README檔案。
1. github.com/corsoft/esper-demo-nuclear
2. https://github.com/liangyihuai/Esper4SpingJMS
運行示範的一個例子如下所示 - 它產生隨機溫度事件並通過Esper處理器發送它們。
當我們的3個查詢中的任何一個檢測到匹配時 - 調試資訊被顯示到控制台。在現實世界的解決方案中,這三個監聽器中的每一個都會以不同的方式處理這些事件 - 也許可以通過發送訊息來提醒隊列/端點來擷取系統的其他部分來擷取處理。
結論
使用像Esper這樣的系統是一種使用最少代碼即時監控和識別資料模式的簡便方法。
這篇文章只是一個簡單的用例。查看 Esper網站擷取更多資訊。
這篇文章翻譯自:complex-event-processing-made