Consistent hashing to a subset of nodes. It works like consistent hash,
but instead of mapping to a single node, we map to a subset of nodes.
This commit is contained in:
parent
29118750be
commit
60b983503b
17 changed files with 434 additions and 17 deletions
|
|
@ -92,7 +92,7 @@ type Ingress struct {
|
|||
SessionAffinity sessionaffinity.Config
|
||||
SSLPassthrough bool
|
||||
UsePortInRedirects bool
|
||||
UpstreamHashBy string
|
||||
UpstreamHashBy upstreamhashby.Config
|
||||
LoadBalancing string
|
||||
UpstreamVhost string
|
||||
Whitelist ipwhitelist.SourceRange
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ func TestUpstreamHashBy(t *testing.T) {
|
|||
|
||||
for _, foo := range fooAnns {
|
||||
ing.SetAnnotations(foo.annotations)
|
||||
r := ec.Extract(ing).UpstreamHashBy
|
||||
r := ec.Extract(ing).UpstreamHashBy.UpstreamHashBy
|
||||
if r != foo.er {
|
||||
t.Errorf("Returned %v but expected %v", r, foo.er)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,14 +27,27 @@ type upstreamhashby struct {
|
|||
r resolver.Resolver
|
||||
}
|
||||
|
||||
// NewParser creates a new CORS annotation parser
|
||||
// Config contains the Consistent hash configuration to be used in the Ingress
|
||||
type Config struct {
|
||||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
||||
UpstreamHashBySubset bool `json:"upstream-hash-by-subset,omitempty"`
|
||||
UpstreamHashBySubsetSize int `json:"upstream-hash-by-subset-size,omitempty"`
|
||||
}
|
||||
|
||||
// NewParser creates a new UpstreamHashBy annotation parser
|
||||
func NewParser(r resolver.Resolver) parser.IngressAnnotation {
|
||||
return upstreamhashby{r}
|
||||
}
|
||||
|
||||
// Parse parses the annotations contained in the ingress rule
|
||||
// used to indicate if the location/s contains a fragment of
|
||||
// configuration to be included inside the paths of the rules
|
||||
func (a upstreamhashby) Parse(ing *extensions.Ingress) (interface{}, error) {
|
||||
return parser.GetStringAnnotation("upstream-hash-by", ing)
|
||||
upstreamHashBy, _ := parser.GetStringAnnotation("upstream-hash-by", ing)
|
||||
upstreamHashBySubset, _ := parser.GetBoolAnnotation("upstream-hash-by-subset", ing)
|
||||
upstreamHashbySubsetSize, _ := parser.GetIntAnnotation("upstream-hash-by-subset-size", ing)
|
||||
|
||||
if upstreamHashbySubsetSize == 0 {
|
||||
upstreamHashbySubsetSize = 3
|
||||
}
|
||||
|
||||
return &Config{upstreamHashBy, upstreamHashBySubset, upstreamHashbySubsetSize}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,12 @@ func TestParse(t *testing.T) {
|
|||
for _, testCase := range testCases {
|
||||
ing.SetAnnotations(testCase.annotations)
|
||||
result, _ := ap.Parse(ing)
|
||||
if result != testCase.expected {
|
||||
uc, ok := result.(*Config)
|
||||
if !ok {
|
||||
t.Fatalf("expected a Config type")
|
||||
}
|
||||
|
||||
if uc.UpstreamHashBy != testCase.expected {
|
||||
t.Errorf("expected %v but returned %v, annotations: %s", testCase.expected, result, testCase.annotations)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -660,9 +660,13 @@ func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.B
|
|||
if upstreams[defBackend].SecureCACert.Secret == "" {
|
||||
upstreams[defBackend].SecureCACert = anns.SecureUpstream.CACert
|
||||
}
|
||||
if upstreams[defBackend].UpstreamHashBy == "" {
|
||||
upstreams[defBackend].UpstreamHashBy = anns.UpstreamHashBy
|
||||
|
||||
if upstreams[defBackend].UpstreamHashBy.UpstreamHashBy == "" {
|
||||
upstreams[defBackend].UpstreamHashBy.UpstreamHashBy = anns.UpstreamHashBy.UpstreamHashBy
|
||||
upstreams[defBackend].UpstreamHashBy.UpstreamHashBySubset = anns.UpstreamHashBy.UpstreamHashBySubset
|
||||
upstreams[defBackend].UpstreamHashBy.UpstreamHashBySubsetSize = anns.UpstreamHashBy.UpstreamHashBySubsetSize
|
||||
}
|
||||
|
||||
if upstreams[defBackend].LoadBalancing == "" {
|
||||
upstreams[defBackend].LoadBalancing = anns.LoadBalancing
|
||||
}
|
||||
|
|
@ -724,8 +728,10 @@ func (n *NGINXController) createUpstreams(data []*ingress.Ingress, du *ingress.B
|
|||
upstreams[name].SecureCACert = anns.SecureUpstream.CACert
|
||||
}
|
||||
|
||||
if upstreams[name].UpstreamHashBy == "" {
|
||||
upstreams[name].UpstreamHashBy = anns.UpstreamHashBy
|
||||
if upstreams[name].UpstreamHashBy.UpstreamHashBy == "" {
|
||||
upstreams[name].UpstreamHashBy.UpstreamHashBy = anns.UpstreamHashBy.UpstreamHashBy
|
||||
upstreams[name].UpstreamHashBy.UpstreamHashBySubset = anns.UpstreamHashBy.UpstreamHashBySubset
|
||||
upstreams[name].UpstreamHashBy.UpstreamHashBySubsetSize = anns.UpstreamHashBy.UpstreamHashBySubsetSize
|
||||
}
|
||||
|
||||
if upstreams[name].LoadBalancing == "" {
|
||||
|
|
|
|||
|
|
@ -113,6 +113,14 @@ type Backend struct {
|
|||
// http://nginx.org/en/docs/http/ngx_http_upstream_module.html#hash
|
||||
UpstreamHashBy string `json:"upstream-hash-by"`
|
||||
|
||||
// Consistent hashing subset flag.
|
||||
// Default: false
|
||||
UpstreamHashBySubset bool `json:"upstream-hash-by-subset"`
|
||||
|
||||
// Subset consistent hashing, subset size.
|
||||
// Default 3
|
||||
UpstreamHashBySubsetSize int `json:"upstream-hash-by-subset-size"`
|
||||
|
||||
// Let's us choose a load balancing algorithm per ingress
|
||||
LoadBalancing string `json:"load-balance"`
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ type Backend struct {
|
|||
// StickySessionAffinitySession contains the StickyConfig object with stickyness configuration
|
||||
SessionAffinity SessionAffinityConfig `json:"sessionAffinityConfig"`
|
||||
// Consistent hashing by NGINX variable
|
||||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
||||
UpstreamHashBy UpstreamHashByConfig `json:"upstreamHashByConfig,omitempty"`
|
||||
// LB algorithm configuration per ingress
|
||||
LoadBalancing string `json:"load-balance,omitempty"`
|
||||
// Denotes if a backend has no server. The backend instead shares a server with another backend and acts as an
|
||||
|
|
@ -150,6 +150,13 @@ type CookieSessionAffinity struct {
|
|||
Path string `json:"path,omitempty"`
|
||||
}
|
||||
|
||||
// UpstreamHashByConfig described setting from the upstream-hash-by* annotations.
|
||||
type UpstreamHashByConfig struct {
|
||||
UpstreamHashBy string `json:"upstream-hash-by,omitempty"`
|
||||
UpstreamHashBySubset bool `json:"upstream-hash-by-subset,omitempty"`
|
||||
UpstreamHashBySubsetSize int `json:"upstream-hash-by-subset-size,omitempty"`
|
||||
}
|
||||
|
||||
// Endpoint describes a kubernetes endpoint in a backend
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Endpoint struct {
|
||||
|
|
|
|||
|
|
@ -234,6 +234,27 @@ func (csa1 *CookieSessionAffinity) Equal(csa2 *CookieSessionAffinity) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
//Equal checks the equality between UpstreamByConfig types
|
||||
func (u1 *UpstreamHashByConfig) Equal(u2 *UpstreamHashByConfig) bool {
|
||||
if u1 == u2 {
|
||||
return true
|
||||
}
|
||||
if u1 == nil || u2 == nil {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBy != u2.UpstreamHashBy {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBySubset != u2.UpstreamHashBySubset {
|
||||
return false
|
||||
}
|
||||
if u1.UpstreamHashBySubsetSize != u2.UpstreamHashBySubsetSize {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Equal checks the equality against an Endpoint
|
||||
func (e1 *Endpoint) Equal(e2 *Endpoint) bool {
|
||||
if e1 == e2 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue