Presto Event Listener开发
简介
同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模式的朋友对于其步骤应该很清楚了,我们只需要:
- 实现Presto Event Listener和EventListenerFactory接口。
- 正确的打包我们的jar。
- 部署,放到Presto指定目录,修改配置文件。
接口
- 实现EventListener,该类是我们的核心逻辑所在,供包含上面所说的三个事件:
public interface EventListener
{
//query创建的详细信息
default void queryCreated(QueryCreatedEvent queryCreatedEvent)
{
}
//query执行的详细信息
default void queryCompleted(QueryCompletedEvent queryCompletedEvent)
{
}
//split执行的详细信息
default void splitCompleted(SplitCompletedEvent splitCompletedEvent)
{
}
}
- 实现EventListenerFactory创建我们自己实现的EventListener
- 实现Plugin接口,实现getEventListenerFactories()方法,获取我们自己实现的EventListenerFactory
- 添加配置信息,为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 -> {
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
}
}
打包
- Presto使用服务提供者接口(SPI)来扩展Presto。Presto使用SPI加载连接器,功能,类型和系统访问控制。SPI通过元数据文件加载。我们还需要创建
src/main/resources/META-INF/services/com.facebook.presto.spi.Plugin元数据文件。该文件应包含我们插件的类名如:com.ji3jin.presto.listener.QueryEventListener - 执行
mvn clean install打包
部署
- 创建配置文件etc/event-listener.properties
event-listener.name=query-event-listener
jdbc.uri=jdbc:mysql://localhost:3306/presto_monitor
jdbc.user=presto
jdbc.pwd=presto123
- 在presto根目录下创建
query-event-listener目录,名称与我们上面event listener的name一致 - 将我们的jar包和mysql connector的jar包拷贝到上面创建的目录
- 重新启动Presto服务即可
好了,现在你可以执行查询,然后就可以在Mysql中看到你的查询历史和相关时间的统计信息了。如果你目前的工作对此也有需要,还等什么,快动手实现一个吧。
欢迎关注我的公众号:叁金大数据

Presto Event Listener开发的更多相关文章
- 引用fastclick.js或使用触屏监听 滑动屏幕报错:解决[Intervention] Unable to preventDefault inside passive event listener
使用fastClick.js所产生的一些问题 开发h5活动页时想到移动端会有300ms的延迟,于是便打算用fastClick.js解决. 页面引入fastClick.js后,滑动H5页面的时候发现谷歌 ...
- Android事件监听器Event Listener
在 Android 中,我们可以通过事件处理使UI与用户互动(UI Events). UI的用户事件处理,即View处理用户的操作,在应用程序中几乎不可避免.View是重要的类,它是与用户互动的前线: ...
- 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 今天在做项目 ...
- Unable to preventDefault inside passive event listener
最近做项目经常在 chrome 的控制台看到如下提示: Unable to preventDefault inside passive event listener due to target bei ...
- 滑动时候警告:Unable to preventDefault inside passive event listener
1 前言 在制作2048时,需要在手机端添加滑动检测事件,然后发现控制台有警告,如下: main2048.js:218 [Intervention] Unable to preventDefault ...
- 移动端页面滑动时候警告:Unable to preventDefault inside passive event listener due to target being treated as passive.
移动端项目中,在滚动的时候,会报出以下提示: [Intervention] Unable to preventDefault inside passive event listener due to ...
- [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() ...
- [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 ...
- IScroll Unable to preventDefault inside passive event listener due to target being treated as passive
最近两天企业微信下IScroll突然无法滚动了,特别慢,之前好好的,发现主要是有红色的Unable to preventDefault inside passive event listener du ...
随机推荐
- 解决wireshark打开错误
错误提示如下: Lua: Error during loading: [string "/usr/share/wireshark/init.lua"]:44: dofile has ...
- Scala 学习之路(十一)—— 模式匹配
一.模式匹配 Scala支持模式匹配机制,可以代替swith语句.执行类型检查.以及支持析构表达式等. 1.1 更好的swith Scala不支持swith,可以使用模式匹配match...case语 ...
- Spark学习之路(二)—— Spark开发环境搭建
一.安装Spark 1.1 下载并解压 官方下载地址:http://spark.apache.org/downloads.html ,选择Spark版本和对应的Hadoop版本后再下载: 解压安装包: ...
- 老雷socket编程之websocket实现
老雷socket编程之websocket实现 我们主要实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket.websocket是一种可以双向通讯的 ...
- Java学习笔记——三层架构
Layer: UI层: user interface 用户接口层 Biz层: service business login layer 业务逻辑层 DAO层: Date Access Obje ...
- solr 重要的知识点
1 solr 查询参数说明 常用 ) q - 查询字符串,必须的. ) fl - 指定返回那些字段内容,用逗号或空格分隔多个. ) start - 返回第一条记录在完整找到结果中的偏移位置, 开始,一 ...
- PHP中var_dump、&&和GLOBALS的爱恨纠缠
var_dump函数:用来打印显示一个变量的内容与结构: &&:定义一个可变变量.php中,在定义变量时,需要在前面加上一个“&”符号,当加上两个“&&”符号时 ...
- .NET Core IdentityServer4实战 第六章-Consent授权页
在identityServer4中登陆页面只要是成功了,就会注册一个Cookie在服务器资源上,像现在大部分的网站第三方授权,都是经过一个页面,然后选需要的功能,IdentityServer4也给我们 ...
- 研究Electron主进程、渲染进程、webview之间的通讯
背景 由于某个Electron应用,需要主进程.渲染进程.webview之间能够互相通讯. 不过因为Electron仅提供了主进程与渲染进程的通讯,没有渲染进程之间或渲染进程与webview之间通讯的 ...
- SpringCloud解析之Ribbon
Ribbon是分布式微服务架构中负载均衡的一个解决方案,我们只需要引入ribbon依赖,然后初始化一个RestTemplate对象,在其上添加@LoadBalanced注解,就可以实现请求的负载均衡, ...