-
Notifications
You must be signed in to change notification settings - Fork 92
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
feat(server): Expose rate limits for metrics #3347
Conversation
094a864
to
5395933
Compare
* master: fix(statsd): Prefix kafka client metrics (#3341)
// because `EnvelopeLimiter` cannot not check metrics without parsing item contents. | ||
if envelope.envelope().items().any(|i| i.ty().is_metrics()) { | ||
let metrics_scoping = scoping.item(DataCategory::MetricBucket); | ||
rate_limits.merge(self.rate_limits.check_with_quotas(quotas, metrics_scoping)); |
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.
This does not work yet. The scoping does not have a namespace, hence no quotas with namespaces match.
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.
Updated. We now check with MetricNamespaceScoping::Any
, which will resolve all metrics. This also makes the API a bit more explicit by adding specific doc comments for the semantics of None
.
* master: ref(cardinality): Pipeline Redis script invocations (#3321) ref(normalization): Remove StoreProcessor (#3097) feat(cardinality): Implement name based cardinality limits (#3313) instr(kafka): Tag existing metrics with variant (#3352) instr(kafka): More broker stats (#3349) instr(kafka): Improve produce error handling (#3351) feat(schema): Allow integers as username (#3328)
@@ -2010,44 +2012,31 @@ impl EnvelopeProcessorService { | |||
// We set over_accept_once such that the limit is actually reached, which allows subsequent | |||
// calls with quantity=0 to be rate limited. | |||
let over_accept_once = true; | |||
let mut rate_limits = RateLimits::new(); | |||
|
|||
for category in [DataCategory::Transaction, DataCategory::Span] { |
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.
Drive-by rewrite for readability.
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.
Thanks!
.check_with_quotas(project_state.get_quotas(), item_scoping); | ||
let limits = self.rate_limits().check_with_quotas( | ||
project_state.get_quotas(), | ||
scoping.item(DataCategory::MetricBucket), |
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.
This might be a bug, filed in #3354
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.
Just a couple of nits.
relay-quotas/src/rate_limit.rs
Outdated
scope: RateLimitScope::Organization(42), | ||
reason_code: None, | ||
retry_after: RetryAfter::from_secs(1), | ||
namespace: smallvec![MetricNamespace::Custom], |
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.
Should we run the same test against a RateLimit with empty namespaces?
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.
There are tests above that test with empty list on different data categories -- a rate limit on MetricBuckets without namespace would actually be semantically incorrect. Though it will work as the other tests ensure.
@@ -2010,44 +2012,31 @@ impl EnvelopeProcessorService { | |||
// We set over_accept_once such that the limit is actually reached, which allows subsequent | |||
// calls with quantity=0 to be rate limited. | |||
let over_accept_once = true; | |||
let mut rate_limits = RateLimits::new(); | |||
|
|||
for category in [DataCategory::Transaction, DataCategory::Span] { |
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.
Thanks!
@@ -35,6 +35,13 @@ pub fn format_rate_limits(rate_limits: &RateLimits) -> String { | |||
|
|||
if let Some(ref reason_code) = rate_limit.reason_code { | |||
write!(header, ":{reason_code}").ok(); | |||
} else if !rate_limit.namespace.is_empty() { | |||
write!(header, ":").ok(); |
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.
It took me a while to understand this code.
write!(header, ":").ok(); | |
write!(header, ":").ok(); // delimits the empty reason code |
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.
Thanks, the comment helps. I was hoping to rewrite this in a better way, but everything else I could come up with ended up much more complex.
Adds a new rate limit component to quota limits in the
x-sentry-rate-limits
header that communicates the namespace(s) that a metrics rate limit should apply to. The data category of limits that have this component is alwaysmetric_bucket
, in other quotas this component will not be set.Clients will receive rate limit entries in the response of every envelope that contains a metric item, regardless of whether the contents match the specific namespace. This is a performance optimization so Relay can avoid to parse item contents in the fast path while the request is still open.
Limitations:
Documentation is added via getsentry/develop#1205
Epic: https://github.com/getsentry/team-ingest/issues/303