diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-10-19 14:35:41 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2020-10-19 14:35:41 +0200 |
commit | e4915ba435f80ec2cec700c36533e97ccf40291a (patch) | |
tree | 07b3e3c05899492da4ed234096f1816d2e5fbf98 /config-model | |
parent | 96e57d962282f90b29a01dd188ae9ba1e26746d8 (diff) |
Scale Jetty threadpool size with node resources
Diffstat (limited to 'config-model')
8 files changed, 67 insertions, 7 deletions
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 00c5f6e326f..e141826ba44 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -54,6 +54,7 @@ public class TestProperties implements ModelContext.Properties { private ApplicationRoles applicationRoles; private Quota quota = Quota.unlimited(); private boolean useAccessControlTlsHandshakeClientAuth; + private double jettyThreadpoolSizeFactor = 0.0; @Override public boolean multitenant() { return multitenant; } @Override public ApplicationId applicationId() { return applicationId; } @@ -93,6 +94,7 @@ public class TestProperties implements ModelContext.Properties { @Override public boolean tlsUseFSync() { return tlsUseFSync; } @Override public String tlsCompressionType() { return tlsCompressionType; } @Override public boolean useAccessControlTlsHandshakeClientAuth() { return useAccessControlTlsHandshakeClientAuth; } + @Override public double jettyThreadpoolSizeFactor() { return jettyThreadpoolSizeFactor; } public TestProperties setJvmGCOptions(String gcOptions) { jvmGCOptions = gcOptions; @@ -144,6 +146,9 @@ public class TestProperties implements ModelContext.Properties { this.queueSizeFactor = queueSizeFactor; return this; } + + public TestProperties setJettyThreadpoolSizeFactor(double factor) { this.jettyThreadpoolSizeFactor = factor; return this; } + public TestProperties setApplicationId(ApplicationId applicationId) { this.applicationId = applicationId; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java index 1d991721ea7..a7f5398c7b5 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/Container.java @@ -88,7 +88,7 @@ public abstract class Container extends AbstractService implements this.parent = parent; this.retired = retired; this.index = index; - this.defaultHttpServer = new JettyHttpServer(new ComponentId("DefaultHttpServer"), isHostedVespa); + this.defaultHttpServer = new JettyHttpServer(new ComponentId("DefaultHttpServer"), containerClusterOrNull(parent), isHostedVespa); if (getHttp() == null) { addChild(defaultHttpServer); } @@ -390,8 +390,12 @@ public abstract class Container extends AbstractService implements return containerCluster().isPresent() && containerCluster().get().rpcServerEnabled(); } - private Optional<ContainerCluster> containerCluster() { - return (parent instanceof ContainerCluster) ? Optional.of((ContainerCluster) parent) : Optional.empty(); + protected Optional<ContainerCluster> containerCluster() { + return Optional.ofNullable(containerClusterOrNull(parent)); + } + + private static ContainerCluster containerClusterOrNull(AbstractConfigProducer producer) { + return producer instanceof ContainerCluster<?> ? (ContainerCluster<?>) producer : null; } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java index 4888add3253..57ebc215dfa 100755 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/ContainerCluster.java @@ -161,11 +161,14 @@ public abstract class ContainerCluster<CONTAINER extends Container> private boolean deferChangesUntilRestart = false; + private double jettyThreadpoolSizeFactor; + public ContainerCluster(AbstractConfigProducer<?> parent, String configSubId, String clusterId, DeployState deployState) { super(parent, configSubId); this.name = clusterId; this.isHostedVespa = stateIsHosted(deployState); this.zone = (deployState != null) ? deployState.zone() : Zone.defaultZone(); + this.jettyThreadpoolSizeFactor = deployState.getProperties().jettyThreadpoolSizeFactor(); componentGroup = new ComponentGroup<>(this, "component"); @@ -639,4 +642,7 @@ public abstract class ContainerCluster<CONTAINER extends Container> .max(); // Use highest vcpu as scale factor } + public OptionalDouble jettyThreadpoolSizeFactor() { + return jettyThreadpoolSizeFactor > 0 ? OptionalDouble.of(jettyThreadpoolSizeFactor) : OptionalDouble.empty(); + } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java index 98fde2e7859..8d55b424ad9 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/JettyHttpServer.java @@ -6,6 +6,7 @@ import com.yahoo.component.ComponentSpecification; import com.yahoo.container.bundle.BundleInstantiationSpecification; import com.yahoo.jdisc.http.ServerConfig; import com.yahoo.osgi.provider.model.ComponentModel; +import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.component.SimpleComponent; import java.util.ArrayList; @@ -20,16 +21,18 @@ import static com.yahoo.component.ComponentSpecification.fromString; */ public class JettyHttpServer extends SimpleComponent implements ServerConfig.Producer { + private final ContainerCluster<?> cluster; private final boolean isHostedVespa; private final List<ConnectorFactory> connectorFactories = new ArrayList<>(); - public JettyHttpServer(ComponentId id, boolean isHostedVespa) { + public JettyHttpServer(ComponentId id, ContainerCluster<?> cluster, boolean isHostedVespa) { super(new ComponentModel( new BundleInstantiationSpecification(id, fromString("com.yahoo.jdisc.http.server.jetty.JettyHttpServer"), fromString("jdisc_http_service")) )); this.isHostedVespa = isHostedVespa; + this.cluster = cluster; final FilterBindingsProviderComponent filterBindingsProviderComponent = new FilterBindingsProviderComponent(id); addChild(filterBindingsProviderComponent); inject(filterBindingsProviderComponent); @@ -69,6 +72,17 @@ public class JettyHttpServer extends SimpleComponent implements ServerConfig.Pro .remoteAddressHeaders(List.of("x-forwarded-for", "y-ra", "yahooremoteip", "client-ip")) .remotePortHeaders(List.of("X-Forwarded-Port", "y-rp"))); } + configureJettyThreadpool(builder); + } + + private void configureJettyThreadpool(ServerConfig.Builder builder) { + if (cluster == null) return; + double vcpu = cluster.vcpu().orElse(0); + double scaleFactor = cluster.jettyThreadpoolSizeFactor().orElse(0); + if (vcpu > 0 && scaleFactor > 0) { + int threads = Math.max(8, (int) Math.ceil(vcpu * scaleFactor)); + builder.maxWorkerThreads(threads).minWorkerThreads(threads); + } } static ComponentModel providerComponentModel(final ComponentId parentId, String className) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java index 004539688e2..9b9ebedda6d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/HttpBuilder.java @@ -56,7 +56,8 @@ public class HttpBuilder extends VespaDomBuilder.DomConfigProducerBuilder<Http> Http http = new Http(filterChains); http.getBindings().addAll(bindings); - http.setHttpServer(new JettyHttpServerBuilder().build(deployState, ancestor, spec)); + ApplicationContainerCluster cluster = getContainerCluster(ancestor).orElse(null); + http.setHttpServer(new JettyHttpServerBuilder(cluster).build(deployState, ancestor, spec)); if (accessControl != null) { accessControl.configureHttpFilterChains(http); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyHttpServerBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyHttpServerBuilder.java index cc9cd61df36..7f3c5f653aa 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyHttpServerBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/http/xml/JettyHttpServerBuilder.java @@ -6,6 +6,7 @@ import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.producer.AbstractConfigProducer; import com.yahoo.text.XML; import com.yahoo.vespa.model.builder.xml.dom.VespaDomBuilder; +import com.yahoo.vespa.model.container.ContainerCluster; import com.yahoo.vespa.model.container.http.ConnectorFactory; import com.yahoo.vespa.model.container.http.JettyHttpServer; import org.w3c.dom.Element; @@ -15,9 +16,15 @@ import org.w3c.dom.Element; */ public class JettyHttpServerBuilder extends VespaDomBuilder.DomConfigProducerBuilder<JettyHttpServer> { + private final ContainerCluster<?> cluster; + + public JettyHttpServerBuilder(ContainerCluster<?> cluster) { + this.cluster = cluster; + } + @Override protected JettyHttpServer doBuild(DeployState deployState, AbstractConfigProducer ancestor, Element http) { - JettyHttpServer jettyHttpServer = new JettyHttpServer(new ComponentId("jdisc-jetty"), deployState.isHosted()); + JettyHttpServer jettyHttpServer = new JettyHttpServer(new ComponentId("jdisc-jetty"), cluster, deployState.isHosted()); for (Element serverSpec: XML.getChildren(http, "server")) { ConnectorFactory connectorFactory = new JettyConnectorBuilder().build(deployState, ancestor, serverSpec); jettyHttpServer.addConnector(connectorFactory); 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 6fd1c9b35fb..37dd97a49b1 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 @@ -360,7 +360,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> { cluster.setHttp(new Http(new FilterChains(cluster))); } if(cluster.getHttp().getHttpServer().isEmpty()) { - JettyHttpServer defaultHttpServer = new JettyHttpServer(new ComponentId("DefaultHttpServer"), cluster.isHostedVespa()); + JettyHttpServer defaultHttpServer = new JettyHttpServer(new ComponentId("DefaultHttpServer"), cluster, cluster.isHostedVespa()); cluster.getHttp().setHttpServer(defaultHttpServer); defaultHttpServer.addConnector(new ConnectorFactory("SearchServer", Defaults.getDefaults().vespaWebServicePort())); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java index 3515efb7bc1..80fc713d69a 100755 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java @@ -18,6 +18,7 @@ import com.yahoo.config.provision.Zone; import com.yahoo.container.di.config.PlatformBundlesConfig; import com.yahoo.container.handler.ThreadPoolProvider; import com.yahoo.container.handler.ThreadpoolConfig; +import com.yahoo.jdisc.http.ServerConfig; import com.yahoo.search.config.QrStartConfig; import com.yahoo.vespa.model.Host; import com.yahoo.vespa.model.HostResource; @@ -280,6 +281,28 @@ public class ContainerClusterTest { } @Test + public void jetty_threadpool_scales_with_node_resources() { + HostProvisionerWithCustomRealResource hostProvisioner = new HostProvisionerWithCustomRealResource(); + MockRoot root = new MockRoot( + "foo", + new DeployState.Builder() + .properties(new TestProperties().setJettyThreadpoolSizeFactor(4).setHostedVespa(true)) + .applicationPackage(new MockApplicationPackage.Builder().build()) + .modelHostProvisioner(hostProvisioner) + .build()); + ApplicationContainerCluster cluster = createContainerCluster(root, false); + HostResource hostResource = new HostResource( + new Host(null, "host-c1"), + hostProvisioner.allocateHost("host-c1")); + addContainerWithHostResource(root.deployLogger(), cluster, "c1", hostResource); + root.freezeModelTopology(); + + ServerConfig cfg = root.getConfig(ServerConfig.class, "container0/c1/DefaultHttpServer"); + assertEquals(16, cfg.maxWorkerThreads()); + assertEquals(16, cfg.minWorkerThreads()); + } + + @Test public void requireThatRoutingProviderIsDisabledForNonHosted() { DeployState state = new DeployState.Builder().properties(new TestProperties().setHostedVespa(false)).build(); MockRoot root = new MockRoot("foo", state); |