mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Fixes #3640 by shuffling endpoints in the round-robin load balancer
This commit is contained in:
parent
2863fa9fe6
commit
79a6bfb95f
@ -18,8 +18,10 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -170,6 +172,15 @@ func filterValidEndpoints(endpoints []string) []string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shuffleEndpoints(endpoints []string) []string {
|
||||||
|
shuffled := make([]string, len(endpoints))
|
||||||
|
perm := rand.Perm(len(endpoints))
|
||||||
|
for i, v := range perm {
|
||||||
|
shuffled[v] = endpoints[i]
|
||||||
|
}
|
||||||
|
return shuffled
|
||||||
|
}
|
||||||
|
|
||||||
//remove any session affinity records associated to a particular endpoint (for example when a pod goes down).
|
//remove any session affinity records associated to a particular endpoint (for example when a pod goes down).
|
||||||
func removeSessionAffinityByEndpoint(lb *LoadBalancerRR, service string, endpoint string) {
|
func removeSessionAffinityByEndpoint(lb *LoadBalancerRR, service string, endpoint string) {
|
||||||
for _, affinityDetail := range lb.serviceDtlMap[service].sessionAffinityMap {
|
for _, affinityDetail := range lb.serviceDtlMap[service].sessionAffinityMap {
|
||||||
@ -210,6 +221,10 @@ func (lb *LoadBalancerRR) OnUpdate(endpoints []api.Endpoints) {
|
|||||||
for _, endpoint := range endpoints {
|
for _, endpoint := range endpoints {
|
||||||
existingEndpoints, exists := lb.endpointsMap[endpoint.Name]
|
existingEndpoints, exists := lb.endpointsMap[endpoint.Name]
|
||||||
validEndpoints := filterValidEndpoints(endpoint.Endpoints)
|
validEndpoints := filterValidEndpoints(endpoint.Endpoints)
|
||||||
|
// Need to compare sorted endpoints here, since they are shuffled below
|
||||||
|
// before being put into endpointsMap
|
||||||
|
sort.Strings(existingEndpoints)
|
||||||
|
sort.Strings(validEndpoints)
|
||||||
if !exists || !reflect.DeepEqual(existingEndpoints, validEndpoints) {
|
if !exists || !reflect.DeepEqual(existingEndpoints, validEndpoints) {
|
||||||
glog.V(3).Infof("LoadBalancerRR: Setting endpoints for %s to %+v", endpoint.Name, endpoint.Endpoints)
|
glog.V(3).Infof("LoadBalancerRR: Setting endpoints for %s to %+v", endpoint.Name, endpoint.Endpoints)
|
||||||
updateServiceDetailMap(lb, endpoint.Name, validEndpoints)
|
updateServiceDetailMap(lb, endpoint.Name, validEndpoints)
|
||||||
@ -217,7 +232,7 @@ func (lb *LoadBalancerRR) OnUpdate(endpoints []api.Endpoints) {
|
|||||||
// to be safe we will call it here. A new service will only be created
|
// to be safe we will call it here. A new service will only be created
|
||||||
// if one does not already exist.
|
// if one does not already exist.
|
||||||
lb.NewService(endpoint.Name, api.AffinityTypeNone, 0)
|
lb.NewService(endpoint.Name, api.AffinityTypeNone, 0)
|
||||||
lb.endpointsMap[endpoint.Name] = validEndpoints
|
lb.endpointsMap[endpoint.Name] = shuffleEndpoints(validEndpoints)
|
||||||
|
|
||||||
// Reset the round-robin index.
|
// Reset the round-robin index.
|
||||||
lb.rrIndex[endpoint.Name] = 0
|
lb.rrIndex[endpoint.Name] = 0
|
||||||
|
@ -18,6 +18,7 @@ package proxy
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||||
@ -56,6 +57,26 @@ func TestFilterWorks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShuffleWorks(t *testing.T) {
|
||||||
|
endpoints := []string{"foobar:1", "foobar:2", "foobar:3"}
|
||||||
|
shuffled := shuffleEndpoints(endpoints)
|
||||||
|
|
||||||
|
if len(shuffled) != 3 {
|
||||||
|
t.Errorf("Failed to shuffle to the correct size")
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(shuffled)
|
||||||
|
if shuffled[0] != "foobar:1" {
|
||||||
|
t.Errorf("Index zero is not foobar:1")
|
||||||
|
}
|
||||||
|
if shuffled[1] != "foobar:2" {
|
||||||
|
t.Errorf("Index one is not foobar:2")
|
||||||
|
}
|
||||||
|
if shuffled[2] != "foobar:3" {
|
||||||
|
t.Errorf("Index two is not foobar:3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLoadBalanceFailsWithNoEndpoints(t *testing.T) {
|
func TestLoadBalanceFailsWithNoEndpoints(t *testing.T) {
|
||||||
loadBalancer := NewLoadBalancerRR()
|
loadBalancer := NewLoadBalancerRR()
|
||||||
var endpoints []api.Endpoints
|
var endpoints []api.Endpoints
|
||||||
@ -75,7 +96,7 @@ func expectEndpoint(t *testing.T, loadBalancer *LoadBalancerRR, service string,
|
|||||||
t.Errorf("Didn't find a service for %s, expected %s, failed with: %v", service, expected, err)
|
t.Errorf("Didn't find a service for %s, expected %s, failed with: %v", service, expected, err)
|
||||||
}
|
}
|
||||||
if endpoint != expected {
|
if endpoint != expected {
|
||||||
t.Errorf("Didn't get expected endpoint for service %s, expected %s, got: %s", service, expected, endpoint)
|
t.Errorf("Didn't get expected endpoint for service %s client %v, expected %s, got: %s", service, netaddr, expected, endpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,10 +130,11 @@ func TestLoadBalanceWorksWithMultipleEndpoints(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], nil)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
func TestLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
||||||
@ -127,21 +149,23 @@ func TestLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], nil)
|
||||||
// Then update the configuration with one fewer endpoints, make sure
|
// Then update the configuration with one fewer endpoints, make sure
|
||||||
// we start in the beginning again
|
// we start in the beginning again
|
||||||
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"},
|
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Endpoints: []string{"endpoint:8", "endpoint:9"},
|
Endpoints: []string{"endpoint:8", "endpoint:9"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:8", nil)
|
shuffledEndpoints = loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:9", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:8", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:9", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], nil)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], nil)
|
||||||
// Clear endpoints
|
// Clear endpoints
|
||||||
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Endpoints: []string{}}
|
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Endpoints: []string{}}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
@ -168,17 +192,19 @@ func TestLoadBalanceWorksWithServiceRemoval(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
shuffledFooEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[2], nil)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", nil)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], nil)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], nil)
|
||||||
|
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", nil)
|
shuffledBarEndpoints := loadBalancer.endpointsMap["bar"]
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], nil)
|
||||||
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], nil)
|
||||||
|
|
||||||
// Then update the configuration by removing foo
|
// Then update the configuration by removing foo
|
||||||
loadBalancer.OnUpdate(endpoints[1:])
|
loadBalancer.OnUpdate(endpoints[1:])
|
||||||
@ -188,10 +214,10 @@ func TestLoadBalanceWorksWithServiceRemoval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// but bar is still there, and we continue RR from where we left off.
|
// but bar is still there, and we continue RR from where we left off.
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], nil)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", nil)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStickyLoadBalanceWorksWithSingleEndpoint(t *testing.T) {
|
func TestStickyLoadBalanceWorksWithSingleEndpoint(t *testing.T) {
|
||||||
@ -232,14 +258,15 @@ func TestStickyLoadBalanaceWorksWithMultipleEndpoints(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStickyLoadBalanaceWorksWithMultipleEndpointsStickyNone(t *testing.T) {
|
func TestStickyLoadBalanaceWorksWithMultipleEndpointsStickyNone(t *testing.T) {
|
||||||
@ -259,14 +286,15 @@ func TestStickyLoadBalanaceWorksWithMultipleEndpointsStickyNone(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStickyLoadBalanaceWorksWithMultipleEndpointsRemoveOne(t *testing.T) {
|
func TestStickyLoadBalanaceWorksWithMultipleEndpointsRemoveOne(t *testing.T) {
|
||||||
@ -289,32 +317,45 @@ func TestStickyLoadBalanaceWorksWithMultipleEndpointsRemoveOne(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
client1Endpoint := shuffledEndpoints[0]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
|
client2Endpoint := shuffledEndpoints[1]
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client3)
|
||||||
|
client3Endpoint := shuffledEndpoints[2]
|
||||||
|
|
||||||
endpoints[0] = api.Endpoints{
|
endpoints[0] = api.Endpoints{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Endpoints: []string{"endpoint:1", "endpoint:2"},
|
Endpoints: []string{"endpoint:1", "endpoint:2"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints = loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
if client1Endpoint == "endpoint:3" {
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client3)
|
client1Endpoint = shuffledEndpoints[0]
|
||||||
|
} else if client2Endpoint == "endpoint:3" {
|
||||||
|
client2Endpoint = shuffledEndpoints[0]
|
||||||
|
} else if client3Endpoint == "endpoint:3" {
|
||||||
|
client3Endpoint = shuffledEndpoints[0]
|
||||||
|
}
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", client1Endpoint, client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", client2Endpoint, client2)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", client3Endpoint, client3)
|
||||||
|
|
||||||
endpoints[0] = api.Endpoints{
|
endpoints[0] = api.Endpoints{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:4"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:4"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints = loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", client1Endpoint, client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client3)
|
expectEndpoint(t, loadBalancer, "foo", client2Endpoint, client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client4)
|
expectEndpoint(t, loadBalancer, "foo", client3Endpoint, client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client5)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client4)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:4", client6)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client5)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client6)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStickyLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
func TestStickyLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
||||||
@ -334,24 +375,26 @@ func TestStickyLoadBalanceWorksWithMultipleEndpointsAndUpdates(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
Endpoints: []string{"endpoint:1", "endpoint:2", "endpoint:3"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
// Then update the configuration with one fewer endpoints, make sure
|
// Then update the configuration with one fewer endpoints, make sure
|
||||||
// we start in the beginning again
|
// we start in the beginning again
|
||||||
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"},
|
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"},
|
||||||
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:4", client1)
|
shuffledEndpoints = loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledEndpoints[1], client2)
|
||||||
|
|
||||||
// Clear endpoints
|
// Clear endpoints
|
||||||
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Endpoints: []string{}}
|
endpoints[0] = api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}, Endpoints: []string{}}
|
||||||
@ -384,19 +427,21 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) {
|
|||||||
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
Endpoints: []string{"endpoint:4", "endpoint:5"},
|
||||||
}
|
}
|
||||||
loadBalancer.OnUpdate(endpoints)
|
loadBalancer.OnUpdate(endpoints)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
shuffledFooEndpoints := loadBalancer.endpointsMap["foo"]
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:3", client3)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:1", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[2], client3)
|
||||||
expectEndpoint(t, loadBalancer, "foo", "endpoint:2", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], client2)
|
||||||
|
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
shuffledBarEndpoints := loadBalancer.endpointsMap["bar"]
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "foo", shuffledFooEndpoints[0], client1)
|
||||||
|
|
||||||
// Then update the configuration by removing foo
|
// Then update the configuration by removing foo
|
||||||
loadBalancer.OnUpdate(endpoints[1:])
|
loadBalancer.OnUpdate(endpoints[1:])
|
||||||
@ -406,10 +451,11 @@ func TestStickyLoadBalanceWorksWithServiceRemoval(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// but bar is still there, and we continue RR from where we left off.
|
// but bar is still there, and we continue RR from where we left off.
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
shuffledBarEndpoints = loadBalancer.endpointsMap["bar"]
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:5", client2)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], client1)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[1], client2)
|
||||||
expectEndpoint(t, loadBalancer, "bar", "endpoint:4", client1)
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], client1)
|
||||||
|
expectEndpoint(t, loadBalancer, "bar", shuffledBarEndpoints[0], client1)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user