【基本简介】
- Esper是一个事件流处理(ESP)和事件关联引擎(CEP的,复杂事件处理)。
- Esper的目标是针对实时事件驱动架构(EDA) 。
- Esper监测到事件流中又符合条件的时间发生时,即可触发PlainOldJavaObjects(POJO)编写的自定义操作。
当数百万数量级的事件同时发生时,我们不可能使用普通的关系型数据库来存储和查询,Esper正是专为这样的大批量关联事件而设计的。
【Esper概念】
- Esper提供一个定制的事件处理语言(EPL),允许的条件表达丰富的事件,相关性,可能跨越时间窗,从而减少开发工作需要设置一个系统,可以对复杂的情况作出反应。
- Esper是一个轻量级的Java编写的内核是完全纳入任何Java进程,JEE应用服务器或基于Java的企业服务总线嵌入的。它使应用程序的过程中收到的消息或事件的大量快速发展。
介绍事件流和复杂事件信息是至关重要的作出明智的决定。
Esper,不得不说一下CEP。CEP即Complex Event Process,中文意思就是"复杂事件处理"。
听起来好像很复杂,实际上就是基于事件流进行数据处理,把要分析的数据抽象成事件,然后将数据发送到CEP引擎,引擎就会根据事件的输入和最初注册的处理模型,得到事件处理结果。
【CEP介绍】
Complex Event Processing, 复杂事件处理
事件(Event)一般情况下指的是一个系统中正在发生的事,事件可能发生在系统的各个层面上,它可以是某个动作,例如客户下单,发送消息,提交报告等,也可以是某种状态的改变,例如温度的变化,超时等等。
通过对这些事件进行分析,可以提取出其中有效的信息。 根据维基百科的定义,事件处理(Event processing)指的是跟踪系统中发生的事件,分析事件中的信息并从中得到某种结论。而复杂事件处理,则是结合多个事件源中的事件,从中推断出更加复杂的情况下的事件。
由此可见,CEP的目的包括:
- (1)识别所需要的事件;
- (2)快速地对这些事件进行处理。
通常情况下,我们想要利用CEP达到的目的是掌握当前的某种情况或者说状态,因此CEP感兴趣的不是事件本身给出的信息,而是通过这些信息所能推导出的某种结论,通过CEP,我们能够让这些事件变得有意义。
要实现一个CEP引擎,需要考虑的事情包括:
- (1)吞吐量;
- (2)低延迟,从事件到达到事件被处理,不能有太大的延迟;
- (3)复杂的逻辑处理,CEP需要能够对事件进行较为复杂的操作,例如,检测事件之间的相关性,过滤,加窗,连接等。
CEP是一种标准,Esper只是对这个标准的一种开源实现。除了Esper,很多大公司也有类似的商业软件,比如IBM,Sybase等等,听说巨贵无比。
CEP的一个重要特点就是他是一个内存计算工具和类SQL语句。内存计算可以说是一把双刃剑。
- 好处自不必说,一个字:快!坏处也显而易见,数据有丢失的风险,而且还有容量的限制(实时计算其实并不受制于内存大小,而是得看如何对实时进行定义,也就是具体的业务来决定了)。
- 所以如果业务不能容忍数据丢失,那么高可用方案就必须做好,不过Esper的高可用很不好做。
CEP的类SQL语句,可以理解为处理模型的定义与描述。这是运行在CEP引擎中的特殊语句,之所以叫他类SQL,是因为它和SQL确实很像,除了select,insert,delete,update,而且也有avg,count等函数。
所以对于会SQL的人来说,他的语法结构大致还是能猜出一二的。在Esper中,这个句子叫做EPL,即Event Process Language。作为Esper的核心内容。
定制的事件处理语言EPL,允许表达丰富的事件条件、关联性,也可跨越事件窗口,从而最大限度的减少为应对复杂情况而必须建立系统的开发难度。
【总结】
Esper是一个事件处理和复杂事件关联处理的java内核的轻量级引擎。对于大量事件的处理,能够用最短的时间做出反应,触发相应的操作。另外,为Esper量身定制的事件处理语言——类SQL语言,对于表达事件的条件以及关联关系的处理等非常方便。
事件流和复杂事件
一条一条的离散事件是没有意义的,事件流——一个无限的事件集合——可认为是一个滑动的窗口,进一步关联是非常有意义的,并用最小的延迟对事件做出反应,对有效行动和竞争优势是至关重要的。
事件流其实一个个离散的事件串接而成。现实中对于事件流的监控或者处理,比如股票信息等,需要实时性的计算其走势,以便能够及时的获取有价值数据。事件流在Esper中是一个滑动的窗口,对事件关联处理等至关重要。
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> 在最终的环境上,测试吞吐量和延迟。
设计事件表示方式
在Esper当中,java类是一种简单、丰富且通用的事件表示方式。通过接口和超类,java类提供了继承性和多态性,通过一个对象graph,就可以表示一个复杂的业务域。Maps或XML也是事件表示的一种方式。
事件流分析
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 复制代码 复制代码
下面的例子关联了两个事件流。
第一个事件流由欺诈告警事件组成,用于保存过去30s的事件信息。
第二个流则是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 复制代码 复制代码
事件模式匹配
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) 复制代码 复制代码
模式匹配和事件流分析结合使用
当检测到事件序列(或没有事件发生)时,模式就会匹配。模式匹配的结果可以用于进一步的分析和处理。
下面的模式监测的是 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 复制代码 复制代码
命名窗口
命名窗口在引擎中是全局的数据窗口,其可以参与到很多的语句查询,并且可以被多个statement执行select、insert和delete操作。命名窗口和关系型数据库系统的表很相似。
通过下面的几步可以创建命名窗口:
create window AlertNamedWindow as (origin string, priority string, alarmNumber long) 复制代码 复制代码
当事件到达时,可以触发一个select、update或delete操作。下面是一个select应用,简单的统计数据窗口中的记录行总数:
on TriggerEvent select count(*) from AlertNamedWindow 复制代码 复制代码
匹配-识别模式匹配(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' ) 复制代码 复制代码
变量(Variables)
变量是一个标量、对象或者事件值,可用于所有的statement,包括模式。变量可以用在EPL中任意位置的表达式中。
【总结】开发Esper应用时,事件类型建议采用Java类,对于事件信息的描述更为直观(参考Quick Start)。在具有复杂关系的事件设计中,不建议使用Map的方式(可参考Esper参考文档性能部分)。
在EPL设计时,根据业务需求,如果能通过标准的SQL语法完成的,尽量不要使用匹配模式,因为在运行时,需要对Pattern进行额外的解析,其规则较SQL复杂,性能上有少许损耗。
数据窗口的使用,能够使得Esper处理更为复杂的应用场景,比如与分布式缓存、静态数据的使用等。变量不难理解,不管是高级的开发语言如java、C/C++,还是脚本语言如ruby、JS等,都有变量的概念,其使用范围,仅限于当前的Esper引擎实例。