根据百度结果,推测问题可能是,当使用ip创建ZooKeeper对象时,如果host中没有ip到主机名的映射,ZooKeeper创建过程中会调用ZooInetAddress.getHostName()这个方法从网络中获取主机名,这里耗费时间太长所致。通过调试定位到SaslServerPrincipal类的
static String getServerPrincipal(WrapperInetSocketAddress addr, ZKClientConfig clientConfig) { String configuredServerPrincipal = clientConfig.getProperty(ZKClientConfig.ZOOKEEPER_SERVER_PRINCIPAL); if (configuredServerPrincipal != null) { // If server principal is already configured then return it return configuredServerPrincipal; } String principalUserName = clientConfig.getProperty( ZKClientConfig.ZK_SASL_CLIENT_USERNAME, ZKClientConfig.ZK_SASL_CLIENT_USERNAME_DEFAULT); String hostName = addr.getHostName(); ...... if (canonicalize) { WrapperInetAddress ia = addr.getAddress(); ...... String canonicalHostName = ia.getCanonicalHostName(); //avoid using literal IP address when security check fails if (!canonicalHostName.equals(ia.getHostAddress())) { hostName = canonicalHostName; } } String serverPrincipal = principalUserName + "/" + hostName; return serverPrincipal; }
解决耗时长问题 一个方式就是改host文件,添加ip到域名的映射,但查看上述函数可以发现,如果configuredServerPrincipal不为null,则不会执行String hostName = addr.getHostName();也就可以绕过耗时长的问题。
所以在创建ZooKeeper时,传入ZKClientConfig对象,并配置一个属性,代码如下
String connectString="117.76.191.159"; ZKClientConfig zkClientConfig = new ZKClientConfig(); zkClientConfig.setProperty(ZKClientConfig.ZOOKEEPER_SERVER_PRINCIPAL,"zookeeper/"+connectString); zooKeeper = new ZooKeeper(connectString, timeout, new Watcher() { @Override public void process(WatchedEvent event) { } },false,new StaticHostProvider(new ConnectStringParser(connectString).getServerAddresses()),zkClientConfig);
该方法适合单台Zookeeper,多台可能就不行了。