EBernhardson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/258720

Change subject: [WIP] Collect per-node fetch/query latency percentiles
......................................................................

[WIP] Collect per-node fetch/query latency percentiles

This records latency percentiles on a per node basis and reports
them via JMX.  If we think this is a good idea (i'm not sure) i
can add some settings for turning it on/off along with changing
the default reporting to Graphite.

I tried doing it without rewriting bytecode, but the stats collection
is injected multiple levels down and unaccessible from a plugin. This
is a fairly non-invasive rewrite though so maybe it's ok.

Change-Id: I91c6c989578aee0b320eeac916a0aa6a912f900c
---
M pom.xml
M src/main/java/org/wikimedia/search/extra/ExtraPlugin.java
A 
src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchModule.java
A 
src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchService.java
4 files changed, 123 insertions(+), 1 deletion(-)


  git pull ssh://gerrit.wikimedia.org:29418/search/extra 
refs/changes/20/258720/1

diff --git a/pom.xml b/pom.xml
index 357a3a8..665087e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,8 @@
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <elasticsearch.version>1.7.0</elasticsearch.version>
     <lucene.version>4.10.4</lucene.version>
+    <metrics.version>3.1.0</metrics.version>
+    <javassist.version>3.20.0-GA</javassist.version>
   </properties>
 
   <build>
@@ -338,5 +340,15 @@
       <version>18.0</version>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-core</artifactId>
+      <version>${metrics.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+      <version>${javassist.version}</version>
+     </dependency>
   </dependencies>
 </project>
diff --git a/src/main/java/org/wikimedia/search/extra/ExtraPlugin.java 
b/src/main/java/org/wikimedia/search/extra/ExtraPlugin.java
index 57b8b71..4f99bb6 100644
--- a/src/main/java/org/wikimedia/search/extra/ExtraPlugin.java
+++ b/src/main/java/org/wikimedia/search/extra/ExtraPlugin.java
@@ -5,7 +5,11 @@
 import org.elasticsearch.common.collect.ImmutableList;
 import org.elasticsearch.common.inject.AbstractModule;
 import org.elasticsearch.common.inject.Module;
+import org.elasticsearch.common.inject.Provides;
+import org.elasticsearch.common.inject.Singleton;
 import org.elasticsearch.common.inject.multibindings.Multibinder;
+import org.elasticsearch.common.logging.ESLogger;
+import org.elasticsearch.common.logging.Loggers;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.query.QueryParser;
 import org.elasticsearch.index.query.functionscore.FunctionScoreModule;
@@ -25,6 +29,15 @@
 import org.wikimedia.search.extra.superdetectnoop.SuperDetectNoopScript;
 import org.wikimedia.search.extra.superdetectnoop.WithinAbsoluteHandler;
 import org.wikimedia.search.extra.superdetectnoop.WithinPercentageHandler;
+import org.wikimedia.search.extra.stats.NodeQueryStatsShardSearchService;
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.JmxReporter;
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.CtMethod;
+import javassist.expr.ExprEditor;
+import javassist.expr.NewExpr;
+import javassist.CannotCompileException;
 
 /**
  * Setup the Elasticsearch plugin.
@@ -67,7 +80,7 @@
 
     @Override
     public Collection<Class<? extends Module>> modules() {
-        return ImmutableList.<Class<? extends Module>> 
of(SafeifierActionsModule.class, CloseEnoughDetectorsModule.class);
+        return ImmutableList.<Class<? extends Module>> 
of(SafeifierActionsModule.class, CloseEnoughDetectorsModule.class, 
StatsModule.class);
     }
 
     public static class SafeifierActionsModule extends AbstractModule {
@@ -97,4 +110,49 @@
             handlers.addBinding().toInstance(new SetHandler.Recognizer());
         }
     }
+
+    public static class StatsModule extends AbstractModule {
+
+        public StatsModule(Settings settings) {
+        }
+
+        @Override
+        protected void configure() {
+            final ESLogger logger = Loggers.getLogger(getClass());
+            // here be dragons. Open up IndexService class and replace new 
ShardSearchModule();
+            // with our own module.
+            try {
+                ClassPool pool = ClassPool.getDefault();
+                pool.importPackage("org.wikimedia.search.extra.stats");
+                CtClass ct = pool.get("org.elasticsearch.index.IndexService");
+                final String lookFor = 
"org.elasticsearch.index.search.stats.ShardSearchModule";
+                for(CtMethod method : ct.getMethods()) {
+                    if (!method.getName().equals("createShard")) {
+                        continue;
+                    }
+                    method.instrument(new ExprEditor() {
+                        public void edit(NewExpr expr) throws 
CannotCompileException {
+                            if (!expr.getClassName().equals(lookFor)) {
+                                return;
+                            }
+                            expr.replace("{ $_ = new 
NodeQueryStatsShardSearchModule(); }");
+                        }
+                    });
+                }
+                // Force the JVM to load our new class
+                ct.toClass();
+                logger.info("Replaced IndexService implementation for stats 
collection");
+            } catch (Throwable e) {
+                logger.warn("Failed replacing ShardSearchModule", e);
+            }
+        }
+
+        @Provides @Singleton
+        public MetricRegistry provideMetricRegistry() {
+            MetricRegistry registry = new MetricRegistry();
+            JmxReporter reporter = JmxReporter.forRegistry(registry).build();
+            reporter.start();
+            return registry;
+        }
+    }
 }
diff --git 
a/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchModule.java
 
b/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchModule.java
new file mode 100644
index 0000000..9308b57
--- /dev/null
+++ 
b/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchModule.java
@@ -0,0 +1,17 @@
+package org.wikimedia.search.extra.stats;
+
+import org.elasticsearch.common.inject.AbstractModule;
+import org.elasticsearch.common.logging.Loggers;
+import org.elasticsearch.index.search.stats.ShardSearchService;
+import org.elasticsearch.index.search.slowlog.ShardSlowLogSearchService;
+/**
+ */
+public class NodeQueryStatsShardSearchModule extends AbstractModule {
+
+    @Override
+    protected void configure() {
+        Loggers.getLogger(getClass()).warn("Running in custom 
ShardSearchModule");
+        
bind(ShardSearchService.class).to(NodeQueryStatsShardSearchService.class).asEagerSingleton();
+        bind(ShardSlowLogSearchService.class).asEagerSingleton();
+    }
+}
diff --git 
a/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchService.java
 
b/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchService.java
new file mode 100644
index 0000000..f45cf2f
--- /dev/null
+++ 
b/src/main/java/org/wikimedia/search/extra/stats/NodeQueryStatsShardSearchService.java
@@ -0,0 +1,35 @@
+package org.wikimedia.search.extra.stats;
+
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.search.stats.ShardSearchService;
+import org.elasticsearch.index.search.slowlog.ShardSlowLogSearchService;
+import org.elasticsearch.index.settings.IndexSettings;
+import org.elasticsearch.index.shard.ShardId;
+import org.elasticsearch.search.internal.SearchContext;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Histogram;
+
+public class NodeQueryStatsShardSearchService extends ShardSearchService {
+    final Histogram queryTiming;
+    final Histogram fetchTiming;
+
+    @Inject
+    public NodeQueryStatsShardSearchService(ShardId shardId, @IndexSettings 
Settings indexSettings,
+                                            ShardSlowLogSearchService 
slowLogSearchService, MetricRegistry registry) {
+        super(shardId, indexSettings, slowLogSearchService);
+        queryTiming = registry.histogram(MetricRegistry.name(getClass(), 
"queryNanos"));
+        fetchTiming = registry.histogram(MetricRegistry.name(getClass(), 
"fetchNanos"));
+    }
+
+    public void onQueryPhase(SearchContext searchContext, long tookInNanos) {
+        super.onQueryPhase(searchContext, tookInNanos);
+        queryTiming.update(tookInNanos);
+    }
+
+    public void onFetchPhase(SearchContext searchContext, long tookInNanos) {
+        super.onFetchPhase(searchContext, tookInNanos);
+        fetchTiming.update(tookInNanos);
+    }
+}

-- 
To view, visit https://gerrit.wikimedia.org/r/258720
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I91c6c989578aee0b320eeac916a0aa6a912f900c
Gerrit-PatchSet: 1
Gerrit-Project: search/extra
Gerrit-Branch: master
Gerrit-Owner: EBernhardson <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to