简介

同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. 关于web系统整体优化提速总结

    关于web系统整体优化提速总结 一.背景 随着公司业务的拓展,随之而来就是各种系统横向和纵向的增加,PV.UV也都随之增加,原有的系统架构和模式慢慢遇上了瓶颈,需要逐步的对系统从整体上进行改造升级,通 ...

  2. 《菜鸟也要学会C》-和大家聊一聊

    简介 为什么要出本系列作品? 怎么学好C? 学完这套课程后,我的编程会怎么样? 1.1为什么要出本系列作品? 随着大部分人喜欢编程,大部分人都有一个毛病,就是想要急切的学完编程.其实这种思想是错误的, ...

  3. MySQL解决存入数据库和取出数据库时间格式问题

    我们在往数据库里存数据时,时间格式正是我们想要的,然而取数据时去出现了这种情况 这明显不是我们想要的! 解决办法: 在我们配置mysql时添加一行代码: timezone:"08:00&qu ...

  4. C语言之父Dennis Ritchie告诉你:如何成为世界上最好的程序员?

    文/Ohans Emmanuel 译/网易云信 想要阅读更多技术干货文章,欢迎关注网易云信博客. 了解网易云信,来自网易核心架构的通信与视频云服务. 我不知道如何成为世界上最好的程序员.但是,我们可以 ...

  5. 委托在Smobiler自定义控件中运用

    委托(Delegate) C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托(Delegate) 是存有对某个方法的引用的一种引用类型变量.可以将方法当作另一个方法的参数来进 ...

  6. css 全局样式表

    /*==全局样式==*/   *{padding:0;margin:0;}   div,dl,dt,dd,form,h1,h2,h3,h4,h5,h6,img,ol,ul,li,table,th,td ...

  7. CentOS java生成文件并赋予权限的问题

    2.检查文件是否允许: file.canExecute(); – return true, file is executable; false is not. file.canWrite(); – r ...

  8. SQL Server Update 链接修改和when的应用

    一.自链接方式 update b1 set b1.money = b1.money + b2.money from (select * from wallet where type='余额') b1 ...

  9. 使jira支持reopen率的统计

    jira本身并不能统计bug的reopen率,虽然bug工作流程中有reopen节点,只能借助第三方插件来处理. 插件名称:Enhancer Plugin for JIRA,此插件支持自定义字段.自定 ...

  10. [原创]自动化部署K8S(v1.10.11)集群

          标准运维实现自动化部署K8S集群主要分两步,第一步是部署gse-agent,拱第二步执行部署. 第一步:部署gse-agent.如下: 第二步:部署k8s集群.主要通过作业平台分为5小步执 ...