-
Notifications
You must be signed in to change notification settings - Fork 812
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 global ingestion rate limiter to distributors #1766
Add global ingestion rate limiter to distributors #1766
Conversation
6da7da1
to
3b3dbb3
Compare
I don't want to maintain another way of doing service discovery tbh. I'd would just use the current one again. There is no proof that the current method is limiting us in a anyway and my guess would be that people would be inclined to use the gossip backend for rate-limiting SD which should be even lesser IO. If we find that the ring based implementation is too IO intensive / becoming a bottleneck, we can then add a new one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice work. This is a straightforward extension of ring idea. I like that.
This code is reusing existing KVStore, but is storing a different structure into it, under a different key. I think that makes sense, instead of making ring structure bigger. It's written in a generic way (I don't see a need for that, for now, but is harmless otherwise) and called "service discovery", but idea is the same as in the ring (without tokens). |
a005da6
to
714be9f
Compare
@pstibrany and @gouthamve thanks for your comments. I've addressed the feedback:
May you do another round of review, please? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Nice work. (I like fixed error messages 👍 )
142945c
to
15350c1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still looks good to me :-)
ca48988
to
7b42491
Compare
7b42491
to
0dd49d3
Compare
0dd49d3
to
c8648ee
Compare
Ping @gouthamve? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
One nit and a suggestion if you have a chance. It would be nice to reuse the NoopFlushTransferer in the ruler. Currently the ruler basically implements NoopFlushTransferer
itself.
} | ||
|
||
// RegisterFlags adds the flags required to config this to the given FlagSet | ||
func (cfg *RingConfig) RegisterFlags(f *flag.FlagSet) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something similar for this would be nice for the ruler. The main difference being the number of tokens. However, that can probably be figured out at another time. Maybe the ring package could use a refactor to make it more friendly to simpler use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. I would suggest to keep ruler's refactoring as a separate PR, given it's not related to this work. I will add it to my backlog.
// be used in cases we don't need one | ||
type NoopFlushTransferer struct{} | ||
|
||
// NewNoopFlushTransferer makes a new NoopFlushTransferer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ruler has identical functionality in pkg/ruler/lifecycle.go
it would be cool to delete that and reuse this instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ruler Flush()
is not a noop. Currently the NoopFlushTransferer
is a adopt all or nothing: how would you see reusing it in the ruler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, I forgot the change to make the ruler flush has not been merged yet:
https://github.com/cortexproject/cortex/pull/1571/files#diff-95b5a43683ab83429e93fef5c5daf87fL26
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem. We can use the NoopFlushTransferer
in the ruler as soon as the PR 1571 will be merged.
c8648ee
to
b018af5
Compare
Nice work -- I like the ring re-use. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but have some minor nits!
pkg/distributor/distributor.go
Outdated
if d.cfg.LimiterReloadPeriod == 0 { | ||
return | ||
} | ||
if !canJoinRing { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified to:
if !canJoinRing {
ingestionRateStrategy = newLocalIngestionRateStrategy(limits)
} else if limits.IngestionRateStrategy() == validation.GlobalIngestionRateStrategy {
distributorsRing, err = ring.NewLifecycler(cfg.DistributorRing.ToLifecyclerConfig(), nil, "distributor", ring.DistributorRingKey)
if err != nil {
return nil, err
}
distributorsRing.Start()
ingestionRateStrategy = newGlobalIngestionRateStrategy(limits, distributorsRing)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this means that it's never going to be infinite, maybe double the logic once?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure. I think the current logic is safer and the intention is more clear (when it's an internal dependency, do not configure any rate limit at all).
241aaf4
to
f209bfc
Compare
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
…ke it more clear Signed-off-by: Marco Pracucci <[email protected]>
…ssarily a ring of ingesters backed by consul Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
Signed-off-by: Marco Pracucci <[email protected]>
bc5f1d0
to
738b5d7
Compare
cfg.DistributorRing.HeartbeatPeriod = 100 * time.Millisecond | ||
cfg.DistributorRing.InstanceID = strconv.Itoa(rand.Int()) | ||
cfg.DistributorRing.KVStore.Mock = kvStore | ||
cfg.DistributorRing.InstanceInterfaceNames = []string{"eth0", "en0", "lo0"} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TestDistributor_PushIngestionRateLimiter
fails in my local machine because none of these interfaces match :/ I will open a PR to get it from the system so that tests pass on all machines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Following up this design doc, in this PR I'm proposing to introduce a global ingestion rate limiter implemented as a local rate limiter configured with
limit / N
, whereN
is the actual number of distributors.Fixes #1090
Notes about the distributors ring
We currently don't have a ring of distributors, so I had to introduce it.
For this purpose, in this PR I'm proposing to introduce a generic simple service discovery based on the KVStore, instead of the ring itself. It's an opinionated change. If there's no consensus, I can rollback to reuse the ring implementation for distributors too.From my perspective, a generic lightweight internal service discovery/registry would be just easier to plug compared to the current ring, because of:No need to have a real ring (ie. no need for tokens)No need to deal withIngesterState
No need to haveFlushTransferer
Notes about alternatives