让Storm插上CEP的翅膀 - Siddhi调研和集成
什么是 Siddhi?
Siddhi 是一种 lightweight, easy-to-use, open source CEP(Complex Event Processing)引擎,由wso2公司开发(http://wso2.com/about/)。
像绝大多数的 CEP 系统一样,Siddhi 支持对于流式数据的类 SQL 的查询,SQL 式的 query 通过 complier 翻译成 Java 代码。
当一条数据流或多条数据流流入时,Siddhi Core 会实时的 check 当前数据流是否满足定义的 query,如果满足则触发 Callback 执行相应的逻辑。
Siddhi和传统的CEP系统,如Esper,相比区别?
主要是比较轻量和高效,之所以可以达到更高的 performance,因为:
- Multi-threading
- Queues and use of pipelining
- Nested queries and chaining streams
- Query optimization and common sub query elimination
尤其是前两点非常关键,传统的CEP系统,如果Esper,都是使用单线程去处理所有的 query matching,这样虽然简单,但是效率不高,无法利用 cpu 多核。
所以 Siddhi 采用多线程,并且结合pipeline机制,如下图
Siddhi 将整个 query 切分成独立的 stages,即 processors,这样做的好处,首先是便于多线程化,再者,可以重用相同的 processor;
而 processor 之间通过 queue 进行连接,这里就不详细描述了,有兴趣的同学可以去仔细看 Siddhi 的论文和文档。
Siddhi 能做什么?
下面我们就来看看,最关键的,Siddhi 可以为我们做什么?
这里就用几个形象的例子来说明 Siddhi 使用的典型的场景
简单 ETL
我们先用个最简单的例子,看看如果 run 一个真正的 Siddhi 例子,
上面说了,Siddhi 是用类 SQL 的查询语言,
首先需要先定义流的格式,
define stream TempStream (deviceID long, roomNo int, temp double);
然后定义查询,
from TempStream
select roomNo, temp * 9/5 + 32 as temp, 'F' as scale, roomNo >= 100 and roomNo < 110 as isServerRoom
insert into RoomTempStream;
这样就能实现一个完整的 ETL 过程,
extraction,将需要的字段从 TempStream 里面 select 出来;
transform, 将摄氏温度转换为华氏温度;
loading,将结果输出到RoomTempStream流;
很方便,不用再另外写任何的逻辑,只需要写类SQL的Query语句。
为了增加感性认识,我给出一个完成的 Java 测试例子,
SiddhiManager siddhiManager = new SiddhiManager(); String executionPlan = "" +
"ddefine stream TempStream (deviceID int, roomNo int, temp float);" +
"" +
"@info(name = 'query1') " +
"from TempStream " +
"select roomNo, temp * 9/5 + 32 as temp, 'F' as scale, roomNo >= 100 and roomNo < 110 as isServerRoom " +
"insert into RoomTempStream;"; ExecutionPlanRuntime executionPlanRuntime = siddhiManager.createExecutionPlanRuntime(executionPlan); executionPlanRuntime.addCallback("query1", new QueryCallback() {
@Override
public void receive(long timeStamp, Event[] inEvents, Event[] removeEvents) {
EventPrinter.print(timeStamp, inEvents, removeEvents);
}
}); InputHandler inputHandler = executionPlanRuntime.getInputHandler("TempStream");
executionPlanRuntime.start(); inputHandler.send(new Object[] {12344, 201, 28.2f});
inputHandler.send(new Object[] {12345, 202, 22.2f});
inputHandler.send(new Object[] {12346, 203, 24.2f});
//Shutting down the runtime
executionPlanRuntime.shutdown(); //Shutting down Siddhi
siddhiManager.shutdown();
基于 window 聚合
Siddhi 支持很多中类型的 window,具体参考https://docs.wso2.com/display/CEP400/Inbuilt+Windows#InbuiltWindows-time
这里给出最基本的,基于时间窗口的例子,
from TempStream#window.time(1 min)
select roomNo, avg(temp) as avgTemp
group by roomNo
insert all events into AvgRoomTempStream ;
这个查询会计算以1分钟为滑动窗口的,每个 room 的平均温度
Siddhi时间窗口也支持,按照外部的输入的时间进行聚合,但是它要求时间是必须递增的;这点我们brain的聚合库比它通用,可以适用于非单调递增的场景
多个流 Join
Siddhi 支持基于 window 的多个流的实时 join,
from TempStream[temp > 30.0]#window.time(1 min) as T
join RegulatorStream[isOn == false]#window.length(1) as R
on T.roomNo == R.roomNo
select T.roomNo, T.temp, R.deviceID, 'start' as action
insert into RegulatorActionStream ;
上面的查询将,TempStream 和RegulatorStream 通过 roomNo 进行 join
Pattern Query
这种 query 最能表达出 CEP 的威力,什么是Pattern Query?
“Pattern allows event streams to be correlated over time and detect event patterns based on the order of event arrival.”
直接看个例子,用 Pattern 查询来 detect credit card/ATM transaction frauds:
from every a1 = atmStatsStream[amountWithdrawed < 100]
-> b1 = atmStatsStream[amountWithdrawed > 10000 and a1.cardNo == b1.cardNo]
within 1 day
select a1.cardNo as cardNo, a1.cardHolderName as cardHolderName, b1.amountWithdrawed as amountWithdrawed, b1.location as location, b1.cardHolderMobile as cardHolderMobile
insert into possibleFraudStream;
注意看到这个符号‘->’,这个表示 event 发生顺序,
上面这个查询的意思就是,在一天内,出现一次取现金额 < 100后,同一张卡,出现取现金额 > 10000,则认为可能是 fraud。
当然这只是个例子,不是说这样真的可以 detect fraud。你可以参照这个,写出更为复杂的查询。
Sequence Query
和 pattern 的区别是,pattern 的多个 event 之间可以是不连续的,但 sequence 的 events 之间必须是连续的。
我们可以看个例子,用 sequence 来发现股票价格的 peak:
from every e1=FilteredStockStream[price>20],
e2=FilteredStockStream[((e2[last].price is null) and price>=e1.price) or ((not (e2[last].price is null)) and price>=e2[last].price)],
e3=FilteredStockStream[price<e2[last].price]
select e1.price as priceInitial, e2[last].price as pricePeak, e3.price as priceAfterPeak
insert into PeakStream ;
上面的查询的意思,
e1,收到一条 event.price>20
e2,后续收到的所有 events 的 price,都大于前一条 event
e3,最终收到一条 event 的 price,小于前一条 event
ok,我们发现了一个peak
Siddhi 还有其他很多的功能,这里就不一一说明。。。。。。
集成到 Storm
那么最后,我们看看如何将 Siddhi 融入到我们当前的框架中,达到作为 Brain 补充的目的。
我将 Siddhi core 封装成一个 Siddhi Bolt,这样可以在 JStorm 的 topology 中很灵活的,选择是否什么方案,可以部分统计用 brain,部分用 Siddhi,非常简单。
废话不说,直接给出源码,供大家参考,
public class SiddhiBolt implements IRichBolt {
protected OutputCollector collector;
protected SiddhiManager siddhiManager = null;
protected String executionPlan = null;
ExecutionPlanRuntime executionPlanRuntime = null;
protected HashMap<String,InputHandler> handlers = null; public SiddhiBolt(String plan) {
this.executionPlan = plan;
} public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
this.siddhiManager = new SiddhiManager();
this.executionPlanRuntime = siddhiManager.createExecutionPlanRuntime(executionPlan);
addCallbacks();
handlers = new HashMap<String,InputHandler>();
executionPlanRuntime.start();
} public void execute(Tuple tuple) {
String inputStream = tuple.getSourceStreamId();
InputHandler inputHandler = getInputHandler(inputStream); List<Object> values = tuple.getValues();
Object[] objects = values.toArray(); try {
inputHandler.send(objects);
}catch (Exception e){
LOG.error("Send stream event error: ", e);
}
// collector.fail(tuple); //test replay
collector.ack(tuple); // remember ack the tuple
// Make sure that add anchor tuple if you want to track it
// collector.emit(streamid, tuple,new Values(counters, now));
} public InputHandler getInputHandler(String streamName){
InputHandler handler = null;
if(handlers.containsKey(streamName))
handler = handlers.get(streamName);
else {
handler = executionPlanRuntime.getInputHandler(streamName);
if (handler != null) {
handlers.put(streamName, handler);
}
}
return handler;
} //Need Override
public void addCallbacks( ){
//StreamCallback example
executionPlanRuntime.addCallback("outputStream", new StreamCallback() { @Override
public void receive(Event[] events) {
LOG.info("receive events: " + events.length);
for (Event e:events)
LOG.info(e);
}
}); //QueryCallback example
executionPlanRuntime.addCallback("query1", new QueryCallback() {
@Override
public void receive(long timeStamp, Event[] inEvents, Event[] removeEvents) {
printEvents(timeStamp, inEvents, removeEvents);
}
});
} public void printEvents(long timeStamp, Event[] inEvents, Event[] removeEvents){
StringBuilder sb = new StringBuilder();
sb.append("Events{ @timeStamp = ").append(timeStamp).append(", inEvents = ").append(
Arrays.deepToString(inEvents)).append(", RemoveEvents = ").append(Arrays.deepToString(removeEvents)).append(" }");
LOG.info(sb.toString());
} public void cleanup() {
//Shutting down the runtime
executionPlanRuntime.shutdown(); //Shutting down Siddhi
siddhiManager.shutdown();
}
}
Reference
1. Siddhi paper, https://people.apache.org/~hemapani/research/papers/siddi-gce2011.pdf
2. Siddhi doc, https://docs.wso2.com/display/CEP400/SiddhiQL+Guide+3.0
让Storm插上CEP的翅膀 - Siddhi调研和集成的更多相关文章
- 时序数据库(TSDB)-为万物互联插上一双翅膀
本文由 网易云发布. 时序数据库(TSDB)是一种特定类型的数据库,主要用来存储时序数据.随着5G技术的不断成熟,物联网技术将会使得万物互联.物联网时代之前只有手机.电脑可以联网,以后所有设备都会联 ...
- 插上腾飞的翅膀:为asp.net core添加protobuf支持
没时间解释了,快上车. 通过NuGet获取Zaabee.AspNetCoreProtobuf Install-Package Zaabee.AspNetCoreProtobuf 在Startup.cs ...
- 给PLSQL插上飞翔的翅膀-PLSQL优化
60-80% of database performance issues are related to poorly performing SQL,60-80%的数据库性能问题要归结于生产中糟糕的S ...
- 让MEF插上AOP的翅膀
什么是MEF Git:https://github.com/MicrosoftArchive/mef MEF也是一款ioc框架,貌似历史比较悠久了. 这里有一篇.net阵容里面主流ioc比较. htt ...
- 为Spring Cloud Config插上管理的翅膀
最近一致在更新Spring Cloud Config的相关内容,主要也是为这篇埋个伏笔,相信不少调研过Spring Cloud Config的用户都会吐槽它的管理能力太弱.因此,就有了下面为讲推荐的这 ...
- 插上翅膀,让Excel飞起来——xlwings(二)
在上一篇插上翅膀,让Excel飞起来——xlwings(一)中提到利用xlwings模块,用python操作Excel有如下的优点: xlwings能够非常方便的读写Excel文件中的数据,并且能够进 ...
- Spring Boot (六): 为 JPA 插上翅膀的 QueryDSL
在前面的文章中,我们介绍了 JPA 的基础使用方式,<Spring Boot (三): ORM 框架 JPA 与连接池 Hikari>,本篇文章,我们由入门至进阶的介绍一下为 JPA 插上 ...
- XCode4.5.6,iOS6.1下测试 判断当前设备,及其联网状态等; 关于设备插上后XCode检测不出的情况的说明
目录[-] 一.判断设备 二.判断网络连接状态 三.设备不显示的解决办法 一.判断设备 01 //设备名称 02 return [UIDevice currentDevice].name; 03 ...
- QT使用WOL实现远程一键开机(局域网,需要目标电脑的主板支持,并且插上网线,用udpSocket.writeDatagram一句话就可以)
功能:让关机的电脑一键开机,需要目标电脑的主板支持,并且插上网线: 效果:相当于手动按了一下目标电脑的开关机按钮. 没啥技术含量,简单开说... 1.获取目标机MAC地址 QByteArray sMa ...
随机推荐
- 浅析十三种常用的数据挖掘的技术&五个免费开源的数据挖掘软件
一.前 沿 数据挖掘就是从大量的.不完全的.有噪声的.模糊的.随机的数据中,提取隐含在其中的.人们事先不知道的但又是潜在有用的信息和知识的过程.数据挖掘的任务是从数据集中发现模式,可以发现的模式有很多 ...
- wamp下php无法保存SESSION问题总汇
由于是在windows 下的iis进行php的环境,所以很多情况下不能像lamp那么简单进行设置.由于工作原因我也遇到很多session无法保存的情况(在wamp下).以下是相信信息的汇总,仅供参考学 ...
- CC2540开发板学习笔记(七)—— 睡眠唤醒
(一)中断唤醒 一.实验内容 通过中断唤醒在睡眠模式下的CC2540 二.实验原理 1.系统电源管理(工作方式) (1)全功能模式: 高频晶振(16M或者32M)和低频晶振(32.768K RCOSC ...
- C++primer学习笔记(三)——Chapter 5
5.1 Simple Statements 1.记得每个语句后面加上”;”不过现在编译器都有实时编译,一般都不会忘记的, 2.空语句 (1)就是啥都没有.只有一个“:” (2)还是有很多用处的,例 ...
- cmd.ExecuteNonQuery();和cmd.ExecuteScalar();
C#...cmd.ExecuteNonQuery();是返回执行命令后影响的参数 返回符合你条件的所有语句,如果你要数据库里某张表的数据,说执行这个命令后他返回的是就是这张表的全部数据cmd.Exec ...
- WPF/Silverlight HierarchicalDataTemplate 模版的使用(转)
上一篇 对Wpf/Silverlight Template 进行了总结,本篇继续上一篇,主要是介绍 HierarchicalDataTemplate 的使用方法.HierarchicalDataTem ...
- 简单几何(线段相交) POJ 2826 An Easy Problem?!
题目传送门 题意:两条线段看成两块木板,雨水从上方往下垂直落下,问能接受到的水的体积 分析:恶心的分类讨论题,考虑各种情况,尤其是入口被堵住的情况,我的方法是先判断最高的两个点是否在交点的同一侧,然后 ...
- 拓扑排序 POJ 1049 Sorting It All Out
题目传送门 /* 拓扑排序裸题:有三种情况: 1. 输入时发现与之前的矛盾,Inconsistency 2. 拓扑排序后,没有n个点(先判断cnt,即使一些点没有边连通,也应该是n,此时错误是有环): ...
- LogHelper拾遗
1.被简化之前 对已LogHelper,形如: public static void WriteError(string className,string methodName,string mess ...
- WPF之TextBox
1. TextBox实现文字垂直居中 TextBox纵向长度比较长但文字字体比较小的时候,在输入时就会发现文字不是垂直居中的. 而使用中我们发现,TextBox虽然可以设置文字的水平对齐方式,但却没有 ...