diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-09-14 13:42:52 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-09-14 15:57:00 +0200 |
commit | c47259b05c3d6ce7fbc9cf2ba4fa21950f58a2b4 (patch) | |
tree | 948b9f59a8688a23059c5cdab5bccefce391e4b2 /config-model | |
parent | e5780128358a2db9574e785025d3db39a4563084 (diff) |
Setup separate threadpool for search handler in model
Diffstat (limited to 'config-model')
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(); |