热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

闲鱼如何打造高效CEP系统及DSL编程语言

该怎么拯

背景

复杂事件处理(Complex Event Processing,以下简称CEP)是一种分析事件流的技术,事件可以是事物有意义的状态变化也可以是事物之间的动作。主要用于分析事件之间的关联关系,且这种关联关系在时间上是多种多样的。

在闲鱼内部,需要处理复杂事件的场景逐渐增多。比如:
1. 安全治理领域:
用户N分钟内发送图片或文字消息给M个人,标记该用户。
卖家发布商品,买家快速拍下商品。 M小时内,同一买家超过K次。标记该买家。
2. 营销领域:
12小时内,买家查看商品详情,卖家降价商品。给买家发送降价push。
这些需求常常多变的,而且需要快速上线验证,如何提升开发效率同时满足事件计算的及时性、可靠性、稳定性成为摆在闲鱼面前的一大问题。

CEP系统的构建思路

CEP技术是一项历史比较久的技术,早年就被应用于很多计算机领域-比如应用于无线射频识别(Radio Frequency Identification,RFID)领域的的事件监控预警。
对闲鱼来应用场景来说,总结核心诉求如下:

1. 需要满足常见的计算需求:需要考虑事件序列、窗口聚合、事件过滤、模式匹配计算场景。

2. 开发效率:需求常常是多变的,要求可以低成本开发快速上线。

3. 性能:闲鱼存在海量的用户行为数据以及各种预定义事件,要求千万级/秒的事件处理吞吐量,秒级延迟。

4. 容错性:数据不可丢,计算不可以出错,出现错误后系统可自动恢复。

5. 云端联动:有一些简单计算场景可以直接在端上实现掉,提升响应性能。只有复杂场景才需要在服务端计算实现。

6. 能够解决大部分计算场景就可以了,不需要为了一些非常少见的场景去设计特别复杂的机制。

主流开源CEP技术框架

目前主流的CEP技术花样繁多,各成体系,我们调研了业内主流开源技术方案做了一些比较:

闲鱼CEP系统的思路

调研众多技术方案和参考相关论文后,闲鱼决定采用如下的方式构建CEP系统:

1. 标准化事件的输入与输出,这样可以大幅度降低系统的复杂性。输出事件写入消息服务中供使用方订阅。

2. 为了简化开发工作,同时统一云和端的匹配规则表达,参考业内论文,我们决定自定义一种简单的DSL语言来描述规则。该语言应该类似SQL,由有限的关键字组成,让普通开发者一看就懂,同时有足够的表达能力覆盖大部分闲鱼CEP计算场景。

3. 关于计算引擎的选择:考虑到系统需要处理海量的用户行为数据,对性能、实时性、容错性的严苛要求以及人员技术熟悉情况。选择阿里内部较为成熟Blink(开源版本叫Flink)实时计算框架作为底层计算引擎。

设计实现

输入输出

整个系统本质上是一个数据处理系统,自然首先需要定义的事情就是:输入与输出。

我们抽象了闲鱼的常见的用户行为和动作,作为基本事件,并把这些基本事件标准化。这些基本事件可以看作是我们CEP计算的输入,由基本事件匹配生成的结果可以看作是输出事件。
1. 事件标准化输入:

  1. 输入样例:

  2. event_code: S_SEND_MSG

  3. event_time: 2019-09-24 10:15:23.474

  4. extra_info: {"to_user":"ccc","ARG3":"0",

  5. "SDKTYPE":"mini","UTPVID_T":"156*****104","ARG1":"xchat",

  6. "chat_session_type":"1","APPKEY":"***","EVENTID":"***",

  7. "PAGE":"UT","_priority":"4","chat_session_id":"*****",

  8. "content_type":"1",

  9. "text":"******"}

  10. user_id: abc

2. 事件的标准化输出:
默认输出到消息服务中。
消息体是由输出字段组成的json kv结构

  1. 输入样例:

  2. {"user_id":"abc","event_time":"2019-09-24 10:15:23"}

运行架构

我们定义了一种简单的DSL语言来表达事件处理规则,有了DSL,用户可以像使用普通的数据库一样编写DSL,然后提交给系统自动运行该DSL语言,运行该DSL的系统持续的监听输入数据做实时匹配,并将结果作为输出事件输出。
Interactive Service:系统对外提交的交互服务。
Strean Source:标准化的事件来源,使用阿里云sls存储。
EPL Parser:负责DSL的语法扫描与代码翻译,将用户编写的DSL解析生成Blink CEP Pattern代码或者Blink SQL。
Job Manager:主要负责将生成的EPL Parser生成的代码或SQL部署到Blink的任务中,包括生成任务与执行计划、提交任务、停止任务、启动任务等等。
Sink输入:事件命中计算规则后生成json格式的输出事件,存储到消息服务MetaQ中。

闲鱼DSL语言

我们设计DSL语言的第一个原则就是尽量和SQL语法类似,第二原则是要足够的简单明了。结合闲鱼的使用场景,我们定义的主要语言要素如下:

  1. --语言定义

  2. RULENAME <规则名称> --定义规则名称

  3. <变量名:事件类型> --定义事件变量

  4. EVENT <事件模式序列> --定义事件匹配模式

  5. [WHERE] <条件表达式> --定义事件过滤条件

  6. [REPEAT] <频次表达式> [SAME] <指定REPEAT重复计数字段> [HAVING] <条件表达式> --定义频次表达

  7. [WITHIN] <时间窗口> --定义匹配事件窗口

  8. RETUEN <输出字段> --定义输出事件的字段

  9. 支持场常见内置函数:SUM、COUNT、MAX、MIN、DISTINCT

整个语言的定义比较简洁,熟悉SQL的同学非常容易理解其所要表达的含义。
其特点如下:

1. 简化了复杂事件处理的表达。

2. 标准化的事件输入与输出。

3. 语法与关键词含义类SQL。

4. 统一表达方便云端共用。

5. 只表达事件的处理、触发计算,包含基本的过滤、聚合、模式匹配。

6. 支持常见SQL聚合函数。

7. 非通用编程语言,不覆盖所有CEP场景。

编程示例:

  1. --用户,在10分钟内,发送了相同条消息,给了100不同的用户。

  2. RULENAME: "示例"

  3. e1: S_SEND_MSG

  4. EVENT e1

  5. REPEAT 100+ SAME e1.user_id HAVING DISTINCT(e1.extra_info[received_user_id]) > 100

  6. WITHIN 10 MINUTE

  7. RETURN userId=e1.user_id

DSL语言实现简介

该DSL语言在端上的实现还在开发中,本文只介绍其在云端的实现方式。
由于我们选择的计算引擎是Blink,自然该语言需要能够运行在Blink平台上。Blink底层已经支持CEP计算,其JAVA API说明可参考:https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/libs/cep.html
在Blink内部是通过NFA(Non-determined Finite Automaton 不确定有限状态机)来实现CEP技术的,其主要理论依据参考的是论文Efficient Pattern Matching over Event Streams中介绍的模型,有兴趣的同学可以参考。

我们知道标准的SQL是可以直接运行在Blink上面的,Blink没有自己构建一个SQL优化解析器,而是很聪明的选择了Apache Calcite来实现SQL校验、SQL解析、抽象语法树的构建以及SQL优化(底层语法分析实际是通过Javacc实现)。Calcite是一个非常流行的开源SQL实现框架,在很多开源项目中都有应用。这样Calcite在Blink SQL架构中处于核心地位。
闲鱼的DSL相当于扩展了Blink的SQL,通过自定义解析器做DSL的解析、校验同时生成抽象语法树,然后根据语法树生成Blink CEP代码。特别地对于一种简单场景:只有对一种类型的事件做过滤、聚合计算的情况;我们将其直接翻译成Blink SQL,因为Blink SQL底层是Stream API比Blink CEP基于NFA的状态机性能要好。
整体架构如下图所示:

实现流程:

1. 利用calcite定制解析器解析DSL语言,生成类SQL语法树。

2. 语法正确性校验。

3. 通过语法正确性校验生成抽象语法树。

4. 判断如果只有一种类型的事件,通过代码替换模板直接翻译成Blink SQL 转7,否则转5。

5. 翻译成CEP Pattern API代码。

6. 添加标准的输入、输出Stream,构建完整的运行拓扑图。

7. 设定任务运行参数。

8. 通过Blink API提交Blink运行。

应用效果

目前该系统已经上线第一个版本,承接了闲鱼的安全策略检查、实时触达用户以及玩法场景下的规则实时匹配。生成的匹配结果通过写入MetaQ供使用方消费。

效率提升:初步验证实现同样的规则匹配功能,同编写JAVA代码相比使用改DSL语言可以大幅提升开发效率,从接受需求到编写DSL上线验证一般30分钟左右即可完成。
性能:DSL生成的计算任务处理10w左右QPS数据,消耗3个cu,平均延迟1s。
高可靠性:依赖于Blink的高可靠特性,任务的运行自然拥有快速的错误恢复机制以及数据乱序处理能力。
测试运行效果如下图所示:

闲鱼的CEP计算还在不断完善中,同时我们在和Blink团队合作共建该DSL语言,成为Blink应用生态的一部分。计划成熟后将逐步应用于阿里内部其他BU。

闲鱼团队是Flutter+Dart FaaS前后端一体化新技术的行业领军者,就是现在!客户端/服务端java/架构/前端/质量工程师面向社会招聘,base杭州阿里巴巴西溪园区,一起做有创想空间的社区产品、做深度顶级的开源项目,一起拓展技术边界成就极致!


*投喂简历给小闲鱼→guicai.gxy@alibaba-inc.com


更多系列文章、开源项目、关键洞察、深度解读

请认准闲鱼技术




推荐阅读
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
author-avatar
邱文馨4966
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有