Skip to content

SOLR-18094 Support running embedded-zk in "ensemble" mode with new node role#2391

Draft
gerlowskija wants to merge 60 commits into
apache:mainfrom
gerlowskija:spike-zk-quorum
Draft

SOLR-18094 Support running embedded-zk in "ensemble" mode with new node role#2391
gerlowskija wants to merge 60 commits into
apache:mainfrom
gerlowskija:spike-zk-quorum

Conversation

@gerlowskija
Copy link
Copy Markdown
Contributor

@gerlowskija gerlowskija commented Apr 5, 2024

Description

Prior to this commit, Solr only supported running embedded-ZK in "standalone" mode (which cannot take part in any larger ZK ensemble or quorum). But there are usecases that would benefit from being able to do this, both on the development and testing side, and even for adventurous users who might want the benefits of a small multi-node SolrCloud cluster without the headache of also deploying ZK.

See SIP-14, SOLR-15636 for context.

⚠️ Experimental / Alpha feature — this feature is intentionally rough and should not be used in production. The API and configuration format may change without notice.

Solution

This commit augments the embedded-ZK code to support running in "quorum" or ensemble mode. Multiple Solr nodes can now all have their embedded ZK join a multi-node quorum upon startup. Other than Solr and ZK sharing a process, the embedded-ZK ensemble behaves identically to one formed of independent processes.

Embedded-ensemble-ZK is enabled by assigning the new zookeeper_quorum node role (on/off) via the solr.node.roles system property, along with an explicit ZK host string containing all quorum members. Solr identifies which host in the ZK connection string it should be (based on host/port matching) and starts a ZooKeeperServerEmbedded instance in-process to join the ensemble. For example:

export LH="localhost"

# Run each below in a separate terminal, one for each host in the zk-conn string
bin/solr start -p 8983 -z $LH:9983,$LH:9984,$LH:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on
bin/solr start -p 8984 -z $LH:9983,$LH:9984,$LH:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on
bin/solr start -p 8985 -z $LH:9983,$LH:9984,$LH:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on

Note: ZK client port is solr_port + 1000, quorum port is zk_client_port + 1, election port is zk_client_port + 2.

Known limitations (Phase 1 / experimental):

  • Does not work with ZK's dynamic-ensemble feature — all ZK nodes must be specified in a static connection string at startup.
  • Quorum loss and recovery is not yet reliable (see testQuorumLossAndRecovery marked @AwaitsFix).
  • Requires that hostnames in the ZK connection string exactly match Solr's configured host (solr.host).
  • Runs best with the security manager disabled.
  • The configuration interface is rough and subject to change.

Tests

  • TestEmbeddedZkQuorum — basic quorum startup, collection creation, and node join/leave scenarios

Checklist

Please review the following and check all that apply:

  • I have reviewed the guidelines for How to Contribute and my code conforms to the standards described there to the best of my ability.
  • I have created a Jira issue and added the issue ID to my pull request title.
  • I have given Solr maintainers access to contribute to my PR branch. (optional but recommended)
  • I have developed this patch against the main branch.
  • I have run ./gradlew check.
  • I have added tests for my changes.
  • I have added documentation for the Reference Guide

…found" with an out-dated ClusterState (apache#2363)"

This reverts commit 5c399dd.
This commit augments our embedded-ZK code to support running embedded-ZK
in "quorum" or ensemble mode.  Multiple Solr nodes can now all have
their embedded-ZK's join a multi-node quorum upon startup.  Other than
Solr and ZK sharing a process, the embedded- ZK ensemble behaves
identically to one formed of independent processes: nodes can join or
leave the cluster, etc.

Embedded-ensemble-ZK is enabled any time the `zkQuorumRun` system
property is present, along with an explicitly specified ZK host string.
On startup, Solr will identify which host in the zk-conn-string it
should be (based on admittedly hacky heuristics), and then spins up a
'ZooKeeperServerEmbedded' instance in-process to join the ensemble. e.g.

```
export LH="localhost"
bin/solr start -p 8983 -z $LH:9983,$LH:9984,$LH:9985 -DzkQuorumRun
bin/solr start -p 8984 -z $LH:9983,$LH:9984,$LH:9985 -DzkQuorumRun
bin/solr start -p 8985 -z $LH:9983,$LH:9984,$LH:9985 -DzkQuorumRun
```

Some notes:
  - this doesn't (yet) work with ZK's dynamic-ensemble feature, so all
    ZK nodes must be specified in a static ZK conn string provided at
    startup
  - this appears to run best when the security-manager is disabled.
@gerlowskija
Copy link
Copy Markdown
Contributor Author

FYI: https://cwiki.apache.org/confluence/display/SOLR/SIP-14+Embedded+Zookeeper for context on others' interest in moving this direction.

@janhoy
Copy link
Copy Markdown
Contributor

janhoy commented Apr 29, 2024

Great work. I think we should rip out the existing embedded ZK, which is a hack.

Do you want to proceed in a PR or perhaps in a central feature branch?

@gerlowskija
Copy link
Copy Markdown
Contributor Author

Spent a few minutes pulling in the latest 'main'. Hoping to give it a bit more cleanup in the next few days if I can, but I've been hoping that for more than a year at this point (😬 ), so if anyone else is interested please feel free to move this forward!

@epugh
Copy link
Copy Markdown
Contributor

epugh commented Oct 14, 2025

@gerlowskija I took a stab at getting in the use of the solr roles to determine if we hsould run embedded zk quorum mode, and it worked! Here is my start script, where each runs with -f so you need three terminals. Omit the -f and you don't need the seperate terminals.

mkdir -p ./three_nodes/node1/solr
mkdir -p ./three_nodes/node2/solr
mkdir -p ./three_nodes/node3/solr

SOLR_SECURITY_MANAGER_ENABLED=false bin/solr start -f -p 8983 --solr-home "./three_nodes/node1/solr" -z localhost:9983,localhost:9984,localhost:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on
SOLR_SECURITY_MANAGER_ENABLED=false bin/solr start -f -p 8984 --solr-home "./three_nodes/node2/solr" -z localhost:9983,localhost:9984,localhost:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on
SOLR_SECURITY_MANAGER_ENABLED=false bin/solr start -f -p 8985 --solr-home "./three_nodes/node3/solr" -z localhost:9983,localhost:9984,localhost:9985 -Dsolr.node.roles=data:on,overseer:allowed,zookeeper_quorum:on

# Conflicts:
#	solr/core/src/java/org/apache/solr/core/ZkContainer.java
#	solr/packaging/build.gradle
@janhoy
Copy link
Copy Markdown
Contributor

janhoy commented Oct 15, 2025

  • Merged in main branch
  • Properly clean up the ZK server resource in close()

Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java
Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java
@epugh
Copy link
Copy Markdown
Contributor

epugh commented Oct 16, 2025

FYI, the .bats test worked a few times for me and then quit working ;-(

Uses a base class SolrCloudWithEmbeddedZkQuorumTestCase
New MiniSolrCloudCluster constructor that spins up a quorum cluster
Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java Outdated
Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java Outdated
Comment thread solr/packaging/build.gradle Outdated
@github-actions github-actions Bot added documentation Improvements or additions to documentation and removed dependencies Dependency upgrades tool:build labels May 11, 2026
@janhoy
Copy link
Copy Markdown
Contributor

janhoy commented May 11, 2026

I addressed Copilot's review points, then ran another review with Claude and addressed some of those concerns.

Added ref-guide docs, marked as "experimental":

Release-notes:
Skjermbilde 2026-05-11 kl  10 29 33

Zookeeper config:
Skjermbilde 2026-05-11 kl  10 21 03

Node roles:
Skjermbilde 2026-05-11 kl  10 22 07

Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java Outdated
Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java Outdated
Comment thread solr/core/src/java/org/apache/solr/core/ZkContainer.java Outdated
Single-machine example with consecutive Solr ports 8983/8984/8985 caused
ZK quorum/election port collisions (node N's quorum port = node N+1's client
port). Fix by separating the multi-machine and single-machine examples, and
using ports spaced ≥3 apart (8983, 8986, 8989) for the single-machine case.

bin/solr start -p 20000 $ZK $ROLES
bin/solr start -p 30000 $ZK $ROLES
bin/solr start -p 40000 $ZK $ROLES
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running three nodes like this causes all three embedded zookeepers to use exact same server/solr/zoo_home/data folder, which is not good of course.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed it it commit ccf6ec3 - appending -<port> to the zoo_home folder name.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, we can't do 8983, 8984,8985? That is definitly a conceptual change for all of us. I'm used to zk being 1000 more that my port...


|ZK leader election
|`zk_client_port + 2`
|9985
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modified the default ports used for quorum peer and leader election ports. They were something like client-port minus 3000 and minus 4000. Now they are +1 and +2. I feel we spread our port numbers too wide. But then after the change we got another problem that we could not start three test solr nodes on 8983, 8984, 8985, since the first one would occupy port 9983, 9984, 9985 for zookeeper.

I am willing to revert the +1, +2 to something else, but -3000 and -4000 seemed a bit arbitrary, why not +2000 and +3000 since client-port is +1000?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, after commenting elsewhere, I like your +2000 and +3000 idea.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d prefer if Solr occupied a more narrow port space, say within 100 ports total, so you could start Solr on 8000, 8100, 8200 and each instance would have ports close. Instead of node 1 using 8000, 9000, 10000, 11000, while node 2 using 8100, 9100, 10100, 11100….

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And come to think of it, each and every of these ports should probably be configurable individually even if they default to some port offset...

final Path zkDataHome =
Path.of(
EnvUtils.getProperty(
"solr.zookeeper.server.datadir", solrHome.resolve("zoo_data").toString()));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we normally keep constants like this inline or do we have somewhere we try to keep all sysprop-names for e.g. zookeeper together in one place?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cat:cloud documentation Improvements or additions to documentation test-framework tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants