aboutsummaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@verizonmedia.com>2020-09-14 13:42:52 +0200
committerBjørn Christian Seime <bjorncs@verizonmedia.com>2020-09-14 15:57:00 +0200
commitc47259b05c3d6ce7fbc9cf2ba4fa21950f58a2b4 (patch)
tree948b9f59a8688a23059c5cdab5bccefce391e4b2 /config-model
parente5780128358a2db9574e785025d3db39a4563084 (diff)
Setup separate threadpool for search handler in model
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java63
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java26
3 files changed, 90 insertions, 6 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 09911ada69b..150e103e304 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -416,7 +416,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
addIncludes(searchElement);
cluster.setSearch(buildSearch(deployState, cluster, searchElement));
- addSearchHandler(cluster, searchElement);
+ addSearchHandler(cluster, searchElement, deployState);
addGUIHandler(cluster);
validateAndAddConfiguredComponents(deployState, cluster, searchElement, "renderer", ContainerModelBuilder::validateRendererElement);
}
@@ -780,14 +780,13 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
container.setPreLoad(nodesElement.getAttribute(VespaDomBuilder.PRELOAD_ATTRIB_NAME));
}
- private void addSearchHandler(ApplicationContainerCluster cluster, Element searchElement) {
+ private void addSearchHandler(ApplicationContainerCluster cluster, Element searchElement, DeployState deployState) {
// Magic spell is needed to receive the chains config :-|
cluster.addComponent(new ProcessingHandler<>(cluster.getSearch().getChains(),
"com.yahoo.search.searchchain.ExecutionFactory"));
cluster.addComponent(
- new SearchHandler(
- cluster.getSearch().getChains(), serverBindings(searchElement, SearchHandler.DEFAULT_BINDING)));
+ new SearchHandler(cluster, serverBindings(searchElement, SearchHandler.DEFAULT_BINDING), deployState));
}
private void addGUIHandler(ApplicationContainerCluster cluster) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java
index abf151bd673..ec3ab3f9c87 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/SearchHandler.java
@@ -1,12 +1,17 @@
// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.container.xml;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig;
+import com.yahoo.vespa.model.container.ApplicationContainerCluster;
+import com.yahoo.vespa.model.container.ContainerThreadpoolComponent;
import com.yahoo.vespa.model.container.component.BindingPattern;
import com.yahoo.vespa.model.container.component.SystemBindingPattern;
import com.yahoo.vespa.model.container.component.chain.ProcessingHandler;
import com.yahoo.vespa.model.container.search.searchchain.SearchChains;
import java.util.List;
+import java.util.stream.Collectors;
/**
* Component definition for {@link com.yahoo.search.handler.SearchHandler}
@@ -18,8 +23,62 @@ class SearchHandler extends ProcessingHandler<SearchChains> {
static final String HANDLER_CLASS = com.yahoo.search.handler.SearchHandler.class.getName();
static final BindingPattern DEFAULT_BINDING = SystemBindingPattern.fromHttpPath("/search/*");
- SearchHandler(SearchChains searchChains, List<BindingPattern> bindings) {
- super(searchChains, HANDLER_CLASS);
+ private final ApplicationContainerCluster cluster;
+
+ SearchHandler(ApplicationContainerCluster cluster, List<BindingPattern> bindings, DeployState deployState) {
+ super(cluster.getSearchChains(), HANDLER_CLASS);
+ this.cluster = cluster;
bindings.forEach(this::addServerBindings);
+ Threadpool threadpool = new Threadpool(cluster, deployState);
+ inject(threadpool);
+ addComponent(threadpool);
+ }
+
+ private static class Threadpool extends ContainerThreadpoolComponent {
+ private final ApplicationContainerCluster cluster;
+ private final DeployState deployState;
+
+ Threadpool(ApplicationContainerCluster cluster, DeployState deployState) {
+ super("search-handler");
+ this.cluster = cluster;
+ this.deployState = deployState;
+ }
+
+ @Override
+ public void getConfig(ContainerThreadpoolConfig.Builder builder) {
+ super.getConfig(builder);
+
+ builder.maxThreadExecutionTimeSeconds(190);
+ builder.keepAliveTime(5.0);
+
+ double threadPoolSizeFactor = deployState.getProperties().threadPoolSizeFactor();
+ double vcpu = vcpu();
+ if (threadPoolSizeFactor <= 0 || vcpu == 0) {
+ builder.maxThreads(500);
+ builder.minThreads(500);
+ builder.queueSize(0);
+ } else {
+ // Controls max number of concurrent requests per container
+ int workerThreads = Math.max(2, (int)Math.ceil(vcpu * threadPoolSizeFactor));
+ builder.maxThreads(workerThreads);
+ builder.minThreads(workerThreads);
+
+ // This controls your burst handling capability.
+ // 0 => No extra burst handling beyond you max concurrent requests (maxthreads).
+ // N => N times max concurrent requests as a buffer for handling bursts
+ builder.queueSize((int)(workerThreads * deployState.getProperties().queueSizeFactor()));
+ }
+ }
+
+ private double vcpu() {
+ List<Double> vcpus = cluster.getContainers().stream()
+ .filter(c -> c.getHostResource() != null && c.getHostResource().realResources() != null)
+ .map(c -> c.getHostResource().realResources().vcpu())
+ .distinct()
+ .collect(Collectors.toList());
+ // We can only use host resource for calculation if all container nodes in the cluster are homogeneous (in terms of vcpu)
+ if (vcpus.size() != 1 || vcpus.get(0) == 0) return 0;
+ return vcpus.get(0);
+ }
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
index ed7d09d6410..180f21551e2 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/SearchBuilderTest.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.model.container.xml;
import com.yahoo.component.ComponentId;
import com.yahoo.config.model.builder.xml.test.DomBuilderTest;
import com.yahoo.container.core.ChainsConfig;
+import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig;
import com.yahoo.container.jdisc.JdiscBindingsConfig;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
@@ -19,6 +20,7 @@ import static com.yahoo.config.model.api.container.ContainerServiceType.QRSERVER
import static com.yahoo.test.Matchers.hasItemWithMethod;
import static com.yahoo.vespa.model.container.search.ContainerSearch.QUERY_PROFILE_REGISTRY_CLASS;
import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -220,6 +222,30 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase {
assertFalse(cluster.getSearchChains().localProviders().isEmpty());
}
+ @Test
+ public void search_handler_has_dedicated_threadpool() {
+ Element clusterElem = DomBuilderTest.parse(
+ "<container id='default' version='1.0'>",
+ " <search />",
+ nodesXml,
+ "</container>");
+
+ createModel(root, clusterElem);
+
+ ApplicationContainerCluster cluster = (ApplicationContainerCluster)root.getChildren().get("default");
+ Handler<?> searchHandler = cluster.getHandlers().stream()
+ .filter(h -> h.getComponentId().toString().equals(SearchHandler.HANDLER_CLASS))
+ .findAny()
+ .get();
+
+ assertThat(searchHandler.getInjectedComponentIds(), hasItem("threadpool@search-handler"));
+
+ ContainerThreadpoolConfig config = root.getConfig(
+ ContainerThreadpoolConfig.class, "default/component/" + SearchHandler.HANDLER_CLASS + "/threadpool@search-handler");
+ assertEquals(500, config.maxThreads());
+ assertEquals(500, config.minThreads());
+ assertEquals(0, config.queueSize());
+ }
private VespaModel getVespaModelWithMusic(String hosts, String services) {
return new VespaModelCreatorWithMockPkg(hosts, services, ApplicationPackageUtils.generateSchemas("music")).create();