https://juejin.cn/post/6844903822771355655
https://blog.csdn.net/qq_24434251/article/details/119055534
https://blog.csdn.net/qq_32252917/article/details/89168096
首先描述一下问题状况:项目后期规划使用zookeeper做分布式服务配置中心,使用Curator作为客户端中间件操作访问zookeeper. 在测试验证阶段,无限“Will not attempt to authenticate using SASL (unknown error)”流让本人崩溃到泪流满面。“SASL”什么鬼?!本人没有设置过“SASL”的说!!!
环境说明:
zookeeper: 3.5.5
curator: 4.2.0
原因猜测:
查看日志,知道“Will not attempt to authenticate using SASL (unknown error)”的锅。然后各种google,度娘,有各式原因都有,例如因为本地IP映射问题,需要该本地host文件等。本人未采用SASL认证模式,而是使用了简单的digest认证模式。所以排除本地IP映射问题。此外个人觉得修改本地host文件本身不是一个合理的举措。最后只能追本溯源,得嘞,还是乖乖看一下源码吧。
org.apache.zookeeper.ClientCnxn 类中有一段代码如下:
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: " + 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;
}
}
logStartConnect(addr);
clientCnxnSocket.connect(addr);
}复制代码
其中clientConfig.isSaslClientEnabled() 引起我的注意,在查看一下它的实现:
public boolean isSaslClientEnabled() {
return Boolean.valueOf(getProperty(ENABLE_CLIENT_SASL_KEY, ENABLE_CLIENT_SASL_DEFAULT));
}复制代码
发现它默认是true.
最后找到Curator配置生成zookeeper客户端实例的代码 (Curator通过ZookeeperFactory来创建zookeeper客户端实例的)
package org.apache.curator.utils;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
public class DefaultZookeeperFactory implements ZookeeperFactory
{
@Override
public ZooKeeper newZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly) throws Exception
{
return new ZooKeeper(connectString, sessionTimeout, watcher, canBeReadOnly);
}
} 复制代码
好吧,看来Curator默认啥都没配置,那么它就直奔默认值true去了。
解决方案:
解决方案其实就一句话,将ENABLE_CLIENT_SASL_KEY值变成false. 问题是怎么才能在Curator中将其设置为false. 答案还在ZookeeperFactory. 可以在创建CuratorFramework实例时,将CuratorFrameworkFactory.builder的ZookeeperFactory替换成新的ZookeeperFactory实现。
public ZooKeeper newZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly)
throws Exception {
ZKClientConfig config = new ZKClientConfig();
config.setProperty(ZKClientConfig.ENABLE_CLIENT_SASL_KEY, "false");
return new ZooKeeper(connectString, sessionTimeout, watcher, canBeReadOnly, config);
}复制代码
最后多说几句。以上方案适合不用SASL认证模式的zookeeper应用。如果你使用SASL请不要参考以上方案。另外也许还有在服务端disable SASL的解决方案可以考虑,大家也不必一条路走死,兴许这种方案才是最佳的。