-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
[Segment Replication] Rolling upgrade support for default codecs #7698
Conversation
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
server/src/main/java/org/opensearch/index/engine/NRTReplicationEngineFactory.java
Outdated
Show resolved
Hide resolved
try { | ||
if (indexShardList.isEmpty() == false) { | ||
for (IndexShard is : indexShardList) { | ||
is.resetEngineToGlobalCheckpoint(); | ||
} | ||
} | ||
} catch (Exception e) { | ||
logger.error("Received unexpected exception: [{}]", e.getMessage()); | ||
} |
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.
Will this cause disruptions during upgrades?
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.
Throughput will be impacted but we will still queue incoming requests that come in while the switch of index writer is taking place and process them when it's back up.
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.
Is there a test around this that can confirm the same? Can we run some benchmarks/test to see the impact on performance
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.
Ran 2 benchmarks to confirm on nyc_taxis dataset - saw a 0% error rate and a 0.01% error rate on indexing respectively.
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationUpgradeListener.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/IndicesService.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationUpgradeListener.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationUpgradeListener.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/index/codec/CodecService.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationUpgradeListener.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationUpgradeListener.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/index/engine/NRTReplicationEngineFactory.java
Show resolved
Hide resolved
server/src/main/java/org/opensearch/index/engine/InternalEngine.java
Outdated
Show resolved
Hide resolved
server/src/main/java/org/opensearch/indices/replication/SegmentReplicationTargetService.java
Outdated
Show resolved
Hide resolved
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
/** | ||
* Returns <code>true</code> if a version upgrade has taken place in the cluster | ||
*/ | ||
public boolean clusterUpgraded() { |
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.
Rename to something better maybe hasMixedVersionNodes
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.
We're using this method to check that cluster upgrade has been completed - it checks if it used to have mixed version nodes and current state does not. hasMixedVersionNodes
might be misleading in this case.
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.
clusterUpgraded
is equivalent to NOT hasMixedVersionNodes
.
server/src/main/java/org/opensearch/index/codec/CodecService.java
Outdated
Show resolved
Hide resolved
Gradle Check (Jenkins) Run Completed with:
|
Gradle Check (Jenkins) Run Completed with:
|
Signed-off-by: Poojita Raj <[email protected]>
Signed-off-by: Poojita Raj <[email protected]>
Signed-off-by: Poojita Raj <[email protected]>
Signed-off-by: Poojita Raj <[email protected]>
Gradle Check (Jenkins) Run Completed with:
|
versionStringMap.put(Version.fromString("3.0.0"), "Lucene95"); | ||
versionStringMap.put(Version.fromString("2.8.0"), "Lucene95"); | ||
versionStringMap.put(Version.fromString("2.7.1"), "Lucene95"); | ||
versionStringMap.put(Version.fromString("2.7.0"), "Lucene95"); |
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.
- nit: Rather than having specific call, we can static initialize this map. This is due to the fact we are calling this inside class ctor, I don't see advantage of lazy loading.
public static final Map<Version, String> opensearchVersionToLuceneCodec;
static {
Map<Version, String> versionStringMap = new HashMap<>();
versionStringMap.put(Version.fromString("3.0.0"), "Lucene95");
...
opensearchVersionToLuceneCodec = Collections.unmodifiableMap(new HashMap<>(versionStringMap));
}
- Can we build this map reading in Version.java, as this info is present there. This will prevent future maintenance of version <-> lucene codec map. I know this is not straightforward as Lucene version bumps doesn't necessarily mean codec bumps. We can take this in follow up PR.
@@ -71,6 +82,11 @@ public ReplicationCheckpoint(StreamInput in) throws IOException { | |||
length = 0L; | |||
codec = null; | |||
} | |||
if (in.getVersion().onOrAfter(Version.V_2_8_0)) { |
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.
- For main branch (this PR). This needs to be changed to
3.0.0
or else this will break bwc tests (if any is exercising this code) because this field is not yet present in2.x
2.9.0 branch. Reading from or sending to, this field to 2.9.0 node will fail. - On 2.x backport, change this back to
2.9.0
. - Additional Step/PR. Change
main
to use2.9.0
after PR in step 2 is merged.
@@ -58,8 +61,11 @@ public class CodecService { | |||
public static final String BEST_COMPRESSION_CODEC = "best_compression"; | |||
/** the raw unfiltered lucene default. useful for testing */ | |||
public static final String LUCENE_DEFAULT_CODEC = "lucene_default"; | |||
static Map<Version, String> versionStringMap = new HashMap<>(); |
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.
nit: This variable declaration can go inside loadMap()
as it is only used to init opensearchVersionToLuceneCodec
. It doesn't need to be static
@@ -58,8 +61,11 @@ public class CodecService { | |||
public static final String BEST_COMPRESSION_CODEC = "best_compression"; | |||
/** the raw unfiltered lucene default. useful for testing */ | |||
public static final String LUCENE_DEFAULT_CODEC = "lucene_default"; | |||
static Map<Version, String> versionStringMap = new HashMap<>(); | |||
public static Map<Version, String> opensearchVersionToLuceneCodec; |
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.
nit: opensearchVersionToLuceneCodec
-> versionToCodecMap
. There are integrations which overrides Lucene codecs.
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 variable can be scoped protected that still allows integrations overriding CodecService to provide their own mapping
@@ -170,6 +174,33 @@ public void clusterChanged(ClusterChangedEvent event) { | |||
} | |||
} | |||
} | |||
if (event.clusterUpgraded()) { | |||
List<IndexShard> indexShardList = new ArrayList<>(); |
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.
nit: final ?
for (IndexShard indexShard : indexService) { | ||
try { | ||
if (indexShard.routingEntry().primary() | ||
&& (indexShard.getEngine().config().getClusterMinVersion() != nodes.getMaxNodeVersion())) { |
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.
- For large clusters (100s of nodes), it is not uncommon to have few nodes running on older OS version, which means running primary shard in bwc for extended period, in worst case forever. I am not sure about the end result of the state. As an improvement, can this switch be performed when nodes containing all shard copies are upgraded.
- Performing this engine switch gradually also make more sense versus do it all at once. The user may see indexing requests getting piled up, when upgrade completes.
- Need tests.
@@ -131,6 +154,9 @@ public void writeTo(StreamOutput out) throws IOException { | |||
out.writeLong(length); | |||
out.writeString(codec); | |||
} | |||
if (out.getVersion().onOrAfter(Version.V_2_8_0)) { |
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.
Same as above.
Thanks @Poojita-Raj for working on this. Few top level comments. Lucene major version upgradesI think Lucene does not allow wiring in previous major version codecs with IndexWriter. For e.g. I see using Older codecs provided during index creationToday, we allow users to provide older codec names as is during index creation. e.g
|
try { | ||
if (indexShardList.isEmpty() == false) { | ||
for (IndexShard indexShard : indexShardList) { | ||
indexShard.resetEngine(); |
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.
Engine reset is not required when there is no codec change. This change will unnecessarily impact end users post upgrade (delay operations) when it is not really needed.
Version localNodeVersion = Version.CURRENT; | ||
// if replica's OS version is not on or after primary version, then can ignore checkpoint | ||
if (localNodeVersion.onOrAfter(receivedCheckpoint.getMinVersion()) == false) { | ||
logger.trace( | ||
() -> new ParameterizedMessage( | ||
"Ignoring checkpoint, shard not started {} {}\n Shard does not support the received lucene codec version {}", | ||
receivedCheckpoint, | ||
replicaShard.state(), | ||
receivedCheckpoint.getCodec() | ||
) | ||
); | ||
return; | ||
} |
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 check should go inside shouldProcessCheckpoint
containing other validations around processing checkpoint.
() -> new ParameterizedMessage( | ||
"Ignoring checkpoint, shard not started {} {}\n Shard does not support the received lucene codec version {}", | ||
receivedCheckpoint, | ||
replicaShard.state(), | ||
receivedCheckpoint.getCodec() |
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.
() -> new ParameterizedMessage( | |
"Ignoring checkpoint, shard not started {} {}\n Shard does not support the received lucene codec version {}", | |
receivedCheckpoint, | |
replicaShard.state(), | |
receivedCheckpoint.getCodec() | |
() -> new ParameterizedMessage( | |
"Ignoring checkpoint {} as shard does not support the received lucene codec version {}", | |
receivedCheckpoint, | |
receivedCheckpoint.getCodec() |
Verified that using previous major latest lucene codecs is not allowed and any indexing operation fails with Step 1. Create index with older lucene index using current lucene version 9x (any of above 3)
Step 2. Index operation
It appears lucene only allows codecs which are part of core lucene library and older/bwc codecs are only meant for reading the older segments. |
Closing until a decision is made on what approach to take with rolling upgrades with segment replication enabled. |
Description
Supports rolling upgrade for default codecs
Related Issues
Resolves #7349
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.