-
Notifications
You must be signed in to change notification settings - Fork 24.9k
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
Rate of increase for monotonic counter #60619
Comments
Pinging @elastic/es-analytics-geo (:Analytics/Aggregations) |
Adding our use case: In APM we use a combination of a {
aggs: {
over_time: {
date_histogram: getMetricsDateHistogramParams(start, end),
aggs: {
// get the max value
max: {
max: {
field: fieldName,
},
},
// get the derivative, which is the delta y
derivative: {
derivative: {
buckets_path: 'max',
},
},
// if a gc counter is reset, the delta will be >0 and
// needs to be excluded
value: {
bucket_script: {
buckets_path: { value: 'derivative' },
script: 'params.value > 0.0 ? params.value : 0.0',
},
},
},
},
}
} |
@dgieselaar The main reason to ask for a new metric aggregation in Elasticsearch is to avoid the edge cases with the approach you've described:
Here's an example of three separate counters that might have different resets: Based on this example, I would expect that:
|
Hey, I just want to check in on the requirements here. I spoke a bit with @wylieconlon , and he suggested I tag @exekias for input as well. Here's a couple of scenarios I'm looking at, and would like your feedback on. In all examples, I'm showing data as pairs of numbers, with the first representing a time and the second representing the counter value (I'm assuming it's in bytes of network data, just to have some unit to talk about). For ease of typing, I'm writing time in seconds from some nominal T=0 which will be the start of our observations. Obviously in a real application these would be milliseconds since epoch timestamps. Simple case: (0, 1000), (10, 1100), (20, 1200), (30, 1300), (40, 1400), (50, 1500), (60, 1600) In this case, we have a total of 600 bytes over 60 seconds, for a rate of 10 bytes / second, assuming a 1 minute bucket. Spike case: (0, 1000), (10, 1000), (20, 1000), (30, 1000), (40, 1600), (50, 1600), (60, 1600) Reset case 1: (0, 1000), (10, 1100), (20, 100), (30, 200), (40, 300), (50, 400), (60, 500) Reset case 2: (0, 2^32 - 1000200), (10, 2^32 - 1000100), (20, 100), (30, 200), (40, 300), (50, 400), (60, 500) Thanks in advance for your input. |
I see the point about not interpreting that counter reached MAX_INT when we have a reset, but we still have some information after reset: For case 1: (0, 1000), (10, 1100), (20, 100), (30, 200), (40, 300), (50, 400), (60, 500) at time 20 you detect the counter reset, ignoring it would mean reporting a rate of 0 here (?). Still we know that it raised by at least 100 since the previous sample. So you could "interpret" the data as this, making no assumptions on the max number that was reached before reset: (0, 1000), (10, 1100), (20, 1100+100), (30, 1100+200), (40, 1100+300), (50, 1100+400), (60, 1100+500) For case 2: (0, 2^32 - 1000200), (10, 2^32 - 1000100), (20, 100), (30, 200), (40, 300), (50, 400), (60, 500) (0, 2^32 - 1000200), (10, 2^32 - 1000100), (20, 2^32 - 1000100 + 100), (30, 2^32 - 1000100 + 200), (40, 2^32 - 1000100+ 300), (50, 2^32 - 1000100 + 400), (60, 2^32 - 1000100 + 500) This, when compared to taking the positive values only at least takes into account the data we have just after a counter reset, which may of course be incomplete, but better than filling with a 0. It would be good to also try to think about these scenarios when samples are split in several buckets, for instance, 10s bucket would leave you with one value per bucket. I understand this aggregation would take the value from the previous bucket into account when calculating the rate for the next one? |
@exekias I think you are describing the following algorithms in pseudocode.
rate = 0
loop_over_values(lambda (current, previous):
if current >= previous:
rate = rate + (current - previous)
else:
rate = rate + current
) This is different from the other algorithms that we could use, which are:
If we had perfect information, I think 2 would be correct most of the time. But I see your point that without perfect information, 1 might be the closest. There is an edge case that happens pretty often in Metricbeat data, which I want to add here. If the user is requesting the positive rate of a field that is coming from multiple counters, none of these algorithms will catch this and all will produce crazy results:
The question I have for all of you is: are we okay with the potential for user errors here? I think it could go both ways. |
Any new year updates on this? Just had it pop up again in a troubleshooting session regarding a graph of Given our own components have a lot of monotonic counters, it'd be great to have better support for them in ES. For the time being we can get by with TSVB's "Positive Rate" and a 1k "top" value at least. |
@matschaffer It turned out to be much trickier than we originally thought. The main challenge here is scalability. In the current framework, the data that we get is not sorted and distributed across multiple shards. So, in general the issue is not really solvable unless we ship all data to a coordinating node and sort it there unless we change the way we store the data or come up with some heuristic approach. |
That’s unfortunate, but understandable. Should we pursue something at another layer maybe? (Roll up counters to gauges for example) The stack itself produces a many counters today and we’ll probably get more over time (thinking especially about cases like apm agent collecting Prometheus counters). @jasontedor or @tbragin any thoughts on how we should proceed? |
@matschaffer we understand the importance of this feature and it is still high on our priority list. One of the ideas that we wanted to prototype is timestamps sorted indices routed by the counter id. That would allow us to resolve some of the issues mentioned above. There is still an issues of index rollover, but somewhat smaller one if we can ensure that the earliest data point in the later index is always after the latest data point in the earlier index, which would also require some sort of routing mechanism that we don't have at the moment. Another approach that we discussed was to create some sort of streaming API producing sorted data to clients, again tricky and not ideal since each client will have to do their own implementation and we will not be able to wrap it into other aggregations, etc. |
Yeah, streaming API to clients sounds like it could be tricky to build visualizations and alerts on (which would be the end usage for many of these counters). Thanks for confirming the priority. Hopefully we can find some path forward. We'll keep our top:N graphs and alerts tuned high (at least 1k) in the mean time to help avoid fresh counters getting overlooked. |
I think the rate agg on counter field implements what is being asked here. |
Elasticsearch should provide a new metric aggregation for use only in date histograms, which is able to calculate the increase in a monotonic counter. Because the value of a counter is always increasing, it occasionally resets from the maximum value to 0. These resets should be handled automatically by the aggregation. This aggregation requires documents to be sorted in increasing time order.
This aggregation should throw an error if values aren't monotonically increasing. The most common reason for this will be multiple sources of documents, such as multiple servers with separate counters. The error message should indicate to the user to add another bucket aggregation such as
terms of host.name
.The aggregation should also allow scaling to a time unit like the derivative pipeline aggregation.
Use cases for this already exist in most
beats
modules. For example,system.network.in.bytes
is a counter-type field that will generally be converted into a "rate per second."The text was updated successfully, but these errors were encountered: