Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backoff package and fix Consul CPU usage #635

Merged
merged 8 commits into from
Apr 2, 2018

Conversation

nicot
Copy link
Contributor

@nicot nicot commented Dec 3, 2017

Justification for jitter and growth factor: https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/.

Add backoff to the Consul instancer loop.

Fixes #627.

Justification for jitter and growth factor:
https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/.

Add backoff to the Consul instancer loop.

Fixes go-kit#627.
@rjeczalik
Copy link

rjeczalik commented Feb 8, 2018

If I may chime in with one comment about backoff package api.

Overall, the ExponentialBackoff design looks similar to this one. What I do not find good, as a user of the latter, is:

  • lack of meaningful zero-value - the zero-value ExponentialBackoff should use defaults, right now it won't work
  • requirement to call Reset() each time one changes ExponentialBackoff interval (which is not obvious and not documented)

From the minor stuff I think test should not call directly unexported methods of the type being tested.

@peterbourgon
Copy link
Member

Sorry I didn't see this originally, late last year was hectic time for me :(

Copy link
Member

@peterbourgon peterbourgon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feel like too much. What do you think of my alternative? Am I missing a key ingredient?


currentInterval atomic.Value
cancel <-chan struct{}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mixing exported and non-exported fields can be OK, but then you also mix direct and constructor initialization for this type, and combined I think that's a recipe for trouble...

d := float64(current * 2)
jitter := rand.Float64() + 0.5
return time.Duration(d * jitter)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this jitter bit is the real meat of the change. Rather than adding a new package, types, API, package docs, etc. — can you instead put this jitter calculation into the old exponential func, statelessly?

d = time.Minute
}
return d
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking a 1-line change can be enough, something like this, feel free to make corrections...

func exponential(d time.Duration) time.Duration {
    d *= 2
    if d > time.Minute {
        d = time.Minute
    }
    return d * (rand.Float64() + 0.5)
}

@peterbourgon
Copy link
Member

@nicot Ping? I'd love to be able to close the corresponding issue :)

@nicot
Copy link
Contributor Author

nicot commented Mar 19, 2018

Thanks for the review @rjeczalik and @peterbourgon.

I like your simple version a lot more @peterbourgon. There's a little bit of casting funkiness because duration is an int64 and we want to multiply it by a float, so let me know if there is a better way to do that.

Do you think the Exponential function belongs in the util/conn package? Or should it be somewhere more accessible?

@nicot
Copy link
Contributor Author

nicot commented Mar 30, 2018

@peterbourgon ping back at you =)

@@ -132,12 +133,15 @@ func dial(d Dialer, network, address string, logger log.Logger) net.Conn {
return conn
}

func exponential(d time.Duration) time.Duration {
func Exponential(d time.Duration) time.Duration {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get some doc string here? :)

@@ -70,6 +73,8 @@ func (s *Instancer) loop(lastIndex uint64) {
s.cache.Update(sd.Event{Err: err})
default:
s.cache.Update(sd.Event{Instances: instances})
time.Sleep(d)
d = conn.Exponential(d)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for not catching this earlier. We want to implement an upper limit e.g. 30s, and have a successful reconnect reset the d value to its default state.

@@ -59,6 +61,7 @@ func (s *Instancer) loop(lastIndex uint64) {
var (
instances []string
err error
d time.Duration = time.Millisecond * 10
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d = 10 * time.Millisecond is preferable here.

@peterbourgon
Copy link
Member

Still need an upper limit.

@nicot
Copy link
Contributor Author

nicot commented Apr 2, 2018

The upper limit is in the Exponential function -- Do you want both?

@peterbourgon
Copy link
Member

Oh! Gosh. Brainfart. Thanks!

@peterbourgon peterbourgon merged commit 91c58cc into go-kit:master Apr 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants