You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by li...@apache.org on 2016/03/30 15:16:47 UTC
kylin git commit: KYLIN-1550 Persist recent bad queries in scope of
projects
Repository: kylin
Updated Branches:
refs/heads/master 19ef6c374 -> cfb3c440c
KYLIN-1550 Persist recent bad queries in scope of projects
Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/cfb3c440
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/cfb3c440
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/cfb3c440
Branch: refs/heads/master
Commit: cfb3c440c0f86f6987ec6e898f58b7fe5f292b95
Parents: 19ef6c3
Author: lidongsjtu <li...@apache.org>
Authored: Wed Mar 30 21:10:22 2016 +0800
Committer: lidongsjtu <li...@apache.org>
Committed: Wed Mar 30 21:16:22 2016 +0800
----------------------------------------------------------------------
.../apache/kylin/common/KylinConfigBase.java | 8 ++
.../kylin/common/persistence/ResourceStore.java | 1 +
.../kylin/metadata/badquery/BadQueryEntry.java | 96 ++++++++++++++++
.../metadata/badquery/BadQueryHistory.java | 72 ++++++++++++
.../badquery/BadQueryHistoryManager.java | 114 +++++++++++++++++++
.../kylin/metadata/project/ProjectManager.java | 2 +
.../badquery/BadQueryHistoryManagerTest.java | 85 ++++++++++++++
.../localmeta/bad_query/default.json | 25 ++++
.../kylin/rest/service/BadQueryDetector.java | 67 +++++++++--
.../rest/service/BadQueryDetectorTest.java | 2 +-
10 files changed, 459 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
----------------------------------------------------------------------
diff --git a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
index c37f888..bdcdd1d 100644
--- a/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
+++ b/core-common/src/main/java/org/apache/kylin/common/KylinConfigBase.java
@@ -438,6 +438,14 @@ public class KylinConfigBase implements Serializable {
return Integer.parseInt(getOptional("kylin.query.badquery.stacktrace.depth", "10"));
}
+ public int getBadQueryHistoryNum() {
+ return Integer.parseInt(getOptional("kylin.query.badquery.history.num", "10"));
+ }
+
+ public int getBadQueryDefaultAlertingSeconds() {
+ return Integer.parseInt(getOptional("kylin.query.badquery.default.alerting.seconds", "90"));
+ }
+
public int getCachedDictMaxEntrySize() {
return Integer.parseInt(getOptional("kylin.dict.cache.max.entry", "3000"));
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-common/src/main/java/org/apache/kylin/common/persistence/ResourceStore.java
----------------------------------------------------------------------
diff --git a/core-common/src/main/java/org/apache/kylin/common/persistence/ResourceStore.java b/core-common/src/main/java/org/apache/kylin/common/persistence/ResourceStore.java
index b07458c..cf00c05 100644
--- a/core-common/src/main/java/org/apache/kylin/common/persistence/ResourceStore.java
+++ b/core-common/src/main/java/org/apache/kylin/common/persistence/ResourceStore.java
@@ -59,6 +59,7 @@ abstract public class ResourceStore {
public static final String KAFKA_RESOURCE_ROOT = "/kafka";
public static final String STREAMING_OUTPUT_RESOURCE_ROOT = "/streaming_output";
public static final String CUBE_STATISTICS_ROOT = "/cube_statistics";
+ public static final String BAD_QUERY_RESOURCE_ROOT = "/bad_query";
private static final ConcurrentHashMap<KylinConfig, ResourceStore> CACHE = new ConcurrentHashMap<KylinConfig, ResourceStore>();
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryEntry.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryEntry.java b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryEntry.java
new file mode 100644
index 0000000..658cc0a
--- /dev/null
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryEntry.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.metadata.badquery;
+
+import org.apache.kylin.common.persistence.RootPersistentEntity;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
+public class BadQueryEntry extends RootPersistentEntity implements Comparable<BadQueryEntry> {
+
+ @JsonProperty("adj")
+ private String adj;
+ @JsonProperty("sql")
+ private String sql;
+ @JsonProperty("start_time")
+ private long startTime;
+ @JsonProperty("server")
+ private String server;
+ @JsonProperty("thread")
+ private String thread;
+
+ public BadQueryEntry(String sql, String adj, long startTime, String server, String thread) {
+ this.updateRandomUuid();
+ this.adj = adj;
+ this.sql = sql;
+ this.startTime = startTime;
+ this.server = server;
+ this.thread = thread;
+ }
+
+ public BadQueryEntry() {
+ }
+
+ public String getAdj() {
+ return adj;
+ }
+
+ public void setAdj(String adj) {
+ this.adj = adj;
+ }
+
+ public String getSql() {
+ return sql;
+ }
+
+ public void setSql(String sql) {
+ this.sql = sql;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ public String getServer() {
+ return server;
+ }
+
+ public void setServer(String server) {
+ this.server = server;
+ }
+
+ public String getThread() {
+ return thread;
+ }
+
+ public void setThread(String thread) {
+ this.thread = thread;
+ }
+
+ @Override
+ public int compareTo(BadQueryEntry obj) {
+ return (int) (this.startTime - obj.startTime);
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistory.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistory.java b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistory.java
new file mode 100644
index 0000000..7792f0b
--- /dev/null
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistory.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.metadata.badquery;
+
+import java.util.NavigableSet;
+import java.util.TreeSet;
+
+import org.apache.kylin.common.persistence.ResourceStore;
+import org.apache.kylin.common.persistence.RootPersistentEntity;
+import org.apache.kylin.metadata.MetadataConstants;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@SuppressWarnings("serial")
+@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
+public class BadQueryHistory extends RootPersistentEntity {
+
+ @JsonProperty("project")
+ private String project;
+ @JsonProperty("entries")
+ private NavigableSet<BadQueryEntry> entries = new TreeSet<>();
+
+ public BadQueryHistory() {
+ }
+
+ public BadQueryHistory(String project) {
+ this.updateRandomUuid();
+ this.project = project;
+ }
+
+ public NavigableSet<BadQueryEntry> getEntries() {
+ return entries;
+ }
+
+ public void setEntries(NavigableSet<BadQueryEntry> entries) {
+ this.entries = entries;
+ }
+
+ public String getProject() {
+ return project;
+ }
+
+ public void setProject(String project) {
+ this.project = project;
+ }
+
+ public String getResourcePath() {
+ return ResourceStore.BAD_QUERY_RESOURCE_ROOT + "/" + project + MetadataConstants.FILE_SURFIX;
+ }
+
+ @Override
+ public String toString() {
+ return "BadQueryHistory [ project=" + project + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManager.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManager.java
new file mode 100644
index 0000000..3165c13
--- /dev/null
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManager.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.metadata.badquery;
+
+import java.io.IOException;
+import java.util.NavigableSet;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.persistence.JsonSerializer;
+import org.apache.kylin.common.persistence.ResourceStore;
+import org.apache.kylin.common.persistence.Serializer;
+import org.apache.kylin.metadata.MetadataConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BadQueryHistoryManager {
+ public static final Serializer<BadQueryHistory> BAD_QUERY_INSTANCE_SERIALIZER = new JsonSerializer<>(BadQueryHistory.class);
+ private static final Logger logger = LoggerFactory.getLogger(BadQueryHistoryManager.class);
+
+ private static final ConcurrentHashMap<KylinConfig, BadQueryHistoryManager> CACHE = new ConcurrentHashMap<>();
+ private KylinConfig kylinConfig;
+
+ private BadQueryHistoryManager(KylinConfig config) throws IOException {
+ logger.info("Initializing BadQueryHistoryManager with config " + config);
+ this.kylinConfig = config;
+ }
+
+ public static BadQueryHistoryManager getInstance(KylinConfig config) {
+ BadQueryHistoryManager r = CACHE.get(config);
+ if (r != null) {
+ return r;
+ }
+
+ synchronized (BadQueryHistoryManager.class) {
+ r = CACHE.get(config);
+ if (r != null) {
+ return r;
+ }
+ try {
+ r = new BadQueryHistoryManager(config);
+ CACHE.put(config, r);
+ if (CACHE.size() > 1) {
+ logger.warn("More than one singleton exist");
+ }
+ return r;
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to init BadQueryHistoryManager from " + config, e);
+ }
+ }
+ }
+
+ public static void clearCache() {
+ CACHE.clear();
+ }
+
+ private ResourceStore getStore() {
+ return ResourceStore.getStore(this.kylinConfig);
+ }
+
+ public BadQueryHistory getBadQueriesForProject(String project) throws IOException {
+ BadQueryHistory badQueryHistory = getStore().getResource(getResourcePathForProject(project), BadQueryHistory.class, BAD_QUERY_INSTANCE_SERIALIZER);
+ if (badQueryHistory == null) {
+ badQueryHistory = new BadQueryHistory(project);
+ }
+
+ logger.debug("Loaded " + badQueryHistory.getEntries().size() + " Bad Query(s)");
+ return badQueryHistory;
+ }
+
+ public BadQueryHistory addEntryToProject(BadQueryEntry badQueryEntry, String project) throws IOException {
+ if (StringUtils.isEmpty(project) || badQueryEntry.getAdj() == null || badQueryEntry.getSql() == null)
+ throw new IllegalArgumentException();
+
+ BadQueryHistory badQueryHistory = getBadQueriesForProject(project);
+ NavigableSet<BadQueryEntry> entries = badQueryHistory.getEntries();
+ if (entries.size() >= kylinConfig.getBadQueryHistoryNum()) {
+ entries.pollFirst();
+ }
+ entries.add(badQueryEntry);
+
+ getStore().putResource(badQueryHistory.getResourcePath(), badQueryHistory, BAD_QUERY_INSTANCE_SERIALIZER);
+ return badQueryHistory;
+ }
+
+ public BadQueryHistory addEntryToProject(String sql, String adj, long startTime, String server, String threadName, String project) throws IOException {
+ return addEntryToProject(new BadQueryEntry(sql, adj, startTime, server, threadName), project);
+ }
+
+ public void removeBadQueryHistory(String project) throws IOException {
+ getStore().deleteResource(getResourcePathForProject(project));
+ }
+
+ public String getResourcePathForProject(String project) {
+ return ResourceStore.BAD_QUERY_RESOURCE_ROOT + "/" + project + MetadataConstants.FILE_SURFIX;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
index c8d0793..65b3719 100644
--- a/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
+++ b/core-metadata/src/main/java/org/apache/kylin/metadata/project/ProjectManager.java
@@ -31,6 +31,7 @@ import org.apache.kylin.common.persistence.Serializer;
import org.apache.kylin.common.restclient.Broadcaster;
import org.apache.kylin.common.restclient.CaseInsensitiveStringCache;
import org.apache.kylin.metadata.MetadataManager;
+import org.apache.kylin.metadata.badquery.BadQueryHistoryManager;
import org.apache.kylin.metadata.model.ColumnDesc;
import org.apache.kylin.metadata.model.ExternalFilterDesc;
import org.apache.kylin.metadata.model.MeasureDesc;
@@ -168,6 +169,7 @@ public class ProjectManager {
logger.info("Dropping project '" + projectInstance.getName() + "'");
removeProject(projectInstance);
+ BadQueryHistoryManager.getInstance(config).removeBadQueryHistory(projectName);
return projectInstance;
}
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/core-metadata/src/test/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManagerTest.java
----------------------------------------------------------------------
diff --git a/core-metadata/src/test/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManagerTest.java b/core-metadata/src/test/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManagerTest.java
new file mode 100644
index 0000000..28b1805
--- /dev/null
+++ b/core-metadata/src/test/java/org/apache/kylin/metadata/badquery/BadQueryHistoryManagerTest.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.kylin.metadata.badquery;
+
+import java.io.IOException;
+import java.util.NavigableSet;
+
+import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.common.util.JsonUtil;
+import org.apache.kylin.common.util.LocalFileMetadataTestCase;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class BadQueryHistoryManagerTest extends LocalFileMetadataTestCase {
+ @Before
+ public void setUp() throws Exception {
+ this.createTestMetadata();
+ }
+
+ @After
+ public void after() throws Exception {
+ this.cleanupTestMetadata();
+ }
+
+ @Test
+ public void testBasics() throws Exception {
+ BadQueryHistory history = BadQueryHistoryManager.getInstance(getTestConfig()).getBadQueriesForProject("default");
+ System.out.println(JsonUtil.writeValueAsIndentString(history));
+
+ NavigableSet<BadQueryEntry> entries = history.getEntries();
+ assertEquals(2, entries.size());
+
+ BadQueryEntry entry1 = entries.first();
+ assertEquals("Slow", entry1.getAdj());
+ assertEquals("sandbox.hortonworks.com", entry1.getServer());
+ assertEquals("select count(*) from test_kylin_fact", entry1.getSql());
+
+ entries.pollFirst();
+ BadQueryEntry entry2 = entries.first();
+ assertTrue(entry2.getStartTime() > entry1.getStartTime());
+ }
+
+ @Test
+ public void testAddEntryToProject() throws IOException {
+ KylinConfig kylinConfig = getTestConfig();
+ BadQueryHistoryManager manager = BadQueryHistoryManager.getInstance(kylinConfig);
+ BadQueryHistory history = manager.addEntryToProject("sql", "adj", 123, "server", "t-0", "default");
+
+ NavigableSet<BadQueryEntry> entries = history.getEntries();
+ assertEquals(3, entries.size());
+
+ BadQueryEntry newEntry = entries.last();
+ assertEquals("sql", newEntry.getSql());
+ assertEquals("adj", newEntry.getAdj());
+ assertEquals(123, newEntry.getStartTime());
+ assertEquals("server", newEntry.getServer());
+ assertEquals("t-0", newEntry.getThread());
+
+ for (int i = 0; i < kylinConfig.getBadQueryHistoryNum(); i++) {
+ history = manager.addEntryToProject("sql", "adj", 123 + i + 1, "server", "t-0", "default");
+ }
+
+ assertEquals(kylinConfig.getBadQueryHistoryNum(), history.getEntries().size());
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/examples/test_case_data/localmeta/bad_query/default.json
----------------------------------------------------------------------
diff --git a/examples/test_case_data/localmeta/bad_query/default.json b/examples/test_case_data/localmeta/bad_query/default.json
new file mode 100644
index 0000000..c7f26e1
--- /dev/null
+++ b/examples/test_case_data/localmeta/bad_query/default.json
@@ -0,0 +1,25 @@
+{
+ "uuid": "ba0c9cad-35c1-4f4b-8c10-669248842c2f",
+ "project": "default",
+ "entries": [
+ {
+ "uuid": "ca0c9cad-35c1-4f4b-8c10-669248842c2f",
+ "adj": "Slow",
+ "sql": "select count(*) from test_kylin_fact",
+ "server": "sandbox.hortonworks.com",
+ "thread": "t-0",
+ "last_modified": 0,
+ "start_time": 1459362236585
+ },
+ {
+ "uuid": "da0c9cad-35c1-4f4b-8c10-669248842c2f",
+ "adj": "Slow",
+ "sql": "select * from test_kylin_fact limit 1",
+ "server": "sandbox.hortonworks.com",
+ "thread": "t-0",
+ "last_modified": 0,
+ "start_time": 1459362239990
+ }
+ ],
+ "last_modified": 1459362294902
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/server/src/main/java/org/apache/kylin/rest/service/BadQueryDetector.java
----------------------------------------------------------------------
diff --git a/server/src/main/java/org/apache/kylin/rest/service/BadQueryDetector.java b/server/src/main/java/org/apache/kylin/rest/service/BadQueryDetector.java
index 71ab26b..4e313ba 100644
--- a/server/src/main/java/org/apache/kylin/rest/service/BadQueryDetector.java
+++ b/server/src/main/java/org/apache/kylin/rest/service/BadQueryDetector.java
@@ -18,11 +18,15 @@
package org.apache.kylin.rest.service;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ConcurrentMap;
import org.apache.kylin.common.KylinConfig;
+import org.apache.kylin.metadata.badquery.BadQueryHistoryManager;
import org.apache.kylin.rest.request.SQLRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,11 +41,19 @@ public class BadQueryDetector extends Thread {
private final long detectionInterval;
private final int alertMB;
private final int alertRunningSec;
+ private KylinConfig kylinConfig;
private ArrayList<Notifier> notifiers = new ArrayList<Notifier>();
public BadQueryDetector() {
- this(60 * 1000, 100, 90); // 1 minute, 100 MB, 90 seconds
+ super("BadQueryDetector");
+ this.setDaemon(true);
+ this.kylinConfig = KylinConfig.getInstanceFromEnv();
+ this.detectionInterval = 60 * 1000;
+ this.alertMB = 100;
+ this.alertRunningSec = kylinConfig.getBadQueryDefaultAlertingSeconds();
+
+ initNotifiers();
}
public BadQueryDetector(long detectionInterval, int alertMB, int alertRunningSec) {
@@ -50,23 +62,24 @@ public class BadQueryDetector extends Thread {
this.detectionInterval = detectionInterval;
this.alertMB = alertMB;
this.alertRunningSec = alertRunningSec;
+ this.kylinConfig = KylinConfig.getInstanceFromEnv();
- this.notifiers.add(new Notifier() {
- @Override
- public void badQueryFound(String adj, int runningSec, String sql, Thread t) {
- logger.info(adj + " query has been running " + runningSec + " seconds (thread id 0x" + Long.toHexString(t.getId()) + ") -- " + sql);
- }
- });
+ initNotifiers();
+ }
+
+ private void initNotifiers() {
+ this.notifiers.add(new LoggerNotifier());
+ this.notifiers.add(new PersistenceNotifier());
}
public void registerNotifier(Notifier notifier) {
notifiers.add(notifier);
}
- private void notify(String adj, int runningSec, String sql, Thread t) {
+ private void notify(String adj, int runningSec, long startTime, String project, String sql, Thread t) {
for (Notifier notifier : notifiers) {
try {
- notifier.badQueryFound(adj, runningSec, sql, t);
+ notifier.badQueryFound(adj, runningSec, startTime, project, sql, t);
} catch (Exception e) {
logger.error("", e);
}
@@ -74,7 +87,37 @@ public class BadQueryDetector extends Thread {
}
public interface Notifier {
- void badQueryFound(String adj, int runningSec, String sql, Thread t);
+ void badQueryFound(String adj, int runningSec, long startTime, String project, String sql, Thread t);
+ }
+
+ private class LoggerNotifier implements Notifier {
+ @Override
+ public void badQueryFound(String adj, int runningSec, long startTime, String project, String sql, Thread t) {
+ logger.info(adj + " query has been running " + runningSec + " seconds (project:" + project + ", thread: 0x" + Long.toHexString(t.getId()) + ") -- " + sql);
+ }
+ }
+
+ private class PersistenceNotifier implements Notifier {
+ BadQueryHistoryManager badQueryManager = BadQueryHistoryManager.getInstance(kylinConfig);
+ String serverHostname;
+
+ public PersistenceNotifier() {
+ try {
+ serverHostname = InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e) {
+ serverHostname = "Unknow";
+ logger.warn("Error in get current hostname.", e);
+ }
+ }
+
+ @Override
+ public void badQueryFound(String adj, int runningSec, long startTime, String project, String sql, Thread t) {
+ try {
+ badQueryManager.addEntryToProject(sql, adj, startTime, serverHostname, t.getName(), project);
+ } catch (IOException e) {
+ logger.error("Error in bad query persistence.", e);
+ }
+ }
}
public void queryStart(Thread thread, SQLRequest sqlRequest) {
@@ -128,7 +171,7 @@ public class BadQueryDetector extends Thread {
for (Entry e : entries) {
int runningSec = (int) ((now - e.startTime) / 1000);
if (runningSec >= alertRunningSec) {
- notify("Slow", runningSec, e.sqlRequest.getSql(), e.thread);
+ notify("Slow", runningSec, e.startTime, e.sqlRequest.getProject(), e.sqlRequest.getSql(), e.thread);
dumpStackTrace(e.thread);
} else {
break; // entries are sorted by startTime
@@ -143,7 +186,7 @@ public class BadQueryDetector extends Thread {
// log the stack trace of bad query thread for further analysis
private void dumpStackTrace(Thread t) {
- int maxStackTraceDepth = KylinConfig.getInstanceFromEnv().getBadQueryStackTraceDepth();
+ int maxStackTraceDepth = kylinConfig.getBadQueryStackTraceDepth();
int current = 0;
StackTraceElement[] stackTrace = t.getStackTrace();
http://git-wip-us.apache.org/repos/asf/kylin/blob/cfb3c440/server/src/test/java/org/apache/kylin/rest/service/BadQueryDetectorTest.java
----------------------------------------------------------------------
diff --git a/server/src/test/java/org/apache/kylin/rest/service/BadQueryDetectorTest.java b/server/src/test/java/org/apache/kylin/rest/service/BadQueryDetectorTest.java
index 3481fa7..d4223a8 100644
--- a/server/src/test/java/org/apache/kylin/rest/service/BadQueryDetectorTest.java
+++ b/server/src/test/java/org/apache/kylin/rest/service/BadQueryDetectorTest.java
@@ -51,7 +51,7 @@ public class BadQueryDetectorTest extends LocalFileMetadataTestCase {
BadQueryDetector badQueryDetector = new BadQueryDetector(alertRunningSec * 1000, alertMB, alertRunningSec);
badQueryDetector.registerNotifier(new BadQueryDetector.Notifier() {
@Override
- public void badQueryFound(String adj, int runningSec, String sql, Thread t) {
+ public void badQueryFound(String adj, int runningSec, long startTime, String project, String sql, Thread t) {
alerts.add(new String[] { adj, sql });
}
});