Zookeeper客户端使用:
- 使用DefaultZookeeperFactory创建默认的Zookeeper;
DefaultZookeeperFactory factory = new DefaultZookeeperFactory();
factory.newZooKeeper(connectString, sessionTimeout, null, false);
2. 直接使用Zookeeper的构造函数;
ZooKeeper zookeeper = new ZooKeeper(connectString, sessionTimeout, (event)->{}, clientConfig);
如果所有采用默认的配置,在创建Zookeeper后建立连接时,Zookeeper的SendThread在建立连接时,startConnect()函数,先判断是否采用SASL连接,默认情况下回使用SASL连接,即创建ZooKeeperSaslClient对象。如果未配置SASL,此过程会阻塞正常与Zookeeper的连接创建,导致Zookeeper对象创建后不能立即建立与Zookeeper的连接,因此为了加快建立与Zookeeper的连接,需要将相关参数修改。
ZKClientConfig clientConfig = new ZKClientConfig();
clientConfig.setProperty("zookeeper.sasl.client", "false");
ZooKeeper zooKeeper =new ZooKeeper(connectString, sessionTimeout, (event)->{}, clientConfig);
ClientCnxn类中SendThread的startConnect方法:
private void startConnect(InetSocketAddress addr) throws IOException {
// initializing it for new connection
saslLoginFailed = false;
if (!isFirstConnect) {
try {
Thread.sleep(r.nextInt(1000));
} catch (InterruptedException e) {
LOG.warn("Unexpected exception", e);
}
}
state = States.CONNECTING;
String hostPort = addr.getHostString() + ":" + addr.getPort();
MDC.put("myid", hostPort);
setName(getName().replaceAll("\\(.*\\)", "(" + hostPort + ")"));
if (clientConfig.isSaslClientEnabled()) {
try {
if (zooKeeperSaslClient != null) {
zooKeeperSaslClient.shutdown();
}
zooKeeperSaslClient = new ZooKeeperSaslClient(SaslServerPrincipal.getServerPrincipal(addr, clientConfig), clientConfig);
} catch (LoginException e) {
// An authentication error occurred when the SASL client tried to initialize:
// for Kerberos this means that the client failed to authenticate with the KDC.
// This is different from an authentication error that occurs during communication
// with the Zookeeper server, which is handled below.
LOG.warn(
"SASL configuration failed. "
+ "Will continue connection to Zookeeper server without "
+ "SASL authentication, if Zookeeper server allows it.", e);
eventThread.queueEvent(new WatchedEvent(Watcher.Event.EventType.None, Watcher.Event.KeeperState.AuthFailed, null));
saslLoginFailed = true;
}
}
logStartConnect(addr);
clientCnxnSocket.connect(addr);
}
对比zoookeeper3.4.X版本与3.5.X版本:
3.5.X版本:
if (clientConfig.isSaslClientEnabled()) {
try {
if (zooKeeperSaslClient != null) {
zooKeeperSaslClient.shutdown();
}
zooKeeperSaslClient = new ZooKeeperSaslClient(getServerPrincipal(addr), clientConfig);
} catch (LoginException e) {
private String getServerPrincipal(InetSocketAddress addr) {
String principalUserName = clientConfig.getProperty(ZKClientConfig.ZK_SASL_CLIENT_USERNAME,
ZKClientConfig.ZK_SASL_CLIENT_USERNAME_DEFAULT);
String serverPrincipal = principalUserName + "/" + addr.getHostString();
return serverPrincipal;
}
3.4.X版本:
if (ZooKeeperSaslClient.isEnabled()) {
try {
zooKeeperSaslClient = new ZooKeeperSaslClient(SaslServerPrincipal.getServerPrincipal(addr));
} catch (LoginException e) {
// An authentication error occurred when the SASL client tried to initialize:
// for Kerberos this means that the client failed to authenticate with the KDC.
// This is different from an authentication error that occurs during communication
// with the Zookeeper server, which is handled below.
LOG.warn("SASL configuration failed: " + e + " Will continue connection to Zookeeper server without "
+ "SASL authentication, if Zookeeper server allows it.");
eventThread.queueEvent(new WatchedEvent(
Watcher.Event.EventType.None,
Watcher.Event.KeeperState.AuthFailed, null));
saslLoginFailed = true;
}
}
static String getServerPrincipal(WrapperInetSocketAddress addr) {
String principalUserName = System.getProperty(ZK_SASL_CLIENT_USERNAME, "zookeeper");
String hostName = addr.getHostName();
boolean canonicalize = true;
String canonicalizeText = System.getProperty(ZK_SASL_CLIENT_CANONICALIZE_HOSTNAME, "true");
try {
canonicalize = Boolean.parseBoolean(canonicalizeText);
} catch (IllegalArgumentException ea) {
LOG.warn("Could not parse config {} \"{}\" into a boolean using default {}",
ZK_SASL_CLIENT_CANONICALIZE_HOSTNAME, canonicalizeText, canonicalize);
}
if (canonicalize) {
WrapperInetAddress ia = addr.getAddress();
if (ia == null) {
throw new IllegalArgumentException("Unable to canonicalize address " + addr + " because it's not resolvable");
}
String canonicalHostName = ia.getCanonicalHostName();
//avoid using literal IP address when security check fails
if (!canonicalHostName.equals(ia.getHostAddress())) {
hostName = canonicalHostName;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Canonicalized address to {}", hostName);
}
}
String serverPrincipal = principalUserName + "/" + hostName;
return serverPrincipal;
}
两个版本的主要区别在与:3.4.X版本会去解析域名,导致创建了Zookeeper时,延迟创建连接。