diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-06-16 13:58:19 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-06-16 13:58:19 +0200 |
commit | 177e3837a6b5c0b257c215cc8e61c8907fea2efb (patch) | |
tree | b6b1888f4ee1f969794ea62acfb6f1ef04358c38 /container-search | |
parent | 5e00300349d15d4aad0df4ab0631a811df526b79 (diff) |
Improve timeout logic for docsum/search invokers
Diffstat (limited to 'container-search')
5 files changed, 49 insertions, 21 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java index 8b2457606ab..154defe7eb2 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/ProtobufSerialization.java @@ -33,15 +33,14 @@ import com.yahoo.vespa.objects.BufferSerializer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.function.Consumer; public class ProtobufSerialization { private static final int INITIAL_SERIALIZATION_BUFFER_SIZE = 10 * 1024; - static byte[] serializeSearchRequest(Query query, int hits, String serverId) { - return convertFromQuery(query, hits, serverId).toByteArray(); + static byte[] serializeSearchRequest(Query query, int hits, String serverId, double requestTimeout) { + return convertFromQuery(query, hits, serverId, requestTimeout).toByteArray(); } private static void convertSearchReplyErrors(Result target, List<SearchProtocol.Error> errors) { @@ -50,9 +49,9 @@ public class ProtobufSerialization { } } - static SearchProtocol.SearchRequest convertFromQuery(Query query, int hits, String serverId) { + static SearchProtocol.SearchRequest convertFromQuery(Query query, int hits, String serverId, double requestTimeout) { var builder = SearchProtocol.SearchRequest.newBuilder().setHits(hits).setOffset(query.getOffset()) - .setTimeout((int) query.getTimeLeft()); + .setTimeout((int) (requestTimeout * 1000)); var documentDb = query.getModel().getDocumentDb(); if (documentDb != null) { @@ -130,9 +129,10 @@ public class ProtobufSerialization { static SearchProtocol.DocsumRequest.Builder createDocsumRequestBuilder(Query query, String serverId, String summaryClass, - boolean includeQueryData) { + boolean includeQueryData, + double requestTimeout) { var builder = SearchProtocol.DocsumRequest.newBuilder() - .setTimeout((int) query.getTimeLeft()) + .setTimeout((int) (requestTimeout * 1000)) .setDumpFeatures(query.properties().getBoolean(Ranking.RANKFEATURES, false)); if (summaryClass != null) { diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java index 92726ef1415..4e13e265905 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcProtobufFillInvoker.java @@ -80,10 +80,12 @@ public class RpcProtobufFillInvoker extends FillInvoker { outstandingResponses = hitsByNode.size(); responses = new LinkedBlockingQueue<>(outstandingResponses); - var builder = ProtobufSerialization.createDocsumRequestBuilder(result.getQuery(), serverId, summaryClass, summaryNeedsQuery); + var timeout = TimeoutHelper.calculateTimeout(result.getQuery()); + var builder = ProtobufSerialization.createDocsumRequestBuilder( + result.getQuery(), serverId, summaryClass, summaryNeedsQuery, timeout.request()); for (Map.Entry<Integer, List<FastHit>> nodeHits : hitsByNode.entrySet()) { var payload = ProtobufSerialization.serializeDocsumRequest(builder, nodeHits.getValue()); - sendDocsumsRequest(nodeHits.getKey(), nodeHits.getValue(), payload, result); + sendDocsumsRequest(nodeHits.getKey(), nodeHits.getValue(), payload, result, timeout.client()); } } @@ -123,7 +125,8 @@ public class RpcProtobufFillInvoker extends FillInvoker { } /** Send a docsums request to a node. Responses will be added to the given receiver. */ - private void sendDocsumsRequest(int nodeId, List<FastHit> hits, byte[] payload, Result result) { + private void sendDocsumsRequest(int nodeId, List<FastHit> hits, byte[] payload, Result result, + double clientTimeout) { Client.NodeConnection node = resourcePool.getConnection(nodeId); if (node == null) { String error = "Could not fill hits from unknown node " + nodeId; @@ -134,10 +137,9 @@ public class RpcProtobufFillInvoker extends FillInvoker { } Query query = result.getQuery(); - double timeoutSeconds = ((double) query.getTimeLeft() - 3.0) / 1000.0; Compressor.Compression compressionResult = resourcePool.compress(query, payload); - node.request(RPC_METHOD, compressionResult.type(), payload.length, compressionResult.data(), roe -> receive(roe, hits), - timeoutSeconds); + node.request(RPC_METHOD, compressionResult.type(), payload.length, compressionResult.data(), + roe -> receive(roe, hits), clientTimeout); } private void processResponses(Result result, String summaryClass) throws TimeoutException { diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java index 973b9093d9d..51127dc5416 100644 --- a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/RpcSearchInvoker.java @@ -56,25 +56,25 @@ public class RpcSearchInvoker extends SearchInvoker implements Client.ResponseRe } query.trace(false, 5, "Sending search request with jrt/protobuf to node with dist key ", node.key()); - RpcContext context = getContext(incomingContext); - double timeoutSeconds = ((double) query.getTimeLeft() - 3.0) / 1000.0; + var timeout = TimeoutHelper.calculateTimeout(query); + RpcContext context = getContext(incomingContext, timeout.request()); nodeConnection.request(RPC_METHOD, context.compressedPayload.type(), context.compressedPayload.uncompressedSize(), context.compressedPayload.data(), this, - timeoutSeconds); + timeout.client()); return context; } - private RpcContext getContext(Object incomingContext) { + private RpcContext getContext(Object incomingContext, double requestTimeout) { if (incomingContext instanceof RpcContext) return (RpcContext)incomingContext; return new RpcContext(resourcePool, query, ProtobufSerialization.serializeSearchRequest(query, Math.min(query.getHits(), maxHits), - searcher.getServerId())); + searcher.getServerId(), requestTimeout)); } @Override diff --git a/container-search/src/main/java/com/yahoo/search/dispatch/rpc/TimeoutHelper.java b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/TimeoutHelper.java new file mode 100644 index 00000000000..a48ff8cc1a7 --- /dev/null +++ b/container-search/src/main/java/com/yahoo/search/dispatch/rpc/TimeoutHelper.java @@ -0,0 +1,26 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.search.dispatch.rpc; + +import com.yahoo.search.Query; + +/** + * @author bjorncs + */ +class TimeoutHelper { + + private TimeoutHelper() {} + + static Timeout calculateTimeout(Query q) { + long timeLeftMillis = q.getTimeLeft(); + if (timeLeftMillis <= 2) return new Timeout(0d, 0d); + // The old timeout logic subtracted 3ms to timeout for client timeout. + // 3ms equalled to 0.6% of the default query timeout (500ms). + // This accounted for cost of network and container post-processing. + // New logic subtracts 1% for client and 2% for content node (request). + double clientTimeout = Math.max(timeLeftMillis * 0.99d, 2d) / 1000d; + double requestTimeout = Math.max(timeLeftMillis * 0.98d, 1d) / 1000d; + return new Timeout(requestTimeout, clientTimeout); + } + + record Timeout(double request, double client) {} +} diff --git a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java index 7a7ae173766..9953d1467e1 100644 --- a/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java +++ b/container-search/src/test/java/com/yahoo/search/dispatch/rpc/ProtobufSerializationTest.java @@ -35,7 +35,7 @@ public class ProtobufSerializationTest { .setRequest("?query=test&ranking.features.query(tensor_1)=[1.200]") .build(); - SearchProtocol.SearchRequest request1 = ProtobufSerialization.convertFromQuery(query, 9,"serverId"); + SearchProtocol.SearchRequest request1 = ProtobufSerialization.convertFromQuery(query, 9,"serverId", 0.5); assertEquals(9, request1.getHits()); assertEquals(0, request1.getRankPropertiesCount()); assertEquals(0, request1.getTensorRankPropertiesCount()); @@ -47,7 +47,7 @@ public class ProtobufSerializationTest { contentsOf(request1.getTensorFeatureOverrides(1).getValue())); query.prepare(); // calling prepare() moves "overrides" to "features" - content stays the same - SearchProtocol.SearchRequest request2 = ProtobufSerialization.convertFromQuery(query, 9,"serverId"); + SearchProtocol.SearchRequest request2 = ProtobufSerialization.convertFromQuery(query, 9,"serverId", 0.5); assertEquals(9, request2.getHits()); assertEquals(0, request2.getRankPropertiesCount()); assertEquals(2, request2.getTensorRankPropertiesCount()); @@ -62,7 +62,7 @@ public class ProtobufSerializationTest { @Test public void testDocsumSerialization() { Query q = new Query("search/?query=test&hits=10&offset=3"); - var builder = ProtobufSerialization.createDocsumRequestBuilder(q, "server", "summary", true); + var builder = ProtobufSerialization.createDocsumRequestBuilder(q, "server", "summary", true, 0.5); builder.setTimeout(0); var hit = new FastHit(); hit.setGlobalId(new GlobalId(IdString.createIdString("id:ns:type::id")).getRawId()); |