简介

同Hive Hook一样,Presto也支持自定义实现Event Listener,用于侦听Presto引擎执行查询时发生的事件,并作出相应的处理。我们可以利用该功能实现诸如自定义日志记录、调试和性能分析插件,帮助我们更好的运维Presto集群。但是不同于Hive Hook的是,在Presto集群中,一次只能有一个Event Listener处于活动状态。

Event Listener作为Plugin监听以下事件:

  • Query Creation(查询建立相关信息)
  • Query completion (success or failure)(查询执行相关信息,包含成功查询的细节信息,失败查询的错误码等信息)
  • Split completion (success or failure)(split执行信息,同理包含成功和失败的细节信息)

了解Hook及Listener模式的朋友对于其步骤应该很清楚了,我们只需要:

  1. 实现Presto Event Listener和EventListenerFactory接口。
  2. 正确的打包我们的jar。
  3. 部署,放到Presto指定目录,修改配置文件。

接口

  1. 实现EventListener,该类是我们的核心逻辑所在,供包含上面所说的三个事件:
public interface EventListener
{
//query创建的详细信息
default void queryCreated(QueryCreatedEvent queryCreatedEvent)
{
}
//query执行的详细信息
default void queryCompleted(QueryCompletedEvent queryCompletedEvent)
{
}
//split执行的详细信息
default void splitCompleted(SplitCompletedEvent splitCompletedEvent)
{
}
}
  1. 实现EventListenerFactory创建我们自己实现的EventListener
  2. 实现Plugin接口,实现getEventListenerFactories()方法,获取我们自己实现的EventListenerFactory
  3. 添加配置信息,为etc/event-listener.properties。其中event-listener.name为必备属性,其他属性为我们plugin所需要的信息。

示例

由于集群运维的需要,先需要将用户的查询历史、查询花费的时间等信息进行统计,以便于后续对各个业务的查询进行优先级分级和评分,方便后续Presto集群稳定性易用性的维护。这里给出一个简单的将这些信息存储到Mysql数据库的样例。

Maven Pom

<dependency>
<groupId>com.facebook.presto</groupId>
<artifactId>presto-spi</artifactId>
<version>0.220</version>
<scope>compile</scope>
</dependency>

QueryEventListenerFactory

public class QueryEventListenerFactory implements EventListenerFactory {

@Override

public String getName() {

return "query-event-listener";

} @Override

public EventListener create(Map<String, String> config) {

if (!config.containsKey("jdbc.uri")) {

throw new RuntimeException("/etc/event-listener.properties file missing jdbc.uri");

}

if (!config.containsKey("jdbc.user")) {

throw new RuntimeException("/etc/event-listener.properties file missing jdbc.user");

}

if (!config.containsKey("jdbc.pwd")) {

throw new RuntimeException("/etc/event-listener.properties file missing jdbc.pwd");

}
return new QueryEventListener(config);

}

}

QueryEventPlugin

public class QueryEventPlugin implements Plugin {

@Override

public Iterable<EventListenerFactory> getEventListenerFactories() {

EventListenerFactory listenerFactory = new QueryEventListenerFactory();

return Arrays.asList(listenerFactory);

}

}

QueryEventListener

public class QueryEventListener implements EventListener {

private Map<String, String> config;

private Connection connection; public QueryEventListener(Map<String, String> config) {

this.config = new HashMap<>();

this.config.putAll(config);

init();

} private void init() {

try {

if (connection == null || !connection.isValid(10)) {

Class.forName("com.mysql.jdbc.Driver");

connection = DriverManager

.getConnection(config.get("jdbc.uri"), config.get("jdbc.user"), config.get("jdbc.pwd"));

}

} catch (SQLException | ClassNotFoundException e) {

e.printStackTrace();

}

} @Override

public void queryCreated(QueryCreatedEvent queryCreatedEvent) {

} @Override

public void queryCompleted(QueryCompletedEvent queryCompletedEvent) {

String queryId = queryCompletedEvent.getMetadata().getQueryId();

String querySql = queryCompletedEvent.getMetadata().getQuery();

String queryState = queryCompletedEvent.getMetadata().getQueryState();

String queryUser = queryCompletedEvent.getContext().getUser();

long createTime = queryCompletedEvent.getCreateTime().toEpochMilli();

long endTime = queryCompletedEvent.getEndTime().toEpochMilli();

long startTime = queryCompletedEvent.getExecutionStartTime().toEpochMilli();

//insert into query execution table
long analysisTime = queryCompletedEvent.getStatistics().getAnalysisTime().orElse(Duration.ZERO)
.toMillis();
long cpuTime = queryCompletedEvent.getStatistics().getCpuTime().toMillis();
long queuedTime = queryCompletedEvent.getStatistics().getQueuedTime().toMillis();
long wallTime = queryCompletedEvent.getStatistics().getWallTime().toMillis();
int completedSplits = queryCompletedEvent.getStatistics().getCompletedSplits();
double cumulativeMemory = queryCompletedEvent.getStatistics().getCumulativeMemory();
long outputBytes = queryCompletedEvent.getStatistics().getOutputBytes();
long outputRows = queryCompletedEvent.getStatistics().getOutputRows();
long totalBytes = queryCompletedEvent.getStatistics().getTotalBytes();
long totalRows = queryCompletedEvent.getStatistics().getTotalRows();
long writtenBytes = queryCompletedEvent.getStatistics().getWrittenBytes();
long writtenRows = queryCompletedEvent.getStatistics().getWrittenRows();
//insert into query info table queryCompletedEvent.getFailureInfo().ifPresent(queryFailureInfo -&gt; {
int code = queryFailureInfo.getErrorCode().getCode();
String name = queryFailureInfo.getErrorCode().getName();
String failureType = queryFailureInfo.getFailureType().orElse("").toUpperCase();
String failureHost = queryFailureInfo.getFailureHost().orElse("").toUpperCase();
String failureMessage = queryFailureInfo.getFailureMessage().orElse("").toUpperCase();
String failureTask = queryFailureInfo.getFailureTask().orElse("").toUpperCase();
String failuresJson = queryFailureInfo.getFailuresJson();
// insert into failed query table
});

}

@Override

public void splitCompleted(SplitCompletedEvent splitCompletedEvent) {

long createTime = splitCompletedEvent.getCreateTime().toEpochMilli();

long endTime = splitCompletedEvent.getEndTime().orElse(Instant.MIN).toEpochMilli();

String payload = splitCompletedEvent.getPayload();

String queryId = splitCompletedEvent.getQueryId();

String stageId = splitCompletedEvent.getStageId();

long startTime = splitCompletedEvent.getStartTime().orElse(Instant.MIN).toEpochMilli();

String taskId = splitCompletedEvent.getTaskId();

long completedDataSizeBytes = splitCompletedEvent.getStatistics().getCompletedDataSizeBytes();

long completedPositions = splitCompletedEvent.getStatistics().getCompletedPositions();

long completedReadTime = splitCompletedEvent.getStatistics().getCompletedReadTime().toMillis();

long cpuTime = splitCompletedEvent.getStatistics().getCpuTime().toMillis();

long queuedTime = splitCompletedEvent.getStatistics().getQueuedTime().toMillis();

long wallTime = splitCompletedEvent.getStatistics().getWallTime().toMillis();

//insert into stage info table

}

}

打包

  1. Presto使用服务提供者接口(SPI)来扩展Presto。Presto使用SPI加载连接器功能类型系统访问控制。SPI通过元数据文件加载。我们还需要创建src/main/resources/META-INF/services/com.facebook.presto.spi.Plugin元数据文件。该文件应包含我们插件的类名如: com.ji3jin.presto.listener.QueryEventListener
  2. 执行mvn clean install打包

部署

  1. 创建配置文件etc/event-listener.properties
event-listener.name=query-event-listener

jdbc.uri=jdbc:mysql://localhost:3306/presto_monitor

jdbc.user=presto

jdbc.pwd=presto123

  1. 在presto根目录下创建query-event-listener目录,名称与我们上面event listener的name一致
  2. 将我们的jar包和mysql connector的jar包拷贝到上面创建的目录
  3. 重新启动Presto服务即可

好了,现在你可以执行查询,然后就可以在Mysql中看到你的查询历史和相关时间的统计信息了。如果你目前的工作对此也有需要,还等什么,快动手实现一个吧。

欢迎关注我的公众号:叁金大数据

Presto Event Listener开发的更多相关文章

  1. 引用fastclick.js或使用触屏监听 滑动屏幕报错:解决[Intervention] Unable to preventDefault inside passive event listener

    使用fastClick.js所产生的一些问题 开发h5活动页时想到移动端会有300ms的延迟,于是便打算用fastClick.js解决. 页面引入fastClick.js后,滑动H5页面的时候发现谷歌 ...

  2. Android事件监听器Event Listener

    在 Android 中,我们可以通过事件处理使UI与用户互动(UI Events). UI的用户事件处理,即View处理用户的操作,在应用程序中几乎不可避免.View是重要的类,它是与用户互动的前线: ...

  3. Unable to preventDefault inside passive event listener due to target being treated as passive

    Unable to preventDefault inside passive event listener due to target being treated as passive 今天在做项目 ...

  4. Unable to preventDefault inside passive event listener

    最近做项目经常在 chrome 的控制台看到如下提示: Unable to preventDefault inside passive event listener due to target bei ...

  5. 滑动时候警告:Unable to preventDefault inside passive event listener

    1 前言 在制作2048时,需要在手机端添加滑动检测事件,然后发现控制台有警告,如下: main2048.js:218 [Intervention] Unable to preventDefault ...

  6. 移动端页面滑动时候警告:Unable to preventDefault inside passive event listener due to target being treated as passive.

    移动端项目中,在滚动的时候,会报出以下提示: [Intervention] Unable to preventDefault inside passive event listener due to ...

  7. [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080

    相信如果用谷歌浏览器做移动端页面的时候 用touch事件的时候应该遇到过这个东东吧 documet.addEventListener("touchstart",function() ...

  8. [Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive.

    1.滑动时候警告[Intervention] Unable to preventDefault inside passive event listener due to target being tr ...

  9. IScroll Unable to preventDefault inside passive event listener due to target being treated as passive

    最近两天企业微信下IScroll突然无法滚动了,特别慢,之前好好的,发现主要是有红色的Unable to preventDefault inside passive event listener du ...

随机推荐

  1. python文件及路径管理函数

    glob模块 说明: 1.glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,就类似于Windows下的文件搜索, 支持通配符操作 *.?.[] 这三个通配符,*代表0 ...

  2. Spring Bean的3种装配方式

    Bean常用的装配方式有3种: 基于xml的装配 基于Annotation(注解)的装配 基于Java类的装配 基于xml的装配 在xml文件中配置Bean. 如果依赖很多,xml配置文件会很臃肿,后 ...

  3. 系统学习 Java IO (七)----字节数组流 ByteArrayInputStream/ByteArrayOutputStream

    目录:系统学习 Java IO---- 目录,概览 ByteArrayInputStream 如果数据存储在数组中,ByteArrayInputStream 可以很方便读取,它可以返回 InputSt ...

  4. HashMap原理(二) 扩容机制及存取原理

    我们在上一个章节<HashMap原理(一) 概念和底层架构>中讲解了HashMap的存储数据结构以及常用的概念及变量,包括capacity容量,threshold变量和loadFactor ...

  5. 美化Div的边框

    CSS修饰Div边框 大部分时候,Div的边框真的做的太丑了,如果不用很多样式来修饰的话,它永远都是那么的突兀.作为一个后端开发,前端菜鸡,在没有设计和前端开发自己独自做项目的时候常常会遇到Div边框 ...

  6. [Vue 牛刀小试]:第十五章 - 传统开发模式下的 axios 使用入门

    一.前言 在没有接触 React.Angular.Vue 这类 MVVM 的前端框架之前,无法抛弃 Jquery 的重要理由,除了优秀的前端 DOM 元素操作性以外,能够非常便捷的发起 http 请求 ...

  7. 使用SpringSecurity搭建授权认证服务(1) -- 基本demo认证原理

    使用SpringSecurity搭建授权认证服务(1) -- 基本demo 登录认证是做后台开发的最基本的能力,初学就知道一个interceptor或者filter拦截所有请求,然后判断参数是否合理, ...

  8. Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的

    前言 用c#开发的时候,新建的脚本都默认继承自Monobehaviour, 因此脚本才有了自己的生命周期函数,如Awake,Start, Update, OnDestroy等. 在相应的方法中实现游戏 ...

  9. nexus私服快速update index方法

    简单搭好nexus私服后,做好基本的配置. 稍微麻烦点的就是让其更新Jar索引文件.如果有耐心的话,完全可以通过在线更新索引的方式来做,但所消耗的时间较长,让人误以为出错了,不知所措. 下面介绍一种简 ...

  10. [原创]Greenplum数据库集群实践

    GreenPlum实践 ============================================== 目录: 一.安装环境准备 二.GP数据库安装 三.集群添加standby节点 四. ...