diff options
26 files changed, 150 insertions, 199 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java index 9e1407ec93e..1c2da13738f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/clients/ContainerDocumentApi.java @@ -22,9 +22,6 @@ public class ContainerDocumentApi { public static final String DOCUMENT_V1_PREFIX = "/document/v1"; - private static final int FALLBACK_MAX_POOL_SIZE = 0; // Use fallback based on actual logical core count on host - private static final int FALLBACK_CORE_POOL_SIZE = 0; // Use fallback based on actual logical core count on host - public ContainerDocumentApi(ContainerCluster<?> cluster, Options options) { addRestApiHandler(cluster, options); addFeedHandler(cluster, options); @@ -102,22 +99,7 @@ public class ContainerDocumentApi { // User options overrides below configuration if (hasUserOptions()) return; - - builder.maxThreads(maxPoolSize()); - builder.minThreads(minPoolSize()); - builder.queueSize(500); - } - - private int maxPoolSize() { - double vcpu = cluster.vcpu().orElse(0); - if (vcpu == 0) return FALLBACK_MAX_POOL_SIZE; - return Math.max(2, (int)Math.ceil(vcpu * 4.0)); - } - - private int minPoolSize() { - double vcpu = cluster.vcpu().orElse(0); - if (vcpu == 0) return FALLBACK_CORE_POOL_SIZE; - return Math.max(1, (int)Math.ceil(vcpu * 2.0)); + builder.maxThreads(-4).minThreads(-4).queueSize(500); } } 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 f5b168958c0..d05650b10b5 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 @@ -70,7 +70,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; -import java.util.OptionalDouble; import java.util.Set; /** @@ -652,12 +651,4 @@ public abstract class ContainerCluster<CONTAINER extends Container> public boolean getDeferChangesUntilRestart() { return deferChangesUntilRestart; } - /** Effective vcpu for the containers in cluster. Use this value as scale factor for performance/resource tuning. **/ - public OptionalDouble vcpu() { - return getContainers().stream() - .filter(c -> c.getHostResource() != null && c.getHostResource().realResources() != null) - .mapToDouble(c -> c.getHostResource().realResources().vcpu()) - .max(); // Use highest vcpu as scale factor - } - } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java b/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java index 4d665b0bb58..3fde2167bf8 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/DefaultThreadpoolProvider.java @@ -46,13 +46,10 @@ class DefaultThreadpoolProvider extends SimpleComponent implements ThreadpoolCon return; } - double vcpu = cluster.vcpu().orElse(0); - if (vcpu == 0) return; - - // Configuration is currently identical to the search handler's threadpool - int workerThreads = Math.max(8, (int)Math.ceil(vcpu * 2.0)); - builder.maxthreads(workerThreads); - builder.corePoolSize(workerThreads); - builder.queueSize((int)(workerThreads * 40.0)); + if (cluster.isHostedVespa()) { + builder.corePoolSize(-2).maxthreads(-2).queueSize(-40); + } else { + builder.corePoolSize(-4).maxthreads(-4).queueSize(-40); + } } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java index fc41da43479..33e712feeb1 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/AccessLogComponent.java @@ -9,8 +9,6 @@ import com.yahoo.osgi.provider.model.ComponentModel; import com.yahoo.vespa.model.container.ApplicationContainerCluster; import com.yahoo.vespa.model.container.ContainerCluster; -import java.util.OptionalInt; - /** * @author Tony Vaagenes * @author gjoranv @@ -32,11 +30,10 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL public AccessLogComponent(ContainerCluster<?> cluster, AccessLogType logType, CompressionType compressionType, String clusterName, boolean isHostedVespa) { - this(cluster, logType, compressionType, + this(logType, compressionType, String.format("logs/vespa/qrs/%s.%s.%s", capitalize(logType.name()), clusterName, "%Y%m%d%H%M%S"), null, null, isHostedVespa, - capitalize(logType.name()) + "." + clusterName, - queueSize(cluster).orElse(-1), + capitalize(logType.name()) + "." + clusterName, -1, ((cluster instanceof ApplicationContainerCluster) ? 4*1024*1024 : null)); } @@ -44,8 +41,7 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL return name.substring(0, 1).toUpperCase() + name.substring(1); } - public AccessLogComponent(ContainerCluster<?> cluster, - AccessLogType logType, + public AccessLogComponent(AccessLogType logType, CompressionType compressionType, String fileNamePattern, String rotationInterval, @@ -69,13 +65,6 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL throw new RuntimeException("File name pattern required when configuring access log."); } - private static OptionalInt queueSize(ContainerCluster<?> cluster) { - if (cluster == null) return OptionalInt.empty(); - double vcpu = cluster.vcpu().orElse(0); - if (vcpu <= 0) return OptionalInt.empty(); - return OptionalInt.of((int) Math.max(4096, Math.ceil(vcpu * 256.0))); - } - private static String accessLogClass(AccessLogType logType) { switch (logType) { case queryAccessLog: @@ -105,9 +94,7 @@ public final class AccessLogComponent extends SimpleComponent implements AccessL } else if (isHostedVespa) { builder.compressOnRotation(true); } - if (queueSize >= 0) { - builder.queueSize(queueSize); - } + builder.queueSize(queueSize); if (bufferSize != null) { builder.bufferSize(bufferSize); } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java b/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java index 0b51cd163a2..4afac252085 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/component/ConnectionLogComponent.java @@ -6,38 +6,25 @@ import com.yahoo.container.logging.ConnectionLog; import com.yahoo.container.logging.ConnectionLogConfig; import com.yahoo.vespa.model.container.ContainerCluster; -import java.util.OptionalInt; - public class ConnectionLogComponent extends SimpleComponent implements ConnectionLogConfig.Producer { private final String logDirectoryName; private final String clusterName; - private final int queueSize; public ConnectionLogComponent(ContainerCluster<?> cluster, Class<? extends ConnectionLog> cls, String logDirectoryName) { - this(cluster, cls, logDirectoryName, cluster.getName()); + this(cls, logDirectoryName, cluster.getName()); } - public ConnectionLogComponent(ContainerCluster<?> cluster, Class<? extends ConnectionLog> cls, String logDirectoryName, String clusterName) { + public ConnectionLogComponent(Class<? extends ConnectionLog> cls, String logDirectoryName, String clusterName) { super(cls.getName()); this.logDirectoryName = logDirectoryName; this.clusterName = clusterName; - this.queueSize = queueSize(cluster).orElse(-1); - } - - private static OptionalInt queueSize(ContainerCluster<?> cluster) { - if (cluster == null) return OptionalInt.empty(); - double vcpu = cluster.vcpu().orElse(0); - if (vcpu <= 0) return OptionalInt.empty(); - return OptionalInt.of((int) Math.max(4096, Math.ceil(vcpu * 512.0))); } @Override public void getConfig(ConnectionLogConfig.Builder builder) { builder.cluster(clusterName); builder.logDirectoryName(logDirectoryName); - if (queueSize >= 0) { - builder.queueSize(queueSize); - } + builder.queueSize(-1); } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java index d7812e9b4ff..62f04edf0ae 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/AccessLogBuilder.java @@ -55,7 +55,6 @@ public class AccessLogBuilder { @Override protected AccessLogComponent doBuild(DeployState deployState, AbstractConfigProducer<?> ancestor, Element spec) { return new AccessLogComponent( - (ContainerCluster<?>) ancestor, accessLogType, compressionType(spec, isHostedVespa), fileNamePattern(spec), diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java index a1f52cca9fd..75f11020c15 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ConfigServerContainerModelBuilder.java @@ -6,7 +6,6 @@ import com.yahoo.config.model.deploy.DeployState; import com.yahoo.container.logging.FileConnectionLog; import com.yahoo.vespa.model.container.ApplicationContainerCluster; import com.yahoo.vespa.model.container.ContainerModel; -import com.yahoo.vespa.model.container.ContainerModelEvaluation; import com.yahoo.vespa.model.container.component.AccessLogComponent; import com.yahoo.vespa.model.container.component.ConnectionLogComponent; import com.yahoo.vespa.model.container.configserver.ConfigserverCluster; @@ -48,7 +47,7 @@ public class ConfigServerContainerModelBuilder extends ContainerModelBuilder { if (isHosted()){ cluster.addComponent( new AccessLogComponent( - cluster, AccessLogComponent.AccessLogType.jsonAccessLog, AccessLogComponent.CompressionType.ZSTD, + AccessLogComponent.AccessLogType.jsonAccessLog, AccessLogComponent.CompressionType.ZSTD, "logs/vespa/configserver/access-json.log.%Y%m%d%H%M%S", null, true, true, "access-json.log", 1024,256*1024)); cluster.addComponent(new ConnectionLogComponent(cluster, FileConnectionLog.class, "configserver")); } else { 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 95b333f4e52..0902fc454c3 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 @@ -48,22 +48,10 @@ class SearchHandler extends ProcessingHandler<SearchChains> { // User options overrides below configuration if (hasUserOptions()) return; - - double vcpu = cluster.vcpu().orElse(0); - if (vcpu == 0) { - builder.maxThreads(500); - builder.minThreads(500); - builder.queueSize(0); + if (cluster.isHostedVespa()) { + builder.maxThreads(-2).minThreads(-2).queueSize(-40); } else { - // Controls max number of concurrent requests per container - int workerThreads = Math.max(8, (int)Math.ceil(vcpu * 2.0)); - 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 * 40.0)); + builder.maxThreads(-4).minThreads(-4).queueSize(-40); } } 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 60dac5926f4..96029f809ae 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 @@ -239,27 +239,15 @@ public class ContainerClusterTest { } @Test - public void requireThatPoolAndQueueCanNotBeControlledByPropertiesWhenNoFlavor() { + public void requireThatNonHostedUsesLargerDefaultThreadpool() { MockRoot root = new MockRoot("foo"); ApplicationContainerCluster cluster = createContainerCluster(root, false); addContainer(root, cluster, "c1", "host-c1"); root.freezeModelTopology(); ThreadpoolConfig threadpoolConfig = root.getConfig(ThreadpoolConfig.class, "container0/component/default-threadpool"); - assertEquals(500, threadpoolConfig.maxthreads()); - assertEquals(0, threadpoolConfig.queueSize()); - } - - @Test - public void requireThatDefaultThreadPoolConfigIsSane() { - MockRoot root = new MockRoot("foo"); - ApplicationContainerCluster cluster = createContainerCluster(root, false); - addContainer(root, cluster, "c1", "host-c1"); - root.freezeModelTopology(); - - ThreadpoolConfig threadpoolConfig = root.getConfig(ThreadpoolConfig.class, "container0/component/default-threadpool"); - assertEquals(500, threadpoolConfig.maxthreads()); - assertEquals(0, threadpoolConfig.queueSize()); + assertEquals(-4, threadpoolConfig.maxthreads()); + assertEquals(-40, threadpoolConfig.queueSize()); } @Test @@ -277,28 +265,24 @@ public class ContainerClusterTest { } @Test - public void config_for_default_threadpool_provider_scales_with_node_resources() { - HostProvisionerWithCustomRealResource hostProvisioner = new HostProvisionerWithCustomRealResource(); + public void config_for_default_threadpool_provider_scales_with_node_resources_in_hosted() { MockRoot root = new MockRoot( "foo", new DeployState.Builder() + .properties(new TestProperties().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, cluster, "c1", hostResource); + addContainer(root, cluster, "c1", "host-c1"); root.freezeModelTopology(); ThreadpoolConfig threadpoolConfig = root.getConfig(ThreadpoolConfig.class, "container0/component/default-threadpool"); - assertEquals(8, threadpoolConfig.maxthreads()); - assertEquals(320, threadpoolConfig.queueSize()); + assertEquals(-2, threadpoolConfig.maxthreads()); + assertEquals(-40, threadpoolConfig.queueSize()); } @Test - public void jetty_threadpool_scales_with_node_resources() { + public void jetty_threadpool_scales_with_node_resources_in_hosted() { MockRoot root = new MockRoot( "foo", new DeployState.Builder() diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java index 80aafdd4ec7..06281c7b57e 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/AccessLogTest.java @@ -117,7 +117,7 @@ public class AccessLogTest extends ContainerModelBuilderTestBase { assertNotNull(connectionLogComponent); ConnectionLogConfig config = root.getConfig(ConnectionLogConfig.class, "default/component/com.yahoo.container.logging.FileConnectionLog"); assertEquals("default", config.cluster()); - assertEquals(10000, config.queueSize()); + assertEquals(-1, config.queueSize()); assertEquals(256*1024, config.bufferSize()); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java index 3c733d5109d..0176d5f6ffc 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ContainerDocumentApiBuilderTest.java @@ -6,7 +6,6 @@ import com.yahoo.config.model.test.MockApplicationPackage; import com.yahoo.config.model.test.MockRoot; import com.yahoo.container.handler.threadpool.ContainerThreadpoolConfig; import com.yahoo.vespa.model.container.ContainerCluster; -import com.yahoo.vespa.model.container.HostProvisionerWithCustomRealResource; import com.yahoo.vespa.model.container.component.Handler; import com.yahoo.vespa.model.container.component.SystemBindingPattern; import com.yahoo.vespa.model.container.component.UserBindingPattern; @@ -98,7 +97,7 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa " <document-api />", nodesXml, "</container>"); - root = new MockRoot("root", new MockApplicationPackage.Builder().build(), new HostProvisionerWithCustomRealResource()); + root = new MockRoot("root", new MockApplicationPackage.Builder().build()); createModel(root, elem); Map<String, Handler<?>> handlers = getHandlers("cluster1"); Handler<?> feedApiHandler = handlers.get("com.yahoo.vespa.http.server.FeedHandler"); @@ -107,8 +106,8 @@ public class ContainerDocumentApiBuilderTest extends ContainerModelBuilderTestBa ContainerThreadpoolConfig config = root.getConfig( ContainerThreadpoolConfig.class, "cluster1/component/com.yahoo.vespa.http.server.FeedHandler/threadpool@feedapi-handler"); - assertEquals(16, config.maxThreads()); - assertEquals(8, config.minThreads()); + assertEquals(-4, config.maxThreads()); + assertEquals(-4, config.minThreads()); } @Test 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 4c1fda44038..83e338fcaf0 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 @@ -242,9 +242,9 @@ public class SearchBuilderTest extends ContainerModelBuilderTestBase { 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()); + assertEquals(-4, config.maxThreads()); + assertEquals(-4, config.minThreads()); + assertEquals(-40, config.queueSize()); } @Test diff --git a/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java b/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java index 6bed4a6f442..7f4d1462102 100644 --- a/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java +++ b/container-core/src/main/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadpool.java @@ -12,9 +12,10 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; /** - * Default implementation of {@link DefaultContainerThreadpool}. + * Default implementation of {@link ContainerThreadPool}. * * @author Steinar Knutsen * @author baldersheim @@ -23,6 +24,10 @@ import java.util.concurrent.TimeUnit; */ public class DefaultContainerThreadpool extends AbstractComponent implements AutoCloseable, ContainerThreadPool { + private static final Logger log = Logger.getLogger(DefaultContainerThreadpool.class.getName()); + private static final int MIN_QUEUE_SIZE = 650; + private static final int MIN_THREADS_WHEN_SCALE_FACTOR = 8; + private final ExecutorServiceWrapper threadpool; @Inject @@ -31,14 +36,23 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut } public DefaultContainerThreadpool(ContainerThreadpoolConfig config, Metric metric, ProcessTerminator processTerminator) { - ThreadPoolMetric threadPoolMetric = new ThreadPoolMetric(metric, config.name()); - int maxNumThreads = computeMaximumThreadPoolSize(config.maxThreads()); - int coreNumThreads = computeCoreThreadPoolSize(config.minThreads(), maxNumThreads); + this(config, metric, processTerminator, Runtime.getRuntime().availableProcessors()); + } + + DefaultContainerThreadpool(ContainerThreadpoolConfig config, Metric metric, ProcessTerminator processTerminator, + int cpus) { + String name = config.name(); + int maxThreads = maxThreads(config, cpus); + int minThreads = minThreads(config, maxThreads, cpus); + int queueSize = queueSize(config, maxThreads); + log.info(String.format("Threadpool '%s': min=%d, max=%d, queue=%d", name, minThreads, maxThreads, queueSize)); + + ThreadPoolMetric threadPoolMetric = new ThreadPoolMetric(metric, name); WorkerCompletionTimingThreadPoolExecutor executor = - new WorkerCompletionTimingThreadPoolExecutor(coreNumThreads, maxNumThreads, + new WorkerCompletionTimingThreadPoolExecutor(minThreads, maxThreads, (int)config.keepAliveTime() * 1000, TimeUnit.MILLISECONDS, - createQ(config.queueSize(), maxNumThreads), - ThreadFactoryFactory.getThreadFactory(config.name()), + createQueue(queueSize), + ThreadFactoryFactory.getThreadFactory(name), threadPoolMetric); // Prestart needed, if not all threads will be created by the fist N tasks and hence they might also // get the dreaded thread locals initialized even if they will never run. @@ -46,7 +60,7 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut executor.prestartAllCoreThreads(); threadpool = new ExecutorServiceWrapper( executor, threadPoolMetric, processTerminator, config.maxThreadExecutionTimeSeconds() * 1000L, - config.name(), config.queueSize()); + name, queueSize); } @Override public Executor executor() { return threadpool; } @@ -74,24 +88,26 @@ public class DefaultContainerThreadpool extends AbstractComponent implements Aut } } - private static BlockingQueue<Runnable> createQ(int queueSize, int maxThreads) { - return (queueSize == 0) - ? new SynchronousQueue<>(false) - : (queueSize < 0) - ? new ArrayBlockingQueue<>(maxThreads*4) - : new ArrayBlockingQueue<>(queueSize); + private static BlockingQueue<Runnable> createQueue(int size) { + return size == 0 ? new SynchronousQueue<>(false) : new ArrayBlockingQueue<>(size); + } + + private static int maxThreads(ContainerThreadpoolConfig config, int cpus) { + if (config.maxThreads() > 0) return config.maxThreads(); + else if (config.maxThreads() == 0) return 4 * cpus; + else return Math.max(MIN_THREADS_WHEN_SCALE_FACTOR, Math.abs(config.maxThreads()) * cpus); } - private static int computeMaximumThreadPoolSize(int maxNumThreads) { - return (maxNumThreads <= 0) - ? Runtime.getRuntime().availableProcessors() * 4 - : maxNumThreads; + private static int minThreads(ContainerThreadpoolConfig config, int max, int cpus) { + int threads; + if (config.minThreads() > 0) threads = config.minThreads(); + else if (config.minThreads() == 0) threads = 4 * cpus; + else threads = Math.max(MIN_THREADS_WHEN_SCALE_FACTOR, Math.abs(config.minThreads()) * cpus); + return Math.min(threads, max); } - private static int computeCoreThreadPoolSize(int corePoolSize, int maxNumThreads) { - return Math.min( - corePoolSize <= 0 ? Runtime.getRuntime().availableProcessors() * 2 : corePoolSize, - maxNumThreads); + private int queueSize(ContainerThreadpoolConfig config, int maxThreads) { + return config.queueSize() >= 0 ? config.queueSize() : Math.max(MIN_QUEUE_SIZE, Math.abs(config.queueSize()) * maxThreads); } } diff --git a/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java b/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java index f14479899f5..55c3ad2ca8e 100644 --- a/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java +++ b/container-core/src/main/java/com/yahoo/container/logging/AccessLogHandler.java @@ -13,13 +13,19 @@ class AccessLogHandler { AccessLogHandler(AccessLogConfig.FileHandler config, LogWriter<RequestLogEntry> logWriter) { logFileHandler = new LogFileHandler<>( toCompression(config), config.bufferSize(), config.pattern(), config.rotation(), - config.symlink(), config.queueSize(), "request-logger", logWriter); + config.symlink(), queueSize(config), "request-logger", logWriter); + } + + private static int queueSize(AccessLogConfig.FileHandler config) { + if (config.queueSize() != -1) return config.queueSize(); + return Math.max(4096, Runtime.getRuntime().availableProcessors() * 256); } public void log(RequestLogEntry entry) { logFileHandler.publish(entry); } + private LogFileHandler.Compression toCompression(AccessLogConfig.FileHandler config) { if (!config.compressOnRotation()) return LogFileHandler.Compression.NONE; switch (config.compressionFormat()) { diff --git a/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java b/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java index 749426d3da9..273d562d048 100644 --- a/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java +++ b/container-core/src/main/java/com/yahoo/container/logging/FileConnectionLog.java @@ -14,7 +14,13 @@ public class FileConnectionLog extends AbstractComponent implements ConnectionLo @Inject public FileConnectionLog(ConnectionLogConfig config) { - logHandler = new ConnectionLogHandler(config.logDirectoryName(), config.bufferSize(), config.cluster(), config.queueSize(), new JsonConnectionLogWriter()); + logHandler = new ConnectionLogHandler(config.logDirectoryName(), config.bufferSize(), config.cluster(), + queueSize(config), new JsonConnectionLogWriter()); + } + + private static int queueSize(ConnectionLogConfig config) { + if (config.queueSize() != -1) return config.queueSize(); + return Math.max(4096, Runtime.getRuntime().availableProcessors() * 512); } @Override diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java index e13d76b5720..b44a32c4db1 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/JettyHttpServer.java @@ -134,8 +134,11 @@ public class JettyHttpServer extends AbstractServerProvider { private static void configureJettyThreadpool(Server server, ServerConfig config) { int cpus = Runtime.getRuntime().availableProcessors(); QueuedThreadPool pool = (QueuedThreadPool) server.getThreadPool(); - pool.setMaxThreads(config.maxWorkerThreads() > 0 ? config.maxWorkerThreads() : 16 + cpus); - pool.setMinThreads(config.minWorkerThreads() >= 0 ? config.minWorkerThreads() : 16 + cpus); + int maxThreads = config.maxWorkerThreads() > 0 ? config.maxWorkerThreads() : 16 + cpus; + pool.setMaxThreads(maxThreads); + int minThreads = config.minWorkerThreads() >= 0 ? config.minWorkerThreads() : 16 + cpus; + pool.setMinThreads(minThreads); + log.info(String.format("Threadpool size: min=%d, max=%d", minThreads, maxThreads)); } private static JMXServiceURL createJmxLoopbackOnlyServiceUrl(int port) { @@ -225,10 +228,9 @@ public class JettyHttpServer extends AbstractServerProvider { var sslConnectionFactory = serverConnector.getConnectionFactory(SslConnectionFactory.class); if (sslConnectionFactory != null) { var sslContextFactory = sslConnectionFactory.getSslContextFactory(); - log.info(String.format("Enabled SSL cipher suites for port '%d': %s", - localPort, Arrays.toString(sslContextFactory.getSelectedCipherSuites()))); - log.info(String.format("Enabled SSL protocols for port '%d': %s", - localPort, Arrays.toString(sslContextFactory.getSelectedProtocols()))); + String protocols = Arrays.toString(sslContextFactory.getSelectedProtocols()); + String cipherSuites = Arrays.toString(sslContextFactory.getSelectedCipherSuites()); + log.info(String.format("TLS for port '%d': %s with %s", localPort, protocols, cipherSuites)); } } } diff --git a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def index 9248bf2e2bf..4ba14c2da89 100644 --- a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def +++ b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.container-threadpool.def @@ -4,16 +4,19 @@ namespace=container.handler.threadpool ## Maximum number of thread in the thread pool ## 0 is translated to vcpu*4 +## Negative value is interpreted as scale factor ( vcpu*abs(maxThreads) ) maxThreads int default=0 ## Minimum number of thread in the thread pool ## 0 is translated to vcpu*2 +## Negative value is interpreted as scale factor ( vcpu*abs(minThreads) ) minThreads int default=0 ## The number of seconds that excess idle threads will wait for new tasks before terminating keepAliveTime double default=5.0 ## Max queue size +## Negative value is interpreted as scale factor ( effectiveMaxThreads*abs(queueSize) ) queueSize int default=0 ## The max time the container tolerates having no threads available before it shuts down to diff --git a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def index d966738ea9f..e73ee2254fc 100644 --- a/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def +++ b/container-core/src/main/resources/configdefinitions/container.handler.threadpool.def @@ -3,10 +3,13 @@ namespace=container.handler ## Maximum number of thread in the thread pool -## Setting it to 0 or negative number will cause it to be set to #cores * 4 +## 0 is translated to vcpu*4 +## Negative value is interpreted as scale factor ( vcpu*abs(maxThreads) ) maxthreads int default=500 -# The number of threads to keep in the pool, even if they are idle +## The number of threads to keep in the pool, even if they are idle +## 0 is translated to vcpu*4 +## Negative value is interpreted as scale factor ( vcpu*abs(corePoolSize) ) corePoolSize int default=500 # The number of seconds that excess idle threads will wait for new tasks before terminating diff --git a/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java b/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java index 8b1ed12c796..1d9c4b367bd 100644 --- a/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java +++ b/container-core/src/test/java/com/yahoo/container/handler/threadpool/DefaultContainerThreadPoolTest.java @@ -21,6 +21,9 @@ import static org.junit.Assert.fail; * @author bjorncs */ public class DefaultContainerThreadPoolTest { + + private static final int CPUS = 16; + @Test public final void testThreadPool() throws InterruptedException { ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder().maxThreads(1)); @@ -55,8 +58,12 @@ public class DefaultContainerThreadPoolTest { } private ThreadPoolExecutor createPool(int maxThreads, int queueSize) { - ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder().maxThreads(maxThreads).queueSize(queueSize)); - ContainerThreadPool threadPool = new DefaultContainerThreadpool(config, Mockito.mock(Metric.class)); + ContainerThreadpoolConfig config = new ContainerThreadpoolConfig(new ContainerThreadpoolConfig.Builder() + .maxThreads(maxThreads) + .minThreads(maxThreads) + .queueSize(queueSize)); + ContainerThreadPool threadPool = new DefaultContainerThreadpool( + config, Mockito.mock(Metric.class), new MockProcessTerminator(), CPUS); ExecutorServiceWrapper wrapper = (ExecutorServiceWrapper) threadPool.executor(); WorkerCompletionTimingThreadPoolExecutor executor = (WorkerCompletionTimingThreadPoolExecutor)wrapper.delegate(); return executor; @@ -64,27 +71,27 @@ public class DefaultContainerThreadPoolTest { @Test public void testThatThreadPoolSizeFollowsConfig() { - ThreadPoolExecutor executor = createPool(3, 9); + ThreadPoolExecutor executor = createPool(3, 1200); assertEquals(3, executor.getMaximumPoolSize()); - assertEquals(9, executor.getQueue().remainingCapacity()); + assertEquals(1200, executor.getQueue().remainingCapacity()); } @Test public void testThatThreadPoolSizeAutoDetected() { ThreadPoolExecutor executor = createPool(0, 0); - assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize()); + assertEquals(CPUS*4, executor.getMaximumPoolSize()); assertEquals(0, executor.getQueue().remainingCapacity()); } @Test public void testThatQueueSizeAutoDetected() { - ThreadPoolExecutor executor = createPool(3, -1); - assertEquals(3, executor.getMaximumPoolSize()); - assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity()); + ThreadPoolExecutor executor = createPool(24, -50); + assertEquals(24, executor.getMaximumPoolSize()); + assertEquals(24*50, executor.getQueue().remainingCapacity()); } @Test public void testThatThreadPoolSizeAndQueueSizeAutoDetected() { - ThreadPoolExecutor executor = createPool(0, -1); - assertEquals(Runtime.getRuntime().availableProcessors()*4, executor.getMaximumPoolSize()); - assertEquals(executor.getMaximumPoolSize()*4, executor.getQueue().remainingCapacity()); + ThreadPoolExecutor executor = createPool(0, -100); + assertEquals(CPUS*4, executor.getMaximumPoolSize()); + assertEquals(CPUS*4*100, executor.getQueue().remainingCapacity()); } private class FlipIt implements Runnable { diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java index a84d2521b8b..de595da07b6 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java @@ -68,6 +68,7 @@ public final class ConfiguredApplication implements Application { private static final Logger log = Logger.getLogger(ConfiguredApplication.class.getName()); private static final Set<ClientProvider> startedClients = Collections.newSetFromMap(new WeakHashMap<>()); + static final String SANITIZE_FILENAME = "[/,;]"; private static final Set<ServerProvider> startedServers = Collections.newSetFromMap(new IdentityHashMap<>()); private final SubscriberFactory subscriberFactory; @@ -407,6 +408,12 @@ public final class ConfiguredApplication implements Application { } } + static String santizeFileName(String s) { + return s.trim() + .replace('\\', '.') + .replaceAll(SANITIZE_FILENAME, "."); + } + // Workaround for ApplicationLoader.stop not being able to shutdown private void startShutdownDeadlineExecutor() { shutdownDeadlineExecutor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("Shutdown deadline timer")); @@ -414,7 +421,7 @@ public final class ConfiguredApplication implements Application { long delayMillis = (long)(shudownTimeoutS.get() * 1000.0); shutdownDeadlineExecutor.schedule(() -> { if (dumpHeapOnShutdownTimeout.get()) { - String heapDumpName = Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + ProcessHandle.current().pid() + ".hprof"; + String heapDumpName = Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + santizeFileName(configId) + "." + ProcessHandle.current().pid() + ".hprof"; com.yahoo.protect.Process.dumpHeap(heapDumpName, true); } com.yahoo.protect.Process.logAndDie( diff --git a/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java b/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java new file mode 100644 index 00000000000..c8cf5c0ce63 --- /dev/null +++ b/container-disc/src/test/java/com/yahoo/container/jdisc/ConfiguredApplicationTest.java @@ -0,0 +1,14 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.jdisc; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ConfiguredApplicationTest { + @Test + public void testConfigId2FileName() { + assertEquals("admin.metrics.2088223-v6-1.ostk.bm2.prod.ne1.yahoo.com", ConfiguredApplication.santizeFileName("admin/metrics/2088223-v6-1.ostk.bm2.prod.ne1.yahoo.com")); + assertEquals("admin.standalone.cluster-controllers.1", ConfiguredApplication.santizeFileName("admin/standalone/cluster-controllers/1 ")); + } +} diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java index af731e3ade0..fc5bedf07c7 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/Dispatcher.java @@ -2,7 +2,6 @@ package com.yahoo.search.dispatch; import com.google.inject.Inject; -import com.yahoo.cloud.config.ClusterInfoConfig; import com.yahoo.component.AbstractComponent; import com.yahoo.component.ComponentId; import com.yahoo.compress.Compressor; @@ -26,11 +25,9 @@ import com.yahoo.search.query.profile.types.QueryProfileType; import com.yahoo.search.result.ErrorMessage; import com.yahoo.vespa.config.search.DispatchConfig; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.OptionalInt; import java.util.Set; import java.util.stream.Collectors; @@ -94,10 +91,9 @@ public class Dispatcher extends AbstractComponent { public Dispatcher(RpcResourcePool resourcePool, ComponentId clusterId, DispatchConfig dispatchConfig, - ClusterInfoConfig clusterInfoConfig, VipStatus vipStatus, Metric metric) { - this(resourcePool, new SearchCluster(clusterId.stringValue(), dispatchConfig,clusterInfoConfig.nodeCount(), + this(resourcePool, new SearchCluster(clusterId.stringValue(), dispatchConfig, vipStatus, new RpcPingFactory(resourcePool)), dispatchConfig, metric); diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java index 54d5dfc91af..b5fbede4701 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/searchcluster/SearchCluster.java @@ -53,7 +53,7 @@ public class SearchCluster implements NodeManager<Node> { */ private final Optional<Node> localCorpusDispatchTarget; - public SearchCluster(String clusterId, DispatchConfig dispatchConfig, int containerClusterSize, + public SearchCluster(String clusterId, DispatchConfig dispatchConfig, VipStatus vipStatus, PingFactory pingFactory) { this.clusterId = clusterId; this.dispatchConfig = dispatchConfig; @@ -81,17 +81,7 @@ public class SearchCluster implements NodeManager<Node> { this.nodesByHost = nodesByHostBuilder.build(); hitEstimator = new TopKEstimator(30.0, dispatchConfig.topKProbability(), SKEW_FACTOR); - this.localCorpusDispatchTarget = findLocalCorpusDispatchTarget(HostName.getLocalhost(), - size, - containerClusterSize, - nodesByHost, - groups); - } - - /* Testing only */ - public SearchCluster(String clusterId, DispatchConfig dispatchConfig, - VipStatus vipStatus, PingFactory pingFactory) { - this(clusterId, dispatchConfig, 1, vipStatus, pingFactory); + this.localCorpusDispatchTarget = findLocalCorpusDispatchTarget(HostName.getLocalhost(), nodesByHost, groups); } public void addMonitoring(ClusterMonitor<Node> clusterMonitor) { @@ -102,8 +92,6 @@ public class SearchCluster implements NodeManager<Node> { } private static Optional<Node> findLocalCorpusDispatchTarget(String selfHostname, - int searchClusterSize, - int containerClusterSize, ImmutableMultimap<String, Node> nodesByHost, ImmutableMap<Integer, Group> groups) { // A search node in the search cluster in question is configured on the same host as the currently running container. @@ -120,12 +108,6 @@ public class SearchCluster implements NodeManager<Node> { // Only use direct dispatch if the local search node has the entire corpus if (localSearchGroup.nodes().size() != 1) return Optional.empty(); - // Only use direct dispatch if this container cluster has at least as many nodes as the search cluster - // to avoid load skew/preserve fanout in the case where a subset of the search nodes are also containers. - // This disregards the case where the search and container clusters are partially overlapping. - // Such configurations produce skewed load in any case. - if (containerClusterSize < searchClusterSize) return Optional.empty(); - return Optional.of(localSearchNode); } diff --git a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java index ca98b6a1a77..38c231cb1bb 100644 --- a/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java +++ b/container-search/src/test/java/com/yahoo/prelude/cluster/ClusterSearcherTestCase.java @@ -2,7 +2,6 @@ package com.yahoo.prelude.cluster; import com.google.common.collect.ImmutableList; -import com.yahoo.cloud.config.ClusterInfoConfig; import com.yahoo.component.ComponentId; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.container.QrConfig; @@ -518,7 +517,6 @@ public class ClusterSearcherTestCase { Dispatcher dispatcher = new Dispatcher(new RpcResourcePool(dispatchConfig), ComponentId.createAnonymousComponentId("test-id"), dispatchConfig, - createClusterInfoConfig(), vipStatus, new MockMetric()); ComponentRegistry<Dispatcher> dispatchers = new ComponentRegistry<>(); @@ -534,13 +532,6 @@ public class ClusterSearcherTestCase { null); } - private static ClusterInfoConfig createClusterInfoConfig() { - ClusterInfoConfig.Builder clusterInfoConfigBuilder = new ClusterInfoConfig.Builder(); - clusterInfoConfigBuilder.clusterId("containerCluster1"); - clusterInfoConfigBuilder.nodeCount(1); - return new ClusterInfoConfig(clusterInfoConfigBuilder); - } - private static class QueryTimeoutFixture { ClusterSearcher searcher; Execution exec; diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java index f46717ce180..22cc783967d 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/searchcluster/SearchClusterTest.java @@ -58,7 +58,7 @@ public class SearchClusterTest { numDocsPerNode.add(new AtomicInteger(1)); pingCounts.add(new AtomicInteger(0)); } - searchCluster = new SearchCluster(clusterId, MockSearchCluster.createDispatchConfig(nodes), nodes.size() / nodesPerGroup, + searchCluster = new SearchCluster(clusterId, MockSearchCluster.createDispatchConfig(nodes), vipStatus, new Factory(nodesPerGroup, numDocsPerNode, pingCounts)); clusterMonitor = new ClusterMonitor(searchCluster, false); searchCluster.addMonitoring(clusterMonitor); @@ -150,4 +150,9 @@ <module>zookeeper-server</module> </modules> + <properties> + <maven.deploy.skip>true</maven.deploy.skip> + <maven.javadoc.skip>true</maven.javadoc.skip> + </properties> + </project> |