Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK 14 + ZK 3.4 버전에서 Unable to canonicalize address XXX 로그가 출력되는 이슈 #327

Closed
hjyun328 opened this issue Jan 29, 2021 · 6 comments
Assignees

Comments

@hjyun328
Copy link
Collaborator

hjyun328 commented Jan 29, 2021

이슈

  • JDK 14 + ZK 3.4.14 버전(arcus-java-client에서 사용되고 있는 버전)에서 IP, 또는 도메인명으로 ZooKeeeper에 연결을 시도할 때, DNS Lookup이 실패하여, Unable to canonicalize address 로그가 출력되고, 연결이 실패하는 현상.

IP 주소로 연결할 경우

java.lang.IllegalArgumentException: Unable to canonicalize address 1.2.3.4/<unresolved>:1234 because it's not resolvable
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:65) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:41) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.ClientCnxn$SendThread.startConnect(ClientCnxn.java:1001) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1060) [zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]

도메인 이름으로 연결할 경우

java.lang.IllegalArgumentException: Unable to canonicalize address XYZ/<unresolved>:1234 because it's not resolvable
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:65) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.SaslServerPrincipal.getServerPrincipal(SaslServerPrincipal.java:41) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.ClientCnxn$SendThread.startConnect(ClientCnxn.java:1001) ~[zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]
	at org.apache.zookeeper.ClientCnxn$SendThread.run(ClientCnxn.java:1060) [zookeeper-3.4.14.jar:3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf]

원인

  • InetSocketAddress 클래스는 ZooKeeper와 연결하는데 필요한 클래스. InetSocketAddress를 생성하면 내부에서 InetAddress.getByName(DNS Lookup)을 호출하여 ip address를 초기화함.
  • ZooKeeper 3.4에서는 InetSocketAddress를 생성할 때 DNS Lookup을 하지 않은 상태로 생성 (InetSocketAddress의 IP address는 NULL이므로, unresolved 상태). 이후 StaticHostProvider 클래스에서 InetSocketAddress의 toString을 호출하여 IP 또는 도메인 String을 얻은 다음, 해당 String을 통해 DNS Lookup을 한 후 IP address를 가져옴.
class InetSocketAddress{
    ....
    public static InetSocketAddress createUnresolved(String host, int port) {
        return new InetSocketAddress(checkPort(port), checkHost(host));
    }
}
package org.apache.zookeeper.client;

class ConnectStringParser {
    public ConnectStringParser(String connectString) {
        ...
        serverAddresses.add(InetSocketAddress.createUnresolved(host, port));
    }
}
package.org.apache.zookeeper.client;

public final class StaticHostProvider implements HostProvider {
    
    public InetSocketAddress next(long spinDelay) {
        ...

        // curAddr은 unresolved 상태.
        InetSocketAddress curAddr = serverAddresses.get(currentIndex);
        try {
            // curAddr에 toString 결과를 얻고,
            String curHostString = getHostString(curAddr);
            // toString 결과에 getAllByName을 호출하여 DNS Lookup 
            List<InetAddress> resolvedAddresses = new ArrayList<InetAddress>(Arrays.asList(this.resolver.getAllByName(curHostString)));
            if (resolvedAddresses.isEmpty()) {
                return curAddr;
            }
            Collections.shuffle(resolvedAddresses);
            return new InetSocketAddress(resolvedAddresses.get(0), curAddr.getPort());
        } catch (UnknownHostException e) {
            return curAddr;
        }
    }

}
  • JDK 14부터, InetSocketAddress 클래스의 toString 메소드의 내부 구현이 바뀜.
    • unresolved 상태이면 IP/도메인명 뒤에 "unresolved" string이 append 됨.
    • DNS Lookup을 할 때 "unresolved" string에 append 됨으로 인해서 IP 주소를 얻지 못하고, 주키퍼와 연결을 시도하지 못한 상태로 실패하게 됨.

JDK14 - InetSocketAddress.toString

@Override
public String toString() {
    String formatted;

    if (isUnresolved()) {
        formatted = hostname + "/<unresolved>";
    } else {
        formatted = addr.toString();
        if (addr instanceof Inet6Address) {
            int i = formatted.lastIndexOf("/");
            formatted = formatted.substring(0, i + 1)
                    + "[" + formatted.substring(i + 1) + "]";
        }
    }
    return formatted + ":" + port;
}

JDK11 - InetSocketAddress.toString

@Override
    public String toString() {
        if (isUnresolved()) {
            return hostname + ":" + port;
        } else {
            return addr.toString() + ":" + port;
        }
    }

해결 방안

@hjyun328
Copy link
Collaborator Author

hjyun328 commented Jan 29, 2021

3.5 버전 업그레이드 작업이 완료되면 이슈 클로즈 합니다.

현재 JDK 11을 가장 많이 사용하고 있는 상태여서 그동안 해당 이슈가 나오지 않았던 것 같습니다. JDK 14 이상 버전이 많이 사용되게 된다면 해당 이슈가 무조건 발생될 것입니다. JDK 개발 환경과 사용하고 있는 arcus-java-client 버전에 따라 언제라도 이슈가 발생할 수 있기 때문에, 이슈 대응을 위해 정리하여 올립니다.

@jhpark816
Copy link
Collaborator

jhpark816 commented Feb 10, 2021

@hjyun328
이에 관한 문의가 계속 들어오니, 의존하는 ZooKeeper 버전을 3.5.X로 올리는 작업을 바로 진행하죠.
그리고, 이번 릴리즈 시에 포함되도록 하시죠.

@jhpark816
Copy link
Collaborator

아래 코멘트 참고.

http://zookeeper-user.578899.n2.nabble.com/Is-3-5-5-client-compatible-with-3-4-x-servers-td7584161.html#a7584172 에서도 호환이 된다고 나와있긴 하네요. 3.5의 새로운 기능을 사용하지만 않는다면 괜찮은 듯 싶습니다.

@jhpark816
Copy link
Collaborator

ZK ensemble이 3.3.X 버전을 사용하고 있으면 어떻게 되죠 ?

@jhpark816
Copy link
Collaborator

@hjyun328
본 이슈는 close하여도 되죠?

@hjyun328
Copy link
Collaborator Author

@jhpark816
네 클로즈해도 됩니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants