-
Notifications
You must be signed in to change notification settings - Fork 852
SOLR-18330: RTG requests to TLOG can short-circuit #4697
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| title: > | ||
| Optimization: RTG requests to a TLOG leader replica shouldn't use an extra local HTTP hop. | ||
| type: changed | ||
| authors: | ||
| - name: David Smiley | ||
| links: | ||
| - name: SOLR-18330 | ||
| url: https://issues.apache.org/jira/browse/SOLR-18330 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -171,10 +171,8 @@ private List<String> findReplicas( | |
| .filter(replica -> replica.isActive(clusterState.getLiveNodes())) | ||
| .filter( | ||
| replica -> | ||
| !builder.onlyNrt | ||
| || (replica.getType() == Replica.Type.NRT | ||
| || (replica.getType() == Replica.Type.TLOG | ||
| && isShardLeader.test(replica)))) | ||
| !builder.onlyRtg | ||
| || (replica.getType() == Replica.Type.NRT || isShardLeader.test(replica))) | ||
| .collect(Collectors.toList()); | ||
| builder.replicaListTransformer.transform(list); | ||
| List<String> coreUrls = list.stream().map(Replica::getCoreUrl).collect(Collectors.toList()); | ||
|
|
@@ -275,7 +273,7 @@ static class Builder { | |
| private String collection; | ||
| private ZkStateReader zkStateReader; | ||
| private SolrParams params; | ||
| private boolean onlyNrt; | ||
| private boolean onlyRtg; | ||
|
Comment on lines
-278
to
+276
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. onlyNrt is misleading. |
||
| private ReplicaListTransformer replicaListTransformer; | ||
| private AllowListUrlChecker urlChecker; | ||
|
|
||
|
|
@@ -294,8 +292,9 @@ public Builder params(SolrParams params) { | |
| return this; | ||
| } | ||
|
|
||
| public Builder onlyNrt(boolean onlyNrt) { | ||
| this.onlyNrt = onlyNrt; | ||
| /** Replica can serve the most recent data (RealTimeGet capable). */ | ||
| public Builder onlyRtg(boolean onlyRtg) { | ||
| this.onlyRtg = onlyRtg; | ||
| return this; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -75,13 +75,10 @@ public class HttpShardHandler extends ShardHandler { | |
|
|
||
| /** | ||
| * If the request context map has an entry with this key and Boolean.TRUE as value, {@link | ||
| * #prepDistributed(ResponseBuilder)} will only include {@link | ||
| * org.apache.solr.common.cloud.Replica.Type#NRT} replicas as possible destination of the | ||
| * distributed request (or a leader replica of type {@link | ||
| * org.apache.solr.common.cloud.Replica.Type#TLOG}). This is used by the RealtimeGet handler, | ||
| * since other types of replicas shouldn't respond to RTG requests | ||
| * #prepDistributed(ResponseBuilder)} will only include replicas that serve the latest data. This | ||
| * is used by the {@link org.apache.solr.handler.RealTimeGetHandler} (RTG). | ||
| */ | ||
| public static final String ONLY_NRT_REPLICAS = "distribOnlyRealtime"; | ||
| public static final String ONLY_RTG_REPLICAS = "distribOnlyRealtime"; | ||
|
|
||
| /** | ||
| * This is a fake ShardResponse used internally to trigger the {@link #take(boolean)} method to | ||
|
|
@@ -496,7 +493,7 @@ public void prepDistributed(ResponseBuilder rb) { | |
|
|
||
| ReplicaSource replicaSource; | ||
| if (zkController != null) { | ||
| boolean onlyNrt = Boolean.TRUE.equals(req.getContext().get(ONLY_NRT_REPLICAS)); | ||
| boolean onlyRtg = Boolean.TRUE.equals(req.getContext().get(ONLY_RTG_REPLICAS)); | ||
|
|
||
| replicaSource = | ||
| new CloudReplicaSource.Builder() | ||
|
|
@@ -505,11 +502,11 @@ public void prepDistributed(ResponseBuilder rb) { | |
| .allowListUrlChecker(urlChecker) | ||
| .replicaListTransformer(replicaListTransformer) | ||
| .collection(cloudDescriptor.getCollectionName()) | ||
| .onlyNrt(onlyNrt) | ||
| .onlyRtg(onlyRtg) | ||
| .build(); | ||
| rb.slices = replicaSource.getSliceNames().toArray(new String[replicaSource.getSliceCount()]); | ||
|
|
||
| if (!rb.isForcedDistrib() && canShortCircuit(rb.slices, onlyNrt, params, cloudDescriptor)) { | ||
| if (!rb.isForcedDistrib() && canShortCircuit(rb.slices, onlyRtg, params, cloudDescriptor)) { | ||
| rb.isDistrib = false; | ||
| rb.shortCircuitedURL = | ||
| ZkCoreNodeProps.getCoreUrl(zkController.getBaseUrl(), coreDescriptor.getName()); | ||
|
|
@@ -528,7 +525,7 @@ public void prepDistributed(ResponseBuilder rb) { | |
| .allowListUrlChecker(AllowListUrlChecker.ALLOW_ALL) | ||
| .replicaListTransformer(NoOpReplicaListTransformer.INSTANCE) | ||
| .collection(cloudDescriptor.getCollectionName()) | ||
| .onlyNrt(false) | ||
| .onlyRtg(false) | ||
| .build(); | ||
| final String adjective = | ||
| (allActiveReplicaSource.getReplicasBySlice(i).isEmpty() ? "active" : "eligible"); | ||
|
|
@@ -574,21 +571,24 @@ private static String createSliceShardsStr(final List<String> shardUrls) { | |
| /** Can we avoid distributed search / coordinator? */ | ||
| private boolean canShortCircuit( | ||
| String[] slices, | ||
| boolean onlyNrtReplicas, | ||
| boolean onlyRtgReplicas, | ||
| SolrParams params, | ||
| CloudDescriptor cloudDescriptor) { | ||
| // Are we hosting the shard that this request is for, and are we active? If so, then handle it | ||
| // ourselves and make it a non-distributed request. | ||
| String ourSlice = cloudDescriptor.getShardId(); | ||
| String ourCollection = cloudDescriptor.getCollectionName(); | ||
| // Some requests may only be fulfilled by replicas of type Replica.Type.NRT | ||
| // Real-time requests may only be fulfilled by an NRT replica or the shard leader (e.g. a TLOG | ||
| // leader), matching the replica selection in CloudReplicaSource. | ||
| if (slices.length == 1 | ||
| && slices[0] != null | ||
| && (slices[0].equals(ourSlice) | ||
| || slices[0].equals( | ||
| ourCollection + "_" + ourSlice)) // handle the <collection>_<slice> format | ||
| && cloudDescriptor.getLastPublished() == Replica.State.ACTIVE | ||
| && (!onlyNrtReplicas || cloudDescriptor.getReplicaType() == Replica.Type.NRT)) { | ||
| && (!onlyRtgReplicas | ||
| || cloudDescriptor.getReplicaType() == Replica.Type.NRT | ||
| || cloudDescriptor.isLeader())) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change looks good to me. Though maybe we should have a utility method? Maybe if its gets used somewhere else. (Since this is a CloudDescriptor and the CloudReplicaSource change is using a Replica object, it can't be shared I guess) |
||
| // currently just a debugging parameter to check distrib search on a single node | ||
| boolean shortCircuit = params.getBool("shortCircuit", true); | ||
|
|
||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO tracing is a nice way to show the byproduct of this optimization. Without the optimization, there wold be another embedded span for another HTTP request |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| { | ||
| "phases": [ | ||
| { | ||
| "description": "phase 0", | ||
| "spans": [ | ||
| { | ||
| "name": "get:/{collection}/get", | ||
| "kind": "SERVER", | ||
| "db.instance": "tlogCollection", | ||
| "db.type": "solr", | ||
| "http.request.method": "GET", | ||
| "http.response.status_code": 200, | ||
| "http.url": "http://NORMALIZED/solr/tlogCollection/get", | ||
| "http.params": "ids=1&wt=javabin" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the TLOG check was needless and isn't friendly to custom/evolving replica types, even though admittedly unlikely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change looks good to me too. Would be cool to have a
isRealTime()utility.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it'd be nice to have a utility