复杂事件处理引擎—Esper入门(第二弹)

时间:2021-09-27 20:34:02

说明:

  以下内容,可以参考Esper官方网站《Qucik start & Tutorial 》(顺序做了部分调整)。 PS:因为英语水平有限(大学期间刚过CET4的英语小盲童一枚),翻译很烂(自己都感觉不能直视),描述不清的,可以随时问。一有时间,将给予解释。

Tutorial (教程)部分

1、简介 (该部分在入门第一弹中有提起)

Esper 是一个事件流处理和事件关联的引擎(CEP,complex event processing 复合事件处理)。作为实时事件驱动框架,当事件流中有事件条件发生时,Esper能够触发自定义动作(POJO)。Esper也是为了大量事件关联而设计,当有数百万的事件进来时,不能用经典的数据库架构来存储所有事件。

定制的事件处理语言EPL,允许表达丰富的事件条件、关联性,也可跨越事件窗口,从而最大限度的减少为应对复杂情况而必须建立系统的开发难度。

Esper是轻量级的java内核实现,其可以完全嵌入到任何的java进程、javaEE应用服务器或者给予java的ESB(企业服务总线)。Esper可以很快完成传入的大量消息或者事件处理的应用程序。

【总结】Esper是一个事件处理和复杂事件关联处理的java内核的轻量级引擎。对于大量事件的处理,能够用最短的时间做出反应,触发相应的操作。另外,为Esper量身定制的事件处理语言——类SQL语言,对于表达事件的条件以及关联关系的处理等非常方便。

2、事件流和复杂事件

信息对于作出明智的选择是至关重要的。不仅现实生活中这是事实,而且在计算机处理中尤其是一些领域,比如金融、欺诈检测、商业智能或是战场操作等,也是很重要的。信息从不同的来源,以消息或者事件的形式流动,如股票价格在某一特定时间的状态需要给出一个提示。也就是说,看离散的数据大部分时间是没有意义的。交易者需要看到一段时间的股票走势,以便结合其他信息在合适的时间做出最好的交易。

一条一条的离散事件是没有意义的,事件流——一个无限的事件集合——可认为是一个滑动的窗口,进一步关联是非常有意义的,并用最小的延迟对事件做出反应,对有效行动和竞争优势是至关重要的。

【总结】事件流其实一个个离散的事件串接而成。现实中对于事件流的监控或者处理,比如股票信息等,需要实时性的计算其走势,以便能够及时的获取有价值数据。事件流在Esper中是一个滑动的窗口,对事件关联处理等至关重要。

3、Esper

关系型数据库或者基于消息的系统比如JMS,真的很难处理时间数据和实时查询。事实上,数据库需要一个明确的查询来返回有意义的数据,并且在数据放生变化时不适合推送数据。JMS系统是无状态的,需要开发人员自己实现这个时间和聚合的逻辑。相比之下,Esper提供了更高的抽象和智能,可以认为是数据库的倒置:不是存储数据,而是对存储的数据运行查询,Esper允许应用程序存储查询,并让数据运行通过。当满足查询的条件发生时,Esper会做出实时的响应。执行模块是持续的,而不是只有在查询提交的时候。这个概念是EDA(事件驱动架构)的关键基础,在过去的10年,甚至更久都一直在积极的研究。然而,现实中对该系统重要性的认知最近才开始出现。

在Esper中,定制的EPL允许在引擎中注册查询。监听类(POJO类)会在事件满足EPL条件的时候由引擎进行调用。EPL能够表达复杂的匹配条件,包括事件窗口、事件流关联、过滤、聚合以及排序等。Esper statement也可以通过“followed by ” 即“->”条件从多个简单的事件中获取复杂事件。事件可以被描述成JavaBean类、传统的java类、XML或者是Map,作为消息发布者,促进重用现有的系统。

【总结】在处理实时性的数据时,比如心跳监控、股票价格走势等,Esper相对于关系型数据库有天然的优势,Esper不需要对完成的数据的存储,便可以完成数据的实时查询处理,从这点看,更像是数据库的倒置——试想一下,数据库是先存储数据,通过编译解析SQL,完成已存储数据的查询,Esper则是先编译EPL语句,形成一个过滤(或处理)层(或者网),实时过来的数据,通过这个过滤层完成有效事件的筛选或形成有效事件。Esper的事件处理语言——EPL,是类SQL语言,其select 语句、from语句、where语句以及group by 、having等,甚至包括大部分的聚合函数等,都和标准的SQL语言一致。在EPL规则的编写上,对于有数据库开发经验的人来说,上手十分容易。

4、开发事件驱动应用

用Esper来开发事件驱动应用并不困难。大概有下面的几步:

1> 通过分析业务域和定义探测的情景或者需要报告的信息,定义应用程序应该完成的功能或任务。

2> 定义性能要求,特别是吞吐量和延迟。

3> 确定从什么地方获取事件。

4> 根据业务确定事件格式和事件内容。

5> 设计导致复杂事件的事件关系。

6> 事件源。

7>  设计事件表示类型:java类、map、或XML等

8> 定义EPL语句,用于匹配模式和流的处理。

9> 比如,用CSV适配器作为事件模拟工具,测试检测场景,或产生加载加载事件。

10> 在最终的环境上,测试吞吐量和延迟。

5、设计事件表示方式

在Esper当中,java类是一种简单、丰富且通用的事件表示方式。通过接口和超类,java类提供了继承性和多态性,通过一个对象graph,就可以表示一个复杂的业务域。Maps或XML也是事件表示的一种方式。

6、事件流分析

EPL语句从一个或者多个事件流中派生和聚合信息,加入或合并事件流,并将一个时间流的结果提供给后续的语句。EPL在select语句和where语句的使用上,和SQL很相似。不过EPL语句用事件流和views替换了数据库的表格。和SQL中表格相似,views定义了可用于查询和过滤的数据。Views可以表示为一个事件流上的一个窗口。Views也可以排序事件、从事件属性获取统计数据、进行事件分组或者处理唯一的事件属性值。

下面的EPL语句用于计算股票事件过去30s的平均价格:

select avg(price) from StockTickEvent.win:time(30 sec)

下面EPL返回的是前100条股票事件的平均值:

select symbol, avg(price) as averagePrice
from StockTickEvent.win:length(100)
group by symbol

下面的例子关联了两个事件流。第一个事件流由欺诈告警事件组成,用于保存过去30分钟的事件信息。第二个流则是withdrawal事件,用来保存过去30秒的事件。这两个流通过account number进行关联:

select fraud.accountNumber as accntNum, fraud.warning as warn, withdraw.amount as amount,
MAX(fraud.timestamp, withdraw.timestamp) as timestamp, 'withdrawlFraud' as desc
from FraudWarningEvent.win:time(30 min) as fraud,
WithdrawalEvent.win:time(30 sec) as withdraw
where fraud.accountNumber = withdraw.accountNumber

7、事件模式匹配

Event patterns match when an event or multiple events occur that match the pattern's definition.

一个或多个事件发生时,事件模式会匹配定义的模式(很别扭啊⊙﹏⊙b)。模式也可以是基于时间的。模式匹配时通过状态机实现的。

模式表达式可以由连接了模式操作符的过滤器表达式组成。通过在圆括号中的嵌入表达式,可以实现更深的模式表达式嵌套。

5类操作符:

·控制模式探测器的创建和终止:every

· 逻辑操作符:and、or、not

· 操作事件顺序的时间操作符:-> (紧跟着发生的,followed by)

· 过滤输出事件的where条件,引起模式探测器的终止:如,timer:within

· 和观察其他事件一样,观察者也观察时间事件,如 timer:interval,  timer:at

下面是一些EPL的例子:

//模式匹配的是在接下来60秒钟IBM股票值大于80的所有事件
every StockTickEvent(symbol="IBM", price>80) where timer:within(60 seconds)
//每小时的第5分钟给出提醒:
every timer:at(5, *, *, *, *)
//当A事件发生时,如果后面跟的是B事件或C事件,则给出提醒(输出A事件)
A -> ( B or C )
//匹配的是每一个EventX,如果后跟EventY事件,并且其objectID和EventX的objectID一样,则给出提醒(输出a事件):
every a=EventX -> every b=EventY(objectID=a.objectID)

8、模式匹配和事件流分析结合使用

当检测到事件序列(或没有事件发生)时,模式就会匹配。模式匹配的结果可以用于进一步的分析和处理。

下面的模式监测的是 Status事件发生后的10s没有相同ID的status事件发生的场景。整个EPL语句进一步计算了所有发生的每个ID的事件总数。

select a.id, count(*) from pattern [
every a=Status -> (timer:interval(10 sec) and not Status(id=a.id)
] group by id

9、命名窗口

命名窗口在引擎中是全局的数据窗口,其可以参与到很多的语句查询,并且可以被多个statement执行select、insert和delete操作。命名窗口和关系型数据库系统的表很相似。

通过下面的几步可以创建命名窗口:

create window AlertNamedWindow as (origin string, priority string, alarmNumber long)

当事件到达时,可以触发一个select、update或delete操作。下面是一个select应用,简单的统计数据窗口中的记录行总数:

on TriggerEvent select count(*) from AlertNamedWindow

10、匹配-识别模式匹配(Match-Recognize Pattern Matching)

匹配-识别模式是一个基于正则表达式的模式匹配语法,是建议列入SQL的标准语法。

下面的匹配-识别模式,探测的是可能出现在事件中的模式,这些事件通过命名窗口(如上声明)保存。这个模式查找的是两个紧跟的事件,即事件之间没有相同的origin。第一个事件必须有一个“high”优先级,第二个事件必须是“medium”优先级。

select * from AlertNamedWindow
match_recognize (
partition by origin
measures a1.origin as origin, a1.alarmNumber as alarmNumber1, a2.alarmNumber as alarmNumber2
pattern (a1 a2)
define
a1 as a1.priority = 'high',
a2 as a2.priority = 'medium'
)

11、变量(Variables)

变量是一个标量、对象或者事件值,可用于所有的statement,包括模式。变量可以用在EPL中任意位置的表达式中。

【总结】开发Esper应用时,事件类型建议采用Java类,对于事件信息的描述更为直观(参考<a href="http://esper.codehaus.org/tutorials/tutorial/quickstart.html">Quick Start</a>)。在具有复杂关系的事件设计中,不建议使用Map的方式(可参考<a href="http://esper.codehaus.org/esper-4.9.0/doc/reference/en-US/html/performance.html#perf-tips-22">Esper参考文档性能部分</a>)。在EPL设计时,根据业务需求,如果能通过标准的SQL语法完成的,尽量不要使用匹配模式,因为在运行时,需要对Pattern进行额外的解析,其规则较SQL复杂,性能上有少许损耗。

数据窗口的使用,能够使得Esper处理更为复杂的应用场景,比如与分布式缓存、静态数据的使用等。变量不难理解,不管是高级的开发语言如java、C/C++,还是脚本语言如ruby、JS等,都有变量的概念,其使用范围,仅限于当前的Esper引擎实例。

另外,本节所描述的信息,如EPL、数据窗口等概念会在后续的更新中详细描述。敬请期待!!

注:转载请注明出处! 谢谢!