Skip to content

Commit 36395a3

Browse files
committed
netbalancer: reduce logging by only logging when hostlist has changed
1 parent 9e6d655 commit 36395a3

File tree

3 files changed

+227
-28
lines changed

3 files changed

+227
-28
lines changed

netbalancer/netbalancer.go

Lines changed: 62 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package netbalancer
22

33
import (
4+
"bytes"
45
"context"
56
"log"
67
"net"
@@ -35,15 +36,15 @@ func New(host string, port int, updateInterval, timeout time.Duration) (balancer
3536
}
3637

3738
// start update loop
38-
go bal.update()
39+
go bal.loop()
3940

4041
return bal, nil
4142
}
4243

4344
type dnsBalancer struct {
4445
lookupAddress string
4546
port int
46-
hosts []balancer.Host
47+
hosts []*balancer.Host
4748
counter uint64
4849
interval time.Duration
4950
quit chan int
@@ -63,52 +64,93 @@ func (b *dnsBalancer) Next() (balancer.Host, error) {
6364

6465
idx := nextNum % count
6566

66-
return hosts[idx], nil
67+
return *hosts[idx], nil
6768
}
6869

69-
func (b *dnsBalancer) update() {
70+
func (b *dnsBalancer) loop() {
7071
tick := time.NewTicker(b.interval)
7172

7273
for {
7374
select {
7475
case <-tick.C:
75-
nextHostList, err := lookupTimeout(b.Timeout, b.lookupAddress, b.port)
76-
if err != nil {
77-
// TODO: set hostList to empty?
78-
log.Printf("[DnsBalancers] error looking up dns='%v': %v", b.lookupAddress, err)
79-
} else {
80-
if nextHostList != nil {
81-
log.Printf("[DnsBalancer] reloaded dns=%v hosts=%v", b.lookupAddress, nextHostList)
82-
b.lock.Lock()
83-
b.hosts = nextHostList
84-
b.lock.Unlock()
85-
}
86-
}
76+
b.update()
8777
case <-b.quit:
8878
tick.Stop()
8979
return
9080
}
9181
}
9282
}
9383

94-
func lookupTimeout(timeout time.Duration, host string, port int) ([]balancer.Host, error) {
84+
func (b *dnsBalancer) update() {
85+
nextHostList, err := lookupTimeout(b.Timeout, b.lookupAddress, b.port)
86+
if err != nil {
87+
// TODO: set hostList to empty?
88+
log.Printf("[DnsBalancers] error looking up dns='%v': %v", b.lookupAddress, err)
89+
} else {
90+
if nextHostList != nil {
91+
b.lock.Lock()
92+
defer b.lock.Unlock()
93+
94+
prev := b.hosts
95+
if !equals(prev, nextHostList) {
96+
log.Printf("[DnsBalancer] hosts changed dns=%v hosts=%v", b.lookupAddress, nextHostList)
97+
b.hosts = nextHostList
98+
}
99+
}
100+
}
101+
}
102+
103+
func equalsHost(a *balancer.Host, b *balancer.Host) bool {
104+
if a.Port != b.Port {
105+
return false
106+
}
107+
108+
// dont use IP.Equal because it considers ipv4 and ipv6 address to be the same.
109+
return bytes.Equal(a.Address, b.Address)
110+
}
111+
112+
func equals(a []*balancer.Host, b []*balancer.Host) bool {
113+
if len(a) != len(b) {
114+
return false
115+
}
116+
117+
for i := range a {
118+
if !hostListContains(b, a[i]) {
119+
return false
120+
}
121+
}
122+
123+
return true
124+
}
125+
126+
func hostListContains(hosts []*balancer.Host, host *balancer.Host) bool {
127+
for i := range hosts {
128+
if equalsHost(hosts[i], host) {
129+
return true
130+
}
131+
}
132+
133+
return false
134+
}
135+
136+
func lookupTimeout(timeout time.Duration, host string, port int) ([]*balancer.Host, error) {
95137
ctx := context.Background()
96138
ctx, cancel := context.WithTimeout(ctx, timeout)
97139
defer cancel()
98140

99141
return lookup(ctx, host, port)
100142
}
101143

102-
func lookup(ctx context.Context, host string, port int) ([]balancer.Host, error) {
103-
hosts := []balancer.Host{}
144+
func lookup(ctx context.Context, host string, port int) ([]*balancer.Host, error) {
145+
hosts := []*balancer.Host{}
104146

105147
ips, err := net.DefaultResolver.LookupIPAddr(ctx, host)
106148
if err != nil {
107149
return hosts, errors.Wrapf(err, "Error looking up host=%v", host)
108150
}
109151

110152
for k := range ips {
111-
entry := balancer.Host{
153+
entry := &balancer.Host{
112154
Address: ips[k].IP,
113155
Port: port,
114156
}

netbalancer/netbalancer_test.go

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package netbalancer
2+
3+
import (
4+
"net"
5+
"testing"
6+
7+
"github.com/esiqveland/balancer"
8+
)
9+
10+
func Test_equalsHost(t *testing.T) {
11+
type args struct {
12+
a *balancer.Host
13+
b *balancer.Host
14+
}
15+
tests := []struct {
16+
name string
17+
args args
18+
want bool
19+
}{{
20+
name: "two equal hosts",
21+
args: args{
22+
a: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 123},
23+
b: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 123},
24+
},
25+
want: true,
26+
},
27+
{
28+
name: "two not equal hosts by port",
29+
args: args{
30+
a: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 1233},
31+
b: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
32+
},
33+
want: false,
34+
},
35+
{
36+
name: "two not equal hosts by IP",
37+
args: args{
38+
a: &balancer.Host{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
39+
b: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
40+
},
41+
want: false,
42+
},
43+
{
44+
name: "two not equal hosts by IP and Port",
45+
args: args{
46+
a: &balancer.Host{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
47+
b: &balancer.Host{Address: net.IPv4(192, 168, 0, 1), Port: 123},
48+
},
49+
want: false,
50+
},
51+
}
52+
for _, tt := range tests {
53+
t.Run(tt.name, func(t *testing.T) {
54+
if got := equalsHost(tt.args.a, tt.args.b); got != tt.want {
55+
t.Errorf("equalsHost() = %v, want %v", got, tt.want)
56+
}
57+
})
58+
}
59+
}
60+
61+
func Test_equals(t *testing.T) {
62+
type args struct {
63+
a []*balancer.Host
64+
b []*balancer.Host
65+
}
66+
tests := []struct {
67+
name string
68+
args args
69+
want bool
70+
}{{
71+
name: "empty list",
72+
args: args{
73+
a: []*balancer.Host{},
74+
b: []*balancer.Host{},
75+
},
76+
want: true,
77+
},{
78+
name: "two same ips",
79+
args: args{
80+
a: []*balancer.Host{
81+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
82+
},
83+
b: []*balancer.Host{
84+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
85+
},
86+
},
87+
want: true,
88+
},{
89+
name: "different list length",
90+
args: args{
91+
a: []*balancer.Host{
92+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
93+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
94+
},
95+
b: []*balancer.Host{
96+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
97+
},
98+
},
99+
want: false,
100+
},{
101+
name: "two equals lists of hosts",
102+
args: args{
103+
a: []*balancer.Host{
104+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
105+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
106+
{Address: net.IPv4(192, 168, 0, 3), Port: 1234},
107+
},
108+
b: []*balancer.Host{
109+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
110+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
111+
{Address: net.IPv4(192, 168, 0, 3), Port: 1234},
112+
},
113+
},
114+
want: true,
115+
},{
116+
name: "two equals scrambled lists of hosts",
117+
args: args{
118+
a: []*balancer.Host{
119+
{Address: net.IPv4(192, 168, 0, 3), Port: 1234},
120+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
121+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
122+
},
123+
b: []*balancer.Host{
124+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
125+
{Address: net.IPv4(192, 168, 0, 2), Port: 1234},
126+
{Address: net.IPv4(192, 168, 0, 3), Port: 1234},
127+
},
128+
},
129+
want: true,
130+
},{
131+
name: "two equals scrambled lists of host ports",
132+
args: args{
133+
a: []*balancer.Host{
134+
{Address: net.IPv4(192, 168, 0, 1), Port: 123},
135+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
136+
{Address: net.IPv4(192, 168, 0, 1), Port: 12345},
137+
},
138+
b: []*balancer.Host{
139+
{Address: net.IPv4(192, 168, 0, 1), Port: 12345},
140+
{Address: net.IPv4(192, 168, 0, 1), Port: 123},
141+
{Address: net.IPv4(192, 168, 0, 1), Port: 1234},
142+
},
143+
},
144+
want: true,
145+
},
146+
}
147+
for _, tt := range tests {
148+
t.Run(tt.name, func(t *testing.T) {
149+
if got := equals(tt.args.a, tt.args.b); got != tt.want {
150+
t.Errorf("equals() = %v, want %v", got, tt.want)
151+
}
152+
})
153+
}
154+
}

netbalancer/srvbalancer.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type dnsSrvBalancer struct {
4646
serviceName string
4747
proto string
4848
host string
49-
hosts []balancer.Host
49+
hosts []*balancer.Host
5050
counter uint64
5151
interval time.Duration
5252
quit chan int
@@ -88,16 +88,16 @@ func NewSRV(servicename, proto, host string, opts ...srvOption) (balancer.Balanc
8888
return bal, nil
8989
}
9090

91-
func lookupSRVTimeout(timeout time.Duration, resolver srvResolver, serviceName string, proto string, host string) ([]balancer.Host, error) {
91+
func lookupSRVTimeout(timeout time.Duration, resolver srvResolver, serviceName string, proto string, host string) ([]*balancer.Host, error) {
9292
ctx := context.Background()
9393
ctx, cancel := context.WithTimeout(ctx, timeout)
9494
defer cancel()
9595

9696
return lookupSRV(ctx, resolver, serviceName, proto, host)
9797
}
9898

99-
func lookupSRV(ctx context.Context, resolver srvResolver, servicename, proto, host string) ([]balancer.Host, error) {
100-
hosts := []balancer.Host{}
99+
func lookupSRV(ctx context.Context, resolver srvResolver, servicename, proto, host string) ([]*balancer.Host, error) {
100+
hosts := []*balancer.Host{}
101101

102102
_, addrs, err := resolver.LookupSRV(ctx, servicename, proto, host)
103103
if err != nil {
@@ -116,7 +116,7 @@ func lookupSRV(ctx context.Context, resolver srvResolver, servicename, proto, ho
116116
}
117117

118118
for e := range ips {
119-
host := balancer.Host{
119+
host := &balancer.Host{
120120
Address: ips[e].IP,
121121
Port: int(v.Port),
122122
}
@@ -139,7 +139,7 @@ func (b *dnsSrvBalancer) Next() (balancer.Host, error) {
139139

140140
idx := nextNum % count
141141

142-
return hosts[idx], nil
142+
return *hosts[idx], nil
143143
}
144144

145145
func (b *dnsSrvBalancer) update() error {
@@ -152,8 +152,11 @@ func (b *dnsSrvBalancer) update() error {
152152
log.Printf("[SRVBalancer] error looking up dns='%v': %v", b.host, err)
153153
} else {
154154
if nextHostList != nil {
155-
log.Printf("[SRVBalancer] reloaded dns=%v hosts=%v", b.host, nextHostList)
156-
b.hosts = nextHostList
155+
prev := b.hosts
156+
if !equals(prev, nextHostList) {
157+
log.Printf("[SRVBalancer] hosts changed dns=%v hosts=%v", b.host, nextHostList)
158+
b.hosts = nextHostList
159+
}
157160
}
158161
}
159162
return err

0 commit comments

Comments
 (0)