mirror of
https://github.com/golang/go
synced 2024-11-19 22:04:44 -07:00
net: implement query-response fast failover in builtin dns stub resolver
Speed improvements via code cleanup, and changes to make go dns behave more like glibc resolver. See https://groups.google.com/forum/#!topic/golang-dev/lV-0aHqxVeo Fixes #6579. Benchmark results on linux/amd64 benchmark old ns/op new ns/op delta BenchmarkGoLookupIP 4831903 2572937 -46.75% BenchmarkGoLookupIPNoSuchHost 10114105 2419641 -76.08% BenchmarkGoLookupIPWithBrokenNameServer 20007735624 5004490730 -74.99% benchmark old allocs new allocs delta BenchmarkGoLookupIP 287 288 0.35% BenchmarkGoLookupIPNoSuchHost 204 102 -50.00% BenchmarkGoLookupIPWithBrokenNameServer 410 358 -12.68% benchmark old bytes new bytes delta BenchmarkGoLookupIP 13181 13271 0.68% BenchmarkGoLookupIPNoSuchHost 17260 8714 -49.51% BenchmarkGoLookupIPWithBrokenNameServer 28160 22432 -20.34% LGTM=mikioh.mikioh R=golang-codereviews, mikioh.mikioh, bradfitz, josharian, abursavich CC=golang-codereviews https://golang.org/cl/128820043
This commit is contained in:
parent
2758cb75f0
commit
39a021bc0e
@ -169,33 +169,20 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
|
|||||||
}
|
}
|
||||||
timeout := time.Duration(cfg.timeout) * time.Second
|
timeout := time.Duration(cfg.timeout) * time.Second
|
||||||
var lastErr error
|
var lastErr error
|
||||||
for _, server := range cfg.servers {
|
for i := 0; i < cfg.attempts; i++ {
|
||||||
server += ":53"
|
for _, server := range cfg.servers {
|
||||||
lastErr = &DNSError{
|
server = JoinHostPort(server, "53")
|
||||||
Err: "no answer from DNS server",
|
|
||||||
Name: name,
|
|
||||||
Server: server,
|
|
||||||
IsTimeout: true,
|
|
||||||
}
|
|
||||||
for i := 0; i < cfg.attempts; i++ {
|
|
||||||
msg, err := exchange(server, name, qtype, timeout)
|
msg, err := exchange(server, name, qtype, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if nerr, ok := err.(Error); ok && nerr.Timeout() {
|
|
||||||
lastErr = &DNSError{
|
|
||||||
Err: nerr.Error(),
|
|
||||||
Name: name,
|
|
||||||
Server: server,
|
|
||||||
IsTimeout: true,
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
|
|
||||||
}
|
|
||||||
lastErr = &DNSError{
|
lastErr = &DNSError{
|
||||||
Err: err.Error(),
|
Err: err.Error(),
|
||||||
Name: name,
|
Name: name,
|
||||||
Server: server,
|
Server: server,
|
||||||
}
|
}
|
||||||
break
|
if nerr, ok := err.(Error); ok && nerr.Timeout() {
|
||||||
|
lastErr.(*DNSError).IsTimeout = true
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
cname, addrs, err := answer(name, server, msg, qtype)
|
cname, addrs, err := answer(name, server, msg, qtype)
|
||||||
if err == nil || err.(*DNSError).Err == noSuchHost {
|
if err == nil || err.(*DNSError).Err == noSuchHost {
|
||||||
@ -387,31 +374,36 @@ func goLookupIP(name string) (addrs []IP, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var records []dnsRR
|
type racer struct {
|
||||||
var cname string
|
qtype uint16
|
||||||
var err4, err6 error
|
rrs []dnsRR
|
||||||
cname, records, err4 = lookup(name, dnsTypeA)
|
error
|
||||||
addrs = convertRR_A(records)
|
|
||||||
if cname != "" {
|
|
||||||
name = cname
|
|
||||||
}
|
}
|
||||||
_, records, err6 = lookup(name, dnsTypeAAAA)
|
lane := make(chan racer, 1)
|
||||||
if err4 != nil && err6 == nil {
|
qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
|
||||||
// Ignore A error because AAAA lookup succeeded.
|
for _, qtype := range qtypes {
|
||||||
err4 = nil
|
go func(qtype uint16) {
|
||||||
|
_, rrs, err := lookup(name, qtype)
|
||||||
|
lane <- racer{qtype, rrs, err}
|
||||||
|
}(qtype)
|
||||||
}
|
}
|
||||||
if err6 != nil && len(addrs) > 0 {
|
var lastErr error
|
||||||
// Ignore AAAA error because A lookup succeeded.
|
for range qtypes {
|
||||||
err6 = nil
|
racer := <-lane
|
||||||
|
if racer.error != nil {
|
||||||
|
lastErr = racer.error
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch racer.qtype {
|
||||||
|
case dnsTypeA:
|
||||||
|
addrs = append(addrs, convertRR_A(racer.rrs)...)
|
||||||
|
case dnsTypeAAAA:
|
||||||
|
addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err4 != nil {
|
if len(addrs) == 0 && lastErr != nil {
|
||||||
return nil, err4
|
return nil, lastErr
|
||||||
}
|
}
|
||||||
if err6 != nil {
|
|
||||||
return nil, err6
|
|
||||||
}
|
|
||||||
|
|
||||||
addrs = append(addrs, convertRR_AAAA(records)...)
|
|
||||||
return addrs, nil
|
return addrs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,8 +218,29 @@ func TestReloadResolvConfChange(t *testing.T) {
|
|||||||
r.WantServers([]string{"[8.8.4.4]"})
|
r.WantServers([]string{"[8.8.4.4]"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkGoLookupIP(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
goLookupIP("www.example.com")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
|
func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
goLookupIP("some.nonexistent")
|
goLookupIP("some.nonexistent")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
|
||||||
|
onceLoadConfig.Do(loadDefaultConfig)
|
||||||
|
if cfg.dnserr != nil || cfg.dnsConfig == nil {
|
||||||
|
b.Fatalf("loadConfig failed: %v", cfg.dnserr)
|
||||||
|
}
|
||||||
|
// This looks ugly but it's safe as long as benchmarks are run
|
||||||
|
// sequentially in package testing.
|
||||||
|
orig := cfg.dnsConfig
|
||||||
|
cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
goLookupIP("www.example.com")
|
||||||
|
}
|
||||||
|
cfg.dnsConfig = orig
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user