Use consul/lib's RateScaledInterval
This commit is contained in:
parent
26c9110e82
commit
e0e7d94450
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/consul/lib"
|
||||
"github.com/hashicorp/nomad/nomad/structs"
|
||||
)
|
||||
|
||||
|
@ -49,8 +50,7 @@ func (s *Server) resetHeartbeatTimer(id string) (time.Duration, error) {
|
|||
|
||||
// Compute the target TTL value
|
||||
n := len(s.heartbeatTimers)
|
||||
ttl := rateScaledInterval(s.config.MaxHeartbeatsPerSecond,
|
||||
s.config.MinHeartbeatTTL, n)
|
||||
ttl := lib.RateScaledInterval(s.config.MaxHeartbeatsPerSecond, s.config.MinHeartbeatTTL, n)
|
||||
ttl += randomStagger(ttl)
|
||||
|
||||
// Reset the TTL
|
||||
|
|
|
@ -122,16 +122,6 @@ func maxUint64(a, b uint64) uint64 {
|
|||
return b
|
||||
}
|
||||
|
||||
// rateScaledInterval is used to choose an interval to perform an action in order
|
||||
// to target an aggregate number of actions per second across the whole cluster.
|
||||
func rateScaledInterval(rate float64, min time.Duration, n int) time.Duration {
|
||||
interval := time.Duration(float64(time.Second) * float64(n) / rate)
|
||||
if interval < min {
|
||||
return min
|
||||
}
|
||||
return interval
|
||||
}
|
||||
|
||||
// seedRandom seeds the global random variable using a cryptographically random
|
||||
// seed. It returns an error if determing the random seed fails.
|
||||
func seedRandom() error {
|
||||
|
|
|
@ -98,26 +98,3 @@ func TestMaxUint64(t *testing.T) {
|
|||
t.Fatalf("bad")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRateScaledInterval(t *testing.T) {
|
||||
min := 1 * time.Second
|
||||
rate := 200.0
|
||||
if v := rateScaledInterval(rate, min, 0); v != min {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
if v := rateScaledInterval(rate, min, 100); v != min {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
if v := rateScaledInterval(rate, min, 200); v != 1*time.Second {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
if v := rateScaledInterval(rate, min, 1000); v != 5*time.Second {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
if v := rateScaledInterval(rate, min, 5000); v != 25*time.Second {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
if v := rateScaledInterval(rate, min, 10000); v != 50*time.Second {
|
||||
t.Fatalf("Bad: %v", v)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DurationMinusBuffer returns a duration, minus a buffer and jitter
|
||||
// subtracted from the duration. This function is used primarily for
|
||||
// servicing Consul TTL Checks in advance of the TTL.
|
||||
func DurationMinusBuffer(intv time.Duration, buffer time.Duration, jitter int64) time.Duration {
|
||||
d := intv - buffer
|
||||
if jitter == 0 {
|
||||
d -= RandomStagger(d)
|
||||
} else {
|
||||
d -= RandomStagger(time.Duration(int64(d) / jitter))
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// DurationMinusBufferDomain returns the domain of valid durations from a
|
||||
// call to DurationMinusBuffer. This function is used to check user
|
||||
// specified input values to DurationMinusBuffer.
|
||||
func DurationMinusBufferDomain(intv time.Duration, buffer time.Duration, jitter int64) (min time.Duration, max time.Duration) {
|
||||
max = intv - buffer
|
||||
if jitter == 0 {
|
||||
min = max
|
||||
} else {
|
||||
min = max - time.Duration(int64(max)/jitter)
|
||||
}
|
||||
return min, max
|
||||
}
|
||||
|
||||
// Returns a random stagger interval between 0 and the duration
|
||||
func RandomStagger(intv time.Duration) time.Duration {
|
||||
if intv == 0 {
|
||||
return 0
|
||||
}
|
||||
return time.Duration(uint64(rand.Int63()) % uint64(intv))
|
||||
}
|
||||
|
||||
// RateScaledInterval is used to choose an interval to perform an action in
|
||||
// order to target an aggregate number of actions per second across the whole
|
||||
// cluster.
|
||||
func RateScaledInterval(rate float64, min time.Duration, n int) time.Duration {
|
||||
const minRate = 1 / 86400 // 1/(1 * time.Day)
|
||||
if rate <= minRate {
|
||||
return min
|
||||
}
|
||||
interval := time.Duration(float64(time.Second) * float64(n) / rate)
|
||||
if interval < min {
|
||||
return min
|
||||
}
|
||||
|
||||
return interval
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package lib
|
||||
|
||||
func AbsInt(a int) int {
|
||||
if a > 0 {
|
||||
return a
|
||||
}
|
||||
return a * -1
|
||||
}
|
||||
|
||||
func MaxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func MinInt(a, b int) int {
|
||||
if a > b {
|
||||
return b
|
||||
}
|
||||
return a
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package lib
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
|
||||
// SeededSecurely is set to true if a cryptographically secure seed
|
||||
// was used to initialize rand. When false, the start time is used
|
||||
// as a seed.
|
||||
SeededSecurely bool
|
||||
)
|
||||
|
||||
// SeedMathRand provides weak, but guaranteed seeding, which is better than
|
||||
// running with Go's default seed of 1. A call to SeedMathRand() is expected
|
||||
// to be called via init(), but never a second time.
|
||||
func SeedMathRand() {
|
||||
once.Do(func() {
|
||||
n, err := crand.Int(crand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
rand.Seed(time.Now().UTC().UnixNano())
|
||||
return
|
||||
}
|
||||
rand.Seed(n.Int64())
|
||||
SeededSecurely = true
|
||||
})
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package lib
|
||||
|
||||
// StrContains checks if a list contains a string
|
||||
func StrContains(l []string, s string) bool {
|
||||
for _, v := range l {
|
||||
if v == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
Reference in New Issue