Send 'Retry-After' to comply with RFC6585.
This commit is contained in:
parent
027093a5a5
commit
8d75aba7eb
29 changed files with 435 additions and 172 deletions
62
vendor/github.com/vulcand/oxy/roundrobin/rebalancer.go
generated
vendored
62
vendor/github.com/vulcand/oxy/roundrobin/rebalancer.go
generated
vendored
|
@ -16,13 +16,14 @@ import (
|
|||
// RebalancerOption - functional option setter for rebalancer
|
||||
type RebalancerOption func(*Rebalancer) error
|
||||
|
||||
// Meter measures server peformance and returns it's relative value via rating
|
||||
// Meter measures server performance and returns it's relative value via rating
|
||||
type Meter interface {
|
||||
Rating() float64
|
||||
Record(int, time.Duration)
|
||||
IsReady() bool
|
||||
}
|
||||
|
||||
// NewMeterFn type of functions to create new Meter
|
||||
type NewMeterFn func() (Meter, error)
|
||||
|
||||
// Rebalancer increases weights on servers that perform better than others. It also rolls back to original weights
|
||||
|
@ -52,8 +53,11 @@ type Rebalancer struct {
|
|||
stickySession *StickySession
|
||||
|
||||
requestRewriteListener RequestRewriteListener
|
||||
|
||||
log *log.Logger
|
||||
}
|
||||
|
||||
// RebalancerClock sets a clock
|
||||
func RebalancerClock(clock timetools.TimeProvider) RebalancerOption {
|
||||
return func(r *Rebalancer) error {
|
||||
r.clock = clock
|
||||
|
@ -61,6 +65,7 @@ func RebalancerClock(clock timetools.TimeProvider) RebalancerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// RebalancerBackoff sets a beck off duration
|
||||
func RebalancerBackoff(d time.Duration) RebalancerOption {
|
||||
return func(r *Rebalancer) error {
|
||||
r.backoffDuration = d
|
||||
|
@ -68,6 +73,7 @@ func RebalancerBackoff(d time.Duration) RebalancerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// RebalancerMeter sets a Meter builder function
|
||||
func RebalancerMeter(newMeter NewMeterFn) RebalancerOption {
|
||||
return func(r *Rebalancer) error {
|
||||
r.newMeter = newMeter
|
||||
|
@ -83,6 +89,7 @@ func RebalancerErrorHandler(h utils.ErrorHandler) RebalancerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// RebalancerStickySession sets a sticky session
|
||||
func RebalancerStickySession(stickySession *StickySession) RebalancerOption {
|
||||
return func(r *Rebalancer) error {
|
||||
r.stickySession = stickySession
|
||||
|
@ -90,7 +97,7 @@ func RebalancerStickySession(stickySession *StickySession) RebalancerOption {
|
|||
}
|
||||
}
|
||||
|
||||
// RebalancerErrorHandler is a functional argument that sets error handler of the server
|
||||
// RebalancerRequestRewriteListener is a functional argument that sets error handler of the server
|
||||
func RebalancerRequestRewriteListener(rrl RequestRewriteListener) RebalancerOption {
|
||||
return func(r *Rebalancer) error {
|
||||
r.requestRewriteListener = rrl
|
||||
|
@ -98,11 +105,14 @@ func RebalancerRequestRewriteListener(rrl RequestRewriteListener) RebalancerOpti
|
|||
}
|
||||
}
|
||||
|
||||
// NewRebalancer creates a new Rebalancer
|
||||
func NewRebalancer(handler balancerHandler, opts ...RebalancerOption) (*Rebalancer, error) {
|
||||
rb := &Rebalancer{
|
||||
mtx: &sync.Mutex{},
|
||||
next: handler,
|
||||
stickySession: nil,
|
||||
|
||||
log: log.StandardLogger(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := o(rb); err != nil {
|
||||
|
@ -134,6 +144,17 @@ func NewRebalancer(handler balancerHandler, opts ...RebalancerOption) (*Rebalanc
|
|||
return rb, nil
|
||||
}
|
||||
|
||||
// RebalancerLogger defines the logger the rebalancer will use.
|
||||
//
|
||||
// It defaults to logrus.StandardLogger(), the global logger used by logrus.
|
||||
func RebalancerLogger(l *log.Logger) RebalancerOption {
|
||||
return func(rb *Rebalancer) error {
|
||||
rb.log = l
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Servers gets all servers
|
||||
func (rb *Rebalancer) Servers() []*url.URL {
|
||||
rb.mtx.Lock()
|
||||
defer rb.mtx.Unlock()
|
||||
|
@ -142,8 +163,8 @@ func (rb *Rebalancer) Servers() []*url.URL {
|
|||
}
|
||||
|
||||
func (rb *Rebalancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
logEntry := log.WithField("Request", utils.DumpHttpRequest(req))
|
||||
if rb.log.Level >= log.DebugLevel {
|
||||
logEntry := rb.log.WithField("Request", utils.DumpHttpRequest(req))
|
||||
logEntry.Debug("vulcand/oxy/roundrobin/rebalancer: begin ServeHttp on request")
|
||||
defer logEntry.Debug("vulcand/oxy/roundrobin/rebalancer: completed ServeHttp on request")
|
||||
}
|
||||
|
@ -169,25 +190,25 @@ func (rb *Rebalancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
|
||||
if !stuck {
|
||||
url, err := rb.next.NextServer()
|
||||
fwdURL, err := rb.next.NextServer()
|
||||
if err != nil {
|
||||
rb.errHandler.ServeHTTP(w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
if log.GetLevel() >= log.DebugLevel {
|
||||
//log which backend URL we're sending this request to
|
||||
log.WithFields(log.Fields{"Request": utils.DumpHttpRequest(req), "ForwardURL": url}).Debugf("vulcand/oxy/roundrobin/rebalancer: Forwarding this request to URL")
|
||||
// log which backend URL we're sending this request to
|
||||
log.WithFields(log.Fields{"Request": utils.DumpHttpRequest(req), "ForwardURL": fwdURL}).Debugf("vulcand/oxy/roundrobin/rebalancer: Forwarding this request to URL")
|
||||
}
|
||||
|
||||
if rb.stickySession != nil {
|
||||
rb.stickySession.StickBackend(url, &w)
|
||||
rb.stickySession.StickBackend(fwdURL, &w)
|
||||
}
|
||||
|
||||
newReq.URL = url
|
||||
newReq.URL = fwdURL
|
||||
}
|
||||
|
||||
//Emit event to a listener if one exists
|
||||
// Emit event to a listener if one exists
|
||||
if rb.requestRewriteListener != nil {
|
||||
rb.requestRewriteListener(req, &newReq)
|
||||
}
|
||||
|
@ -215,6 +236,7 @@ func (rb *Rebalancer) reset() {
|
|||
rb.ratings = make([]float64, len(rb.servers))
|
||||
}
|
||||
|
||||
// Wrap sets the next handler to be called by rebalancer handler.
|
||||
func (rb *Rebalancer) Wrap(next balancerHandler) error {
|
||||
if rb.next != nil {
|
||||
return fmt.Errorf("already bound to %T", rb.next)
|
||||
|
@ -223,6 +245,7 @@ func (rb *Rebalancer) Wrap(next balancerHandler) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// UpsertServer upsert a server
|
||||
func (rb *Rebalancer) UpsertServer(u *url.URL, options ...ServerOption) error {
|
||||
rb.mtx.Lock()
|
||||
defer rb.mtx.Unlock()
|
||||
|
@ -239,6 +262,7 @@ func (rb *Rebalancer) UpsertServer(u *url.URL, options ...ServerOption) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RemoveServer remove a server
|
||||
func (rb *Rebalancer) RemoveServer(u *url.URL) error {
|
||||
rb.mtx.Lock()
|
||||
defer rb.mtx.Unlock()
|
||||
|
@ -289,7 +313,7 @@ func (rb *Rebalancer) findServer(u *url.URL) (*rbServer, int) {
|
|||
return nil, -1
|
||||
}
|
||||
|
||||
// Called on every load balancer ServeHTTP call, returns the suggested weights
|
||||
// adjustWeights Called on every load balancer ServeHTTP call, returns the suggested weights
|
||||
// on every call, can adjust weights if needed.
|
||||
func (rb *Rebalancer) adjustWeights() {
|
||||
rb.mtx.Lock()
|
||||
|
@ -319,7 +343,7 @@ func (rb *Rebalancer) adjustWeights() {
|
|||
|
||||
func (rb *Rebalancer) applyWeights() {
|
||||
for _, srv := range rb.servers {
|
||||
log.Debugf("upsert server %v, weight %v", srv.url, srv.curWeight)
|
||||
rb.log.Debugf("upsert server %v, weight %v", srv.url, srv.curWeight)
|
||||
rb.next.UpsertServer(srv.url, Weight(srv.curWeight))
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +355,7 @@ func (rb *Rebalancer) setMarkedWeights() bool {
|
|||
if srv.good {
|
||||
weight := increase(srv.curWeight)
|
||||
if weight <= FSMMaxWeight {
|
||||
log.Debugf("increasing weight of %v from %v to %v", srv.url, srv.curWeight, weight)
|
||||
rb.log.Debugf("increasing weight of %v from %v to %v", srv.url, srv.curWeight, weight)
|
||||
srv.curWeight = weight
|
||||
changed = true
|
||||
}
|
||||
|
@ -378,7 +402,7 @@ func (rb *Rebalancer) markServers() bool {
|
|||
}
|
||||
}
|
||||
if len(g) != 0 && len(b) != 0 {
|
||||
log.Debugf("bad: %v good: %v, ratings: %v", b, g, rb.ratings)
|
||||
rb.log.Debugf("bad: %v good: %v, ratings: %v", b, g, rb.ratings)
|
||||
}
|
||||
return len(g) != 0 && len(b) != 0
|
||||
}
|
||||
|
@ -433,9 +457,8 @@ func decrease(target, current int) int {
|
|||
adjusted := current / FSMGrowFactor
|
||||
if adjusted < target {
|
||||
return target
|
||||
} else {
|
||||
return adjusted
|
||||
}
|
||||
return adjusted
|
||||
}
|
||||
|
||||
// rebalancer server record that keeps track of the original weight supplied by user
|
||||
|
@ -448,9 +471,9 @@ type rbServer struct {
|
|||
}
|
||||
|
||||
const (
|
||||
// This is the maximum weight that handler will set for the server
|
||||
// FSMMaxWeight is the maximum weight that handler will set for the server
|
||||
FSMMaxWeight = 4096
|
||||
// Multiplier for the server weight
|
||||
// FSMGrowFactor Multiplier for the server weight
|
||||
FSMGrowFactor = 4
|
||||
)
|
||||
|
||||
|
@ -460,10 +483,12 @@ type codeMeter struct {
|
|||
codeE int
|
||||
}
|
||||
|
||||
// Rating gets ratio
|
||||
func (n *codeMeter) Rating() float64 {
|
||||
return n.r.Ratio()
|
||||
}
|
||||
|
||||
// Record records a meter
|
||||
func (n *codeMeter) Record(code int, d time.Duration) {
|
||||
if code >= n.codeS && code < n.codeE {
|
||||
n.r.IncA(1)
|
||||
|
@ -472,6 +497,7 @@ func (n *codeMeter) Record(code int, d time.Duration) {
|
|||
}
|
||||
}
|
||||
|
||||
// IsReady returns true if the counter is ready
|
||||
func (n *codeMeter) IsReady() bool {
|
||||
return n.r.IsReady()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue