1
0
Fork 0

Add HighestRandomWeight Loadbalancing Algorithm

This commit is contained in:
mathieuHa 2025-09-08 12:00:42 +02:00 committed by GitHub
parent 9b42b5b930
commit 02443545e7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 936 additions and 112 deletions

View file

@ -28,6 +28,7 @@ import (
"github.com/traefik/traefik/v3/pkg/server/middleware"
"github.com/traefik/traefik/v3/pkg/server/provider"
"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/failover"
"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/hrw"
"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/mirror"
"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/p2c"
"github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr"
@ -137,6 +138,13 @@ func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string) (http.H
conf.AddError(err, true)
return nil, err
}
case conf.HighestRandomWeight != nil:
var err error
lb, err = m.getHRWServiceHandler(ctx, serviceName, conf.HighestRandomWeight)
if err != nil {
conf.AddError(err, true)
return nil, err
}
case conf.Mirroring != nil:
var err error
lb, err = m.getMirrorServiceHandler(ctx, conf.Mirroring)
@ -305,6 +313,40 @@ func (m *Manager) getServiceHandler(ctx context.Context, service dynamic.WRRServ
}
}
func (m *Manager) getHRWServiceHandler(ctx context.Context, serviceName string, config *dynamic.HighestRandomWeight) (http.Handler, error) {
// TODO Handle accesslog and metrics with multiple service name
balancer := hrw.New(config.HealthCheck != nil)
for _, service := range shuffle(config.Services, m.rand) {
serviceHandler, err := m.BuildHTTP(ctx, service.Name)
if err != nil {
return nil, err
}
balancer.Add(service.Name, serviceHandler, service.Weight, false)
if config.HealthCheck == nil {
continue
}
childName := service.Name
updater, ok := serviceHandler.(healthcheck.StatusUpdater)
if !ok {
return nil, fmt.Errorf("child service %v of %v not a healthcheck.StatusUpdater (%T)", childName, serviceName, serviceHandler)
}
if err := updater.RegisterStatusUpdater(func(up bool) {
balancer.SetStatus(ctx, childName, up)
}); err != nil {
return nil, fmt.Errorf("cannot register %v as updater for %v: %w", childName, serviceName, err)
}
log.Ctx(ctx).Debug().Str("parent", serviceName).Str("child", childName).
Msg("Child service will update parent on status change")
}
return balancer, nil
}
type serverBalancer interface {
http.Handler
healthcheck.StatusSetter
@ -346,6 +388,8 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
lb = wrr.New(service.Sticky, service.HealthCheck != nil)
case dynamic.BalancerStrategyP2C:
lb = p2c.New(service.Sticky, service.HealthCheck != nil)
case dynamic.BalancerStrategyHRW:
lb = hrw.New(service.HealthCheck != nil)
default:
return nil, fmt.Errorf("unsupported load-balancer strategy %q", service.Strategy)
}