Merge pull request #440 from github/throttle-http-freno-aware

freno-aware http-throttler
This commit is contained in:
Shlomi Noach 2017-07-09 07:38:34 +03:00 committed by GitHub
commit 787419ac2e

View File

@ -8,6 +8,7 @@ package logic
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"strings"
"sync/atomic" "sync/atomic"
"time" "time"
@ -18,6 +19,26 @@ import (
"github.com/outbrain/golib/sqlutils" "github.com/outbrain/golib/sqlutils"
) )
var (
httpStatusMessages map[int]string = map[int]string{
200: "OK",
404: "Not found",
417: "Expectation failed",
429: "Too many requests",
500: "Internal server error",
}
// See https://github.com/github/freno/blob/master/doc/http.md
httpStatusFrenoMessages map[int]string = map[int]string{
200: "OK",
404: "freno: unknown metric",
417: "freno: access forbidden",
429: "freno: threshold exceeded",
500: "freno: internal error",
}
)
const frenoMagicHint = "freno"
// Throttler collects metrics related to throttling and makes informed decisison // Throttler collects metrics related to throttling and makes informed decisison
// whether throttling should take place. // whether throttling should take place.
type Throttler struct { type Throttler struct {
@ -34,6 +55,17 @@ func NewThrottler(applier *Applier, inspector *Inspector) *Throttler {
} }
} }
func (this *Throttler) throttleHttpMessage(statusCode int) string {
statusCodesMap := httpStatusMessages
if throttleHttp := this.migrationContext.GetThrottleHTTP(); strings.Contains(throttleHttp, frenoMagicHint) {
statusCodesMap = httpStatusFrenoMessages
}
if message, ok := statusCodesMap[statusCode]; ok {
return fmt.Sprintf("%s (http=%d)", message, statusCode)
}
return fmt.Sprintf("http=%d", statusCode)
}
// shouldThrottle performs checks to see whether we should currently be throttling. // shouldThrottle performs checks to see whether we should currently be throttling.
// It merely observes the metrics collected by other components, it does not issue // It merely observes the metrics collected by other components, it does not issue
// its own metric collection. // its own metric collection.
@ -49,7 +81,7 @@ func (this *Throttler) shouldThrottle() (result bool, reason string, reasonHint
// HTTP throttle // HTTP throttle
statusCode := atomic.LoadInt64(&this.migrationContext.ThrottleHTTPStatusCode) statusCode := atomic.LoadInt64(&this.migrationContext.ThrottleHTTPStatusCode)
if statusCode != 0 && statusCode != http.StatusOK { if statusCode != 0 && statusCode != http.StatusOK {
return true, fmt.Sprintf("http=%d", statusCode), base.NoThrottleReasonHint return true, this.throttleHttpMessage(int(statusCode)), base.NoThrottleReasonHint
} }
// Replication lag throttle // Replication lag throttle
maxLagMillisecondsThrottleThreshold := atomic.LoadInt64(&this.migrationContext.MaxLagMillisecondsThrottleThreshold) maxLagMillisecondsThrottleThreshold := atomic.LoadInt64(&this.migrationContext.MaxLagMillisecondsThrottleThreshold)