Skip to content

Commit 79e3223

Browse files
committed
ZOOKEEPER-3100. Add feature flag with false default value
1 parent 1bc8d94 commit 79e3223

File tree

4 files changed

+63
-1
lines changed

4 files changed

+63
-1
lines changed

zookeeper-docs/src/main/resources/markdown/zookeeperProgrammers.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,6 +1381,22 @@ and [SASL authentication for ZooKeeper](https://cwiki.apache.org/confluence/disp
13811381
* *zookeeper.kinit* :
13821382
Specifies path to kinit binary. Default is "/usr/bin/kinit".
13831383
1384+
* *zookeeper.shuffleDnsResponse* :
1385+
**New in 3.10.0:**
1386+
Specifies whether ZooKeeper client should randomly pick an IP address from the DNS lookup query result when resolving
1387+
server addresses or not. This is a feature flag in order to keep the old behavior of the default DNS resolver in
1388+
`StaticHostProvider`, because we disabled it by default. The reason behind that is shuffling the response of DNS queries
1389+
shadows JVM network property `java.net.preferIPv6Addresses` (default: false). This property controls whether JVM's built-in
1390+
resolver should prioritize v4 (false value) or v6 (true value) addresses when putting together the list of IP addresses
1391+
in the result. In other words the above Java system property was completely ineffective in the case of ZooKeeper server host
1392+
resolution protocol and this must have been fixed. In a dual stack environment one might want to prefer one stack over
1393+
the other which, in case of Java processes, should be controlled by JVM network properties and ZooKeeper must honor
1394+
these settings. Since the old behavior has been with us since day zero, we introduced this feature flag in case you
1395+
need it. Such case could be when you have a buggy DNS server which responds IP addresses always in the same order and
1396+
you want to randomize that.
1397+
Default: false
1398+
1399+
13841400
<a name="C+Binding"></a>
13851401
13861402
### C Binding

zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,7 @@ public ZooKeeper(ZooKeeperOptions options) throws IOException {
11401140
if (options.getHostProvider() != null) {
11411141
hostProvider = options.getHostProvider().apply(connectStringParser.getServerAddresses());
11421142
} else {
1143-
hostProvider = new StaticHostProvider(connectStringParser.getServerAddresses());
1143+
hostProvider = new StaticHostProvider(connectStringParser.getServerAddresses(), clientConfig);
11441144
}
11451145
this.hostProvider = hostProvider;
11461146

zookeeper-server/src/main/java/org/apache/zookeeper/client/StaticHostProvider.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ public interface Resolver {
5050

5151
private static final Logger LOG = LoggerFactory.getLogger(StaticHostProvider.class);
5252

53+
private ZKClientConfig clientConfig = null;
54+
5355
private List<InetSocketAddress> serverAddresses = new ArrayList<>(5);
5456

5557
private Random sourceOfRandomness;
@@ -90,6 +92,26 @@ public InetAddress[] getAllByName(String name) throws UnknownHostException {
9092
});
9193
}
9294

95+
/**
96+
* Constructs a SimpleHostSet with ZKClientConfig.
97+
*
98+
* Introduced this new overload in 3.10.0 in order to take advantage of some newly introduced feature flags. Like
99+
* the shuffle (old) / not to shuffle (new) behavior of DNS resolution.
100+
*
101+
* @param serverAddresses
102+
* possibly unresolved ZooKeeper server addresses
103+
* @param clientConfig
104+
* ZooKeeper client configuration
105+
*/
106+
public StaticHostProvider(Collection<InetSocketAddress> serverAddresses, ZKClientConfig clientConfig) {
107+
init(serverAddresses, System.currentTimeMillis() ^ this.hashCode(), new Resolver() {
108+
@Override
109+
public InetAddress[] getAllByName(String name) throws UnknownHostException {
110+
return InetAddress.getAllByName(name);
111+
}
112+
}, clientConfig);
113+
}
114+
93115
/**
94116
* Constructs a SimpleHostSet.
95117
*
@@ -125,6 +147,12 @@ public InetAddress[] getAllByName(String name) throws UnknownHostException {
125147
}
126148

127149
private void init(Collection<InetSocketAddress> serverAddresses, long randomnessSeed, Resolver resolver) {
150+
init(serverAddresses, randomnessSeed, resolver, null);
151+
}
152+
153+
private void init(Collection<InetSocketAddress> serverAddresses, long randomnessSeed, Resolver resolver,
154+
ZKClientConfig clientConfig) {
155+
this.clientConfig = clientConfig == null ? new ZKClientConfig() : clientConfig;
128156
this.sourceOfRandomness = new Random(randomnessSeed);
129157
this.resolver = resolver;
130158
if (serverAddresses.isEmpty()) {
@@ -142,6 +170,9 @@ private InetSocketAddress resolve(InetSocketAddress address) {
142170
if (resolvedAddresses.isEmpty()) {
143171
return address;
144172
}
173+
if (clientConfig.isShuffleDnsResponseEnabled()) {
174+
Collections.shuffle(resolvedAddresses);
175+
}
145176
return new InetSocketAddress(resolvedAddresses.get(0), address.getPort());
146177
} catch (UnknownHostException e) {
147178
LOG.error("Unable to resolve address: {}", address.toString(), e);

zookeeper-server/src/main/java/org/apache/zookeeper/client/ZKClientConfig.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,13 @@ public class ZKClientConfig extends ZKConfig {
6262
public static final long ZOOKEEPER_REQUEST_TIMEOUT_DEFAULT = 0;
6363
public static final String ZK_SASL_CLIENT_ALLOW_REVERSE_DNS = "zookeeper.sasl.client.allowReverseDnsLookup";
6464
public static final boolean ZK_SASL_CLIENT_ALLOW_REVERSE_DNS_DEFAULT = false;
65+
/**
66+
* True value preserves the old behavior is to shuffle the addresses in DNS response regardless of address type.
67+
* This could help with buggy DNS servers which always return addresses in the same order, but at the same time
68+
* ignores the JVM option java.net.preferIPv6Addresses.
69+
*/
70+
public static final String ZOOKEEPER_SHUFFLE_DNS_RESPONSE = "zookeeper.shuffleDnsResponse";
71+
public static final boolean ZOOKEEPER_SHUFFLE_DNS_RESPONSE_DEFAULT = false;
6572

6673
public ZKClientConfig() {
6774
super();
@@ -137,6 +144,14 @@ public boolean isSaslClientEnabled() {
137144
return Boolean.valueOf(getProperty(ENABLE_CLIENT_SASL_KEY, ENABLE_CLIENT_SASL_DEFAULT));
138145
}
139146

147+
/**
148+
* Return true if we need to use the old behavior of default DNS resolver and always shuffle the IP addresses
149+
* in the DNS lookup response in order to pick a completely random IP address.
150+
*/
151+
public boolean isShuffleDnsResponseEnabled() {
152+
return getBoolean(ZOOKEEPER_SHUFFLE_DNS_RESPONSE, ZOOKEEPER_SHUFFLE_DNS_RESPONSE_DEFAULT);
153+
}
154+
140155
/**
141156
* Get the value of the <code>key</code> property as an <code>long</code>.
142157
* If property is not set, the provided <code>defaultValue</code> is

0 commit comments

Comments
 (0)