You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

包装net.Conn导致DNS读取超时的Go技术问题求助

Go DNS解析调试异常:包装net.Conn导致读取超时问题

我是Go语言新手,正在排查生产环境中Go应用的网络问题:应用成功连接并交互Redis集群后,出现大量dial: tcp :0: connection refused错误,怀疑与DNS解析有关(:0表示尝试连接零值远程地址,推测是主机名查找异常)。

为调试DNS解析过程,我给Dialer传入自定义Resolver,其Dial函数返回包装了原生net.Conn的ConnWrapper(仅记录读写字节日志),但此时DNS解析出现读取超时;若直接返回原生Conn,DNS解析可正常完成(当前环境中Redis主机不存在,返回no such host符合预期)。

可复现代码

package main

import (
    "context"
    "fmt"
    "net"
    "time"
)

type ConnWrapper struct {
    net.Conn
}

func (c *ConnWrapper) Write(bytes []byte) (int, error) {
    n, err := c.Conn.Write(bytes)
    if err != nil {
        fmt.Printf("Failed to write bytes %s: %v\n", string(bytes), err)
    } else {
        fmt.Printf("Successfully wrote %d of bytes %x\n", n, bytes[:n])
    }
    return n, err
}

func (c *ConnWrapper) Read(bytes []byte) (int, error) {
    n, err := c.Conn.Read(bytes)
    if err != nil {
        fmt.Printf("Failed to read bytes: %v\n", err)
    } else {
        fmt.Printf("Successfully read %d of bytes %x\n", n, bytes[:n])
    }
    return n, err
}

func (c *ConnWrapper) SetDeadline(t time.Time) error {
    fmt.Printf("Setting deadline %v %s %s\n", t, c.LocalAddr(), c.RemoteAddr())
    return c.Conn.SetDeadline(t)
}

func (c *ConnWrapper) SetReadDeadline(t time.Time) error {
    fmt.Printf("Setting read deadline %v %s %s\n", t, c.LocalAddr(), c.RemoteAddr())
    return c.Conn.SetReadDeadline(t)
}

func (c *ConnWrapper) SetWriteDeadline(t time.Time) error {
    fmt.Printf("Setting write deadline %v %s %s\n", t, c.LocalAddr(), c.RemoteAddr())
    return c.Conn.SetWriteDeadline(t)
}

func main() {
    var d *net.Dialer
    d = &net.Dialer{
        Timeout: time.Duration(30) * time.Minute,
        Resolver: &net.Resolver{
            PreferGo: true,
            Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
                fmt.Printf("Redis dialing (from resolver) %s %s\n", network, address)
                conn, err := d.DialContext(ctx, network, address)

                if err != nil {
                    fmt.Printf("Redis resolver failed %v\n", err)
                }

                // When I return c2, the reads time out
                c2 := &ConnWrapper{conn}
                return c2, err

                // When I return conn, everything is fine
                //return conn, err
            },
        },
    }
    conn, err := d.DialContext(context.Background(), "tcp", "redis-node-0:6379")
    if err != nil {
        fmt.Printf("Redis dial failed %v\n", err)
    } else {
        fmt.Printf("Successfully dialed %s\n", conn.RemoteAddr())
    }
}

返回包装Conn时的输出

Redis dialing (from resolver) udp 1.1.1.1:53
Redis dialing (from resolver) udp 1.1.1.1:53
Setting deadline 2023-10-15 10:43:44.031475 -0400 AST m=+5.001741085 192.168.68.61:62862 1.1.1.1:53
Setting deadline 2023-10-15 10:43:44.031494 -0400 AST m=+5.001759751 192.168.68.61:57358 1.1.1.1:53
Successfully wrote 49 of bytes 002f53c8010000010000000000010c72656469732d6e6f64652d30056c6f63616c00001c000100002904d0000000000000
Successfully wrote 49 of bytes 002f29c8010000010000000000010c72656469732d6e6f64652d30056c6f63616c000001000100002904d0000000000000
Successfully read 2 of bytes 002f
Successfully read 2 of bytes 002f
Failed to read bytes: read udp 192.168.68.61:57358->1.1.1.1:53: i/o timeout
Redis dialing (from resolver) udp 1.0.0.1:53
Failed to read bytes: read udp 192.168.68.61:62862->1.1.1.1:53: i/o timeout
Redis dialing (from resolver) udp 1.0.0.1:53
Setting deadline 2023-10-15 10:43:49.033465 -0400 AST m=+10.003676876 192.168.68.61:64641 1.0.0.1:53
Setting deadline 2023-10-15 10:43:49.033817 -0400 AST m=+10.004027543 192.168.68.61:59264 1.0.0.1:53
Successfully wrote 49 of bytes 002f6612010000010000000000010c72656469732d6e6f64652d30056c6f63616c00001c000100002904d0000000000000
Successfully wrote 49 of bytes 002fd26c010000010000000000010c72656469732d6e6f64652d30056c6f63616c000001000100002904d0000000000000
Successfully read 2 of bytes 002f
Failed to read bytes: read udp 192.168.68.61:59264->1.0.0.1:53: i/o timeout
Redis dialing (from resolver) udp 1.1.1.1:53
Setting deadline 2023-10-15 10:43:54.036073 -0400 AST m=+15.006228210 192.168.68.61:56757 1.1.1.1:53
Failed to read bytes: read udp 192.168.68.61:64641->1.0.0.1:53: i/o timeout
Redis dialing (from resolver) udp 1.1.1.1:53
Successfully wrote 49 of bytes 002f4f6d010000010000000000010c72656469732d6e6f64652d30056c6f63616c00001c000100002904d0000000000000
Setting deadline 2023-10-15 10:43:54.036487 -0400 AST m=+15.006642126 192.168.68.61:58296 1.1.1.1:53
Successfully wrote 49 of bytes 002f404c010000010000000000010c72656469732d6e6f64652d30056c6f63616c000001000100002904d0000000000000
Successfully read 2 of bytes 002f
Successfully read 2 of bytes 002f
Failed to read bytes: read udp 192.168.68.61:58296->1.1.1.1:53: i/o timeout
Failed to read bytes: read udp 192.168.68.61:56757->1.1.1.1:53: i/o timeout

返回原生Conn时的输出

Redis dialing (from resolver) udp 1.1.1.1:53
Redis dialing (from resolver) udp 1.1.1.1:53
Redis dialing (from resolver) udp 1.1.1.1:53
Redis dialing (from resolver) udp 1.1.1.1:53
Redis dial failed dial tcp: lookup redis-node-0 on 1.1.1.1:53: no such host

恳请社区帮忙分析该现象的原因。


内容的提问来源于stack exchange,提问作者dbrianj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 07:40:57