Skip to content

Adopting DDSketch as the default ValueRecorder aggregation #919

@jmacd

Description

@jmacd

Issue #636 describes a number of considerations surrounding the choice of a default aggregation for ValueRecorder instruments, where "Last Value", "Histogram", "MinMaxSumCount", "Sketch", and "Exact" are the choices, and prior draft specifications have stated MinMaxSumCount as the default, which corresponds with a Prometheus Summary (Sum, Count) containing the p0 and p100 percentiles (a.k.a. Min and Max)--this is a trivially mergeable summary, but not always the most desired format.

A leading option that has wide support is the use of DDSketch, which has a number of DataDog open-source implementations (e.g., Golang, Python, Java).

See the protocol definition used in the DataDog agent. This is (unfortunately) not commented. This issue proposes that we settle the open question in #636 as proposed, by specifying DDSketch as the default aggregation. To make this happen, ideally a contributor from DataDog would make a pull request to https://github.com/open-telemetry/opentelemetry-proto with a documented protocol (AI: @mikezvi find us contributor(s)?) for DDSketch aggregations.

Reviewing the current agent payload protocol used by DataDog suggests that the protocol makes assumptions about the configuration of the algorithm. Compare and contrast the implementation used by the DD agent:

https://github.com/DataDog/datadog-agent/blob/master/pkg/quantile/config.go

and the "clean" implementation here:

https://github.com/DataDog/sketches-go/tree/master/ddsketch

We see different default configurations. In the agent:

const (
	defaultBinLimit = 4096
	defaultEps      = 1.0 / 128.0
	defaultMin      = 1e-9
)

and in the separate implementation:

const (
	defaultMaxNumBins = 2048
	defaultAlpha      = 0.01
	defaultMinValue   = 1.0e-9
)

The paper states, " As an example, for α = 0.01, a sketch of size 2048 can handle values from 80 microseconds to 1 year, and cover all quantiles." I studied this for a while and had trouble understanding how to get from the settings above to the value of either 80 microseconds or 1 year--particularly note that the paper does not discuss the defaultMinValue setting and that the code contains a concept of "key offset" that is also not included in the paper. DataDog (@mikezvi) I would like your help clarifying some of these aspects and, ideally, publishing more exact pseudocode descriptions of the actual algorithm used. Simply stated: your pseudocode in the paper does not closely match your real code. For example, Algorithm 3 in the paper is under 10 lines of pseudocode and uses a linear scan, whereas it is actually implemented by helpers named growLeft and growRight (~80 lines of code). These helpers are not symmetric, not documented, and not described in the paper. I'd like to see more.

Assuming we can resolve these issues (which I'm confident we can), the DDSketch algorithm looks like a winner. I believe that the DD agent-payload protocol linked above is based on an assumption that the default values are fixed, not variable, as they are not included in the protocol. Based on this, a rough draft for the documented protocol might look like:

message DDSketchDataPoint {
        // Standard OTel Metics data point fields:
	//   Labels = 1
	//   StartTimeUnixNanos = 2
	//   TimeUnixNanos = 3

        // These four fields carry the MinMaxSumCount aggregation.

	// cnt is the number of points described in this sketch
	int64 cnt = 4;
	// min is the smallest value among points described in this sketch
	double min = 5;
	// max is the largest value among points described in this sketch
	double max = 6;
	// sum is the sum of value among points described in this sketch
	double sum = 7;

	// sketch configuration: AI(DataDog) write lengthy comments here including
	// the equations to map from `k` values below into bin boundaries.
	double minValue = 8;   // default is 1e-9
	int64 maxBins = 9;     // default is 2048
	int64 alpha = 10;      // default is 0.01

	// k are the key values used in the equations above to calculate boundaries
	// of the bins representing this sketch.  Note these are signed and use zigzag
	// encoding.
	repeated sint32 k = 7;

	// n are the counts associated with the bins whose boundaries are set by k.
	repeated int64 n = 8;

	// TODO(bogdandrutu) maybe argue for fixed64 instead of int64 above?
}

As you can see, I added three fields to express the configuration parameters used in the sketch. I have concerns about representing these values directly, though, since they do not clearly map into the minimum and maximum values expressible by the sketch (i.e., the connection between these parameters and the 80 microseconds and 1 year figures are not clear, and it's those figures that users actually care about).

Resolves #636.
Closes open-telemetry/oteps#117.
Closes open-telemetry/oteps#118.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:sdkRelated to the SDKpriority:p1Highest priority levelrelease:required-for-gaMust be resolved before GA release, or nice to have before GAspec:metricsRelated to the specification/metrics directory

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions