Use weights from xDS

use the weights as reported. Set prio to 0 to signal it's not used.

Signed-off-by: Miek Gieben <miek@miek.nl>
This commit is contained in:
Miek Gieben
2020-07-24 10:33:52 +02:00
parent 6afcfb8390
commit ccc6e0cff9
4 changed files with 21 additions and 13 deletions

View File

@@ -108,7 +108,7 @@ For SRV queries all endpoints are returned, the SRV target names are synthesized
## Matching Algorithm ## Matching Algorithm
How are clients match against the data we receive from xDS endpoint? How are queries match against the data we receive from xDS endpoint?
1. Does the cluster exist? If not return NXDOMAIN, otherwise continue. 1. Does the cluster exist? If not return NXDOMAIN, otherwise continue.
@@ -116,7 +116,9 @@ How are clients match against the data we receive from xDS endpoint?
endpoint return a NODATA response, otherwise continue. endpoint return a NODATA response, otherwise continue.
3. If weights are assigned, use those to pick an endpoint, otherwise randomly pick one and return a 3. If weights are assigned, use those to pick an endpoint, otherwise randomly pick one and return a
response to the client. response to the client. Weights are copied from the xDS data, priority is not used and set to 0
for all SRV records. Note that weights in SRV records are 16 bits, but xDS uses uint32; you have
been warned.
## Metrics ## Metrics

View File

@@ -103,7 +103,7 @@ func (t *Traffic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
} }
m.Answer = []dns.RR{&dns.AAAA{Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 5}, AAAA: sockaddr.Address()}} m.Answer = []dns.RR{&dns.AAAA{Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 5}, AAAA: sockaddr.Address()}}
case dns.TypeSRV: case dns.TypeSRV:
sockaddrs, _ := t.c.All(cluster, true) sockaddrs, weights, _ := t.c.All(cluster, true)
m.Answer = make([]dns.RR, 0, len(sockaddrs)) m.Answer = make([]dns.RR, 0, len(sockaddrs))
m.Extra = make([]dns.RR, 0, len(sockaddrs)) m.Extra = make([]dns.RR, 0, len(sockaddrs))
for i, sa := range sockaddrs { for i, sa := range sockaddrs {
@@ -111,7 +111,7 @@ func (t *Traffic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
m.Answer = append(m.Answer, &dns.SRV{ m.Answer = append(m.Answer, &dns.SRV{
Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: 5}, Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeSRV, Class: dns.ClassINET, Ttl: 5},
Priority: 100, Weight: 100, Port: sa.Port(), Target: target}) Priority: 0, Weight: uint16(weights[i]), Port: sa.Port(), Target: target})
if sa.Address().To4() == nil { if sa.Address().To4() == nil {
m.Extra = append(m.Extra, &dns.AAAA{Hdr: dns.RR_Header{Name: target, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 5}, AAAA: sa.Address()}) m.Extra = append(m.Extra, &dns.AAAA{Hdr: dns.RR_Header{Name: target, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 5}, AAAA: sa.Address()})
@@ -120,7 +120,7 @@ func (t *Traffic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
} }
} }
case dns.TypeTXT: case dns.TypeTXT:
sockaddrs, _ := t.c.All(cluster, false) sockaddrs, weights, _ := t.c.All(cluster, false)
m.Answer = make([]dns.RR, 0, len(sockaddrs)) m.Answer = make([]dns.RR, 0, len(sockaddrs))
m.Extra = make([]dns.RR, 0, len(sockaddrs)) m.Extra = make([]dns.RR, 0, len(sockaddrs))
for i, sa := range sockaddrs { for i, sa := range sockaddrs {
@@ -128,7 +128,7 @@ func (t *Traffic) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg
m.Answer = append(m.Answer, &dns.TXT{ m.Answer = append(m.Answer, &dns.TXT{
Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 5}, Hdr: dns.RR_Header{Name: state.QName(), Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 5},
Txt: []string{"100", "100", strconv.Itoa(int(sa.Port())), target, corepb2.HealthStatus_name[int32(sa.Health)]}}) Txt: []string{"0", strconv.Itoa(int(uint16(weights[i]))), strconv.Itoa(int(sa.Port())), target, corepb2.HealthStatus_name[int32(sa.Health)]}})
m.Extra = append(m.Extra, &dns.TXT{Hdr: dns.RR_Header{Name: target, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 5}, Txt: []string{sa.Address().String()}}) m.Extra = append(m.Extra, &dns.TXT{Hdr: dns.RR_Header{Name: target, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 5}, Txt: []string{sa.Address().String()}})
} }
default: default:
@@ -162,7 +162,7 @@ func (t *Traffic) serveEndpoint(ctx context.Context, state request.Request, endp
return 0, nil return 0, nil
} }
sockaddrs, _ := t.c.All(cluster, healthy) sockaddrs, _, _ := t.c.All(cluster, healthy)
if len(sockaddrs) < nr { if len(sockaddrs) < nr {
m.Ns = soa(state.Zone) m.Ns = soa(state.Zone)
m.Rcode = dns.RcodeNameError m.Rcode = dns.RcodeNameError

View File

@@ -126,21 +126,27 @@ func (a *assignment) Select(cluster string, healthy bool) (*SocketAddress, bool)
return nil, true return nil, true
} }
// All returns all healthy endpoints. // All returns all healthy endpoints, together with their weights.
func (a *assignment) All(cluster string, healthy bool) ([]*SocketAddress, bool) { func (a *assignment) All(cluster string, healthy bool) ([]*SocketAddress, []uint32, bool) {
cla := a.ClusterLoadAssignment(cluster) cla := a.ClusterLoadAssignment(cluster)
if cla == nil { if cla == nil {
return nil, false return nil, nil, false
} }
sa := []*SocketAddress{} sa := []*SocketAddress{}
we := []uint32{}
for _, ep := range cla.Endpoints { for _, ep := range cla.Endpoints {
for _, lb := range ep.GetLbEndpoints() { for _, lb := range ep.GetLbEndpoints() {
if healthy && lb.GetHealthStatus() != corepb2.HealthStatus_HEALTHY { if healthy && lb.GetHealthStatus() != corepb2.HealthStatus_HEALTHY {
continue continue
} }
weight := lb.GetLoadBalancingWeight().GetValue()
if weight > 2^16 {
log.Warning("Weight in cluster %q > %d, truncating to %d in SRV responses", cluster, weight, uint16(weight))
}
we = append(we, weight)
sa = append(sa, &SocketAddress{lb.GetEndpoint().GetAddress().GetSocketAddress(), lb.GetHealthStatus()}) sa = append(sa, &SocketAddress{lb.GetEndpoint().GetAddress().GetSocketAddress(), lb.GetHealthStatus()})
} }
} }
return sa, true return sa, we, true
} }

View File

@@ -205,9 +205,9 @@ func (c *Client) Select(cluster string, healty bool) (*SocketAddress, bool) {
} }
// All returns all endpoints. // All returns all endpoints.
func (c *Client) All(cluster string, healty bool) ([]*SocketAddress, bool) { func (c *Client) All(cluster string, healty bool) ([]*SocketAddress, []uint32, bool) {
if cluster == "" { if cluster == "" {
return nil, false return nil, nil, false
} }
return c.assignments.All(cluster, healty) return c.assignments.All(cluster, healty)
} }