Three practices of Java custom DNS resolver

Recently, the high-performance testing machine (54C96G * 3) has been finally used, which has tripled the performance and quantity of single machine compared with the previous one, and the more critical broadband single machine has increased by more than 30 times. Generally speaking, it has increased by more than 100 times. Now there is no need to worry about the bottleneck of single machine press and take off directly.

However, I was not happy for five minutes. I found that the interface request failed. After a while, I finally found the reason: the domain name could not be resolved and the IP could not be accessed directly.

Naturally, the solution is ready: customize the Java DNS parser.

Through the guidance of colleagues, data search and exploration practice. Finally locked two core classes: org apache. http. impl. Conn.inmemorydnsresolver and org apache. http. impl. Conn.systemdefaultdnsresolver. Next, I will demonstrate the use practice of these two classes. The main difference is the implementation of load balancing. I will share this when I have time.

InMemoryDnsResolver

This class is relatively simple to use. First write a Demo to realize a simple domain name resolution.

    /**
     * Rewrite Java custom DNS resolver, non load balancing
     *
     * @return
     */
    private static DnsResolver getDnsResolver2() {
        InMemoryDnsResolver dnsResolver = new InMemoryDnsResolver();

        try {
            dnsResolver.add("fun.tester", InetAddress.getByName("127.0.0.1"));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return dnsResolver;
    }

So we can put fun The tester has been parsed to 127.0.0.1. I will conduct a simple test later.

SystemDefaultDnsResolver

This name is the default DNS resolver of the system, but I can't see where the default is. The only reference that can be found is that the asynchronous thread pool manager uses org apache. http. impl. nio. conn.PoolingNHttpClientConnectionManager#PoolingNHttpClientConnectionManager (org.apache.http.nio.reactor.ConnectingIOReactor, org.apache.http.nio.conn.NHttpConnectionFactory<org.apache.http.nio.conn.ManagedNHttpClientConnection>, org.apache.http.config.Registry<org.apache.http.nio.conn.SchemeIOSessionStrategy>, org.apache.http.conn.SchemePortResolver, org.apache.http.conn.DnsResolver, long, java.util.concurrent.TimeUnit), There are other parameters involved, so I won't talk about them here.

Let's look at this Demo first.

    /**
     * Rewrite Java custom DNS resolver, load balancing
     *
     * @return
     */
    private static DnsResolver getDnsResolver() {
        return new SystemDefaultDnsResolver() {
            @Override
            public InetAddress[] resolve(final String host) throws UnknownHostException {
                if (host.equalsIgnoreCase("fun.tester")) {
                    return new InetAddress[]{InetAddress.getByName("127.0.0.1")};
                } else {
                    return super.resolve(host);
                }
            }
        };
    }

Custom DnsResolver

As can be seen from the source code, the two implementation classes are implemented through org apache. http. Conn.dnsresolver this interface contains org apache. http. Conn.dnsresolver#resolve method. We can achieve it by ourselves.

    /**
     * Custom local DNS resolver implementation
     *
     * @return
     */
    private static DnsResolver getDnsResolver3() {
        return new DnsResolver() {
            @Override
            public InetAddress[] resolve(final String host) throws UnknownHostException {
                if (host.equalsIgnoreCase("fun.tester")) {
                    return new InetAddress[]{InetAddress.getByName("127.0.0.1")};
                } else {
                    return InetAddress.getAllByName(host);
                }
            }
        };
    }

It's not difficult to find that it's actually a code stitching monster.

Connection pool manager

Let's share how to use the custom org apache. http. Conn.dnsresolver can be set when creating the connection pool manager.

test

First, I set up an HTTP service locally, port 12345, which is very simple. The code is as follows:

    static void main(String[] args) {
        def util = new ArgsUtil(args)
        def server = getServerNoLog(util.getIntOrdefault(0, 12345))
        server.response("Have Fun ~ Tester !")
        def run = run(server)
        waitForKey("fan")
        run.stop()
    }

Then I prepare a test script:

    public static void main(String[] args) {
        String url = "http://fun.tester:12345/"
        def get = getHttpGet(url)
        def funtester = {
            fun {
                getHttpResponse(get)
            }
        }
        10.times {
            funtester()
        }
    }

Console log output:

INFO-> 27.214 F-1  request uri: http://fun.tester:12345 /, time consuming: 304 MS, httpcode: 200
INFO-> 27.214 F-4  request uri: http://fun.tester:12345 /, time consuming: 304 MS, httpcode: 200
INFO-> 27.214 F-10 request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-5  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-2  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-8  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-3  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-7  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-6  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200
INFO-> 27.214 F-9  request uri: http://fun.tester:12345 /, time consuming: 305 MS, httpcode: 200

The console output of the three implementation methods is similar, and can meet our needs. Of course, it is only in the function test scenario. The next issue will analyze how to achieve load balancing in combination with the source code.

- END -

Added by xray_griff on Tue, 08 Feb 2022 08:27:43 +0200