How to Add Load Balancing to a Custom Go DNS Resolver

This guide shows how to modify a Go custom DNS resolver to perform simple load balancing by predefining IP addresses and randomly selecting one for each new connection, including full code examples and test output.

FunTester
FunTester
FunTester
How to Add Load Balancing to a Custom Go DNS Resolver

The article builds on a previous tutorial about creating a custom DNS resolver in Go and demonstrates how to incorporate load‑balancing logic directly into the resolver.

By adjusting the DialContext function, the resolver checks whether the target host matches a predefined name (e.g., "fun.tester"). If it does, the code can either return a fixed IP address or, for load balancing, choose randomly from a slice of IP strings.

Example implementation:

DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
    host, port, err := net.SplitHostPort(address)
    if err != nil {
        return nil, err
    }
    // Create connection
    if host == "fun.tester" {
        ip := "127.0.0.1"
        conn, err := dialer.DialContext(ctx, network, ip+":"+port)
        if err == nil {
            return conn, nil
        }
    }
    return dialer.DialContext(ctx, network, address)
},

For load balancing, replace the fixed IP with a random selection:

if host == "fun.tester" {
    ips := []string{"127.0.0.1", "0.0.0.0"}
    ip := futil.RandomStrs(ips)
    conn, err := dialer.DialContext(ctx, network, ip+":"+port)
    if err == nil {
        return conn, nil
    }
}

The approach can be further externalized into configuration files, allowing developers to customize the IP pool without changing code.

Testing

The test confirms that each new connection triggers the random IP selection, mirroring the behavior of a similar Java implementation. The test code creates ten concurrent requests to http://fun.tester:12345/test and logs the responses.

func TestFaast(t *testing.T) {
    url := "http://fun.tester:12345/test"
    get := fhttp.Get(url, nil)
    for i := 0; i < 10; i++ {
        go func() {
            log.Println(string(fhttp.Response(get)))
        }()
    }
    response := fhttp.Response(get)
    log.Println(string(response))
}

Sample console output shows a mix of the two IP addresses and the final success messages, proving that the random selection works as intended.

=== RUN   TestFaast
2022/02/14 18:34:14 0.0.0.0
2022/02/14 18:34:14 127.0.0.1
... (repeated lines) ...
2022/02/14 18:34:14 Have Fun ~ Tester !
--- PASS: TestFaast (0.17s)

In summary, adding load balancing to a custom DNS resolver in Go requires only a small change to the dialing logic, and the random selection mechanism can be tailored to specific needs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backendload balancingGoNetworkingDNSCustom Resolver
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.