This is an automated email from the ASF dual-hosted git repository. nkalmar pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/zookeeper.git
The following commit(s) were added to refs/heads/master by this push: new b1105cc ZOOKEEPER-3758: Leader reachability check fails with single address b1105cc is described below commit b1105ccc47685c64d1cca7ccb0b2bb66c194374a Author: Mate Szalay-Beko <szalay.beko.m...@gmail.com> AuthorDate: Thu Mar 19 17:09:38 2020 +0100 ZOOKEEPER-3758: Leader reachability check fails with single address Since ZooKeeper 3.6.0 we can specify multiple addresses for each ZooKeeper server instance (this can increase availability when multiple physical network interfaces can be used parallel in the cluster). ZooKeeper will perform ICMP ECHO requests or try to establish a TCP connection on port 7 (Echo) of the destination host in order to find the reachable addresses. This should happen only if the user provide multiple addresses in the configuration, in a single address is used then ZooKeeper shouldn’t send any ICMP requests. This works as we expected for the leader election connections, but in this Jira issue we found a bug when the reachability check was performed even with a single address when the Follower tries to connect to the newly elected Leader. The fix follows the same approach we discussed for the election protocol before (see ZOOKEEPER-3698). We avoid the reachability check for single addresses. Also when we have multiple addresses and none of them can be reached, we still start to connect to all addresses in parallel. Author: Mate Szalay-Beko <szalay.beko.m...@gmail.com> Reviewers: Enrico Olivelli <eolive...@apache.org>, Norbert Kalmar <nkal...@apache.org> Closes #1288 from symat/ZOOKEEPER-3758 --- .../apache/zookeeper/server/quorum/Learner.java | 4 +++- .../zookeeper/server/quorum/MultipleAddresses.java | 18 +++++++++++++++ .../server/quorum/MultipleAddressesTest.java | 26 ++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java index 0f8f444..8a0cac1 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/Learner.java @@ -303,7 +303,9 @@ public class Learner { this.leaderAddr = multiAddr; Set<InetSocketAddress> addresses; if (self.isMultiAddressReachabilityCheckEnabled()) { - addresses = multiAddr.getAllReachableAddresses(); + // even if none of the addresses are reachable, we want to try to establish connection + // see ZOOKEEPER-3758 + addresses = multiAddr.getAllReachableAddressesOrAll(); } else { addresses = multiAddr.getAllAddresses(); } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java index 3ee63fa..9f15389 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/MultipleAddresses.java @@ -140,6 +140,24 @@ public final class MultipleAddresses { } /** + * Returns a set of all reachable addresses. If none is reachable than returns all addresses. + * + * @return all reachable addresses, or all addresses if none is reachable. + */ + public Set<InetSocketAddress> getAllReachableAddressesOrAll() { + // if there is only a single address provided then we don't need to do any reachability check + if (addresses.size() == 1) { + return getAllAddresses(); + } + + Set<InetSocketAddress> allReachable = getAllReachableAddresses(); + if (allReachable.isEmpty()) { + return getAllAddresses(); + } + return allReachable; + } + + /** * Returns a reachable address or an arbitrary one, if none is reachable. It throws an exception * if there are no addresses registered. The function is nondeterministic in the sense that the * result of calling this function twice with the same set of reachable addresses might lead diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java index e8f08c6..0e1615d 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/MultipleAddressesTest.java @@ -188,6 +188,32 @@ public class MultipleAddressesTest { } @Test + public void testGetAllReachableAddressesOrAllWhenSomeReachable() throws Exception { + InetSocketAddress reachableHost1 = new InetSocketAddress("127.0.0.1", 1234); + InetSocketAddress reachableHost2 = new InetSocketAddress("127.0.0.1", 2345); + InetSocketAddress unreachableHost1 = new InetSocketAddress("unreachable1.address.zookeeper.apache.com", 1234); + InetSocketAddress unreachableHost2 = new InetSocketAddress("unreachable2.address.zookeeper.apache.com", 1234); + + MultipleAddresses multipleAddresses = new MultipleAddresses( + Arrays.asList(unreachableHost1, unreachableHost2, reachableHost1, reachableHost2)); + + Set<InetSocketAddress> reachableHosts = new HashSet<>(Arrays.asList(reachableHost1, reachableHost2)); + Assert.assertEquals(reachableHosts, multipleAddresses.getAllReachableAddressesOrAll()); + } + + @Test + public void testGetAllReachableAddressesOrAllWhenNoneReachable() throws Exception { + InetSocketAddress unreachableHost1 = new InetSocketAddress("unreachable1.address.zookeeper.apache.com", 1234); + InetSocketAddress unreachableHost2 = new InetSocketAddress("unreachable2.address.zookeeper.apache.com", 1234); + InetSocketAddress unreachableHost3 = new InetSocketAddress("unreachable3.address.zookeeper.apache.com", 1234); + List<InetSocketAddress> allUnreachableAddresses = Arrays.asList(unreachableHost1, unreachableHost2, unreachableHost3); + + MultipleAddresses multipleAddresses = new MultipleAddresses(allUnreachableAddresses); + + Assert.assertEquals(new HashSet<>(allUnreachableAddresses), multipleAddresses.getAllReachableAddressesOrAll()); + } + + @Test public void testEquals() { List<InetSocketAddress> addresses = getAddressList();