Dataway Tail Sampling¶
Feature Overview¶
Dataway provides tail sampling capabilities with the following external interfaces:
/v1/tail_sampling(raw payload; compatible with Datakit 2.10's zstd payload without header)/v1/tail_sampling_v2(legacy raw compatibility path)/v2/tail_sampling(zstd payload)/v1/tail_sampling_config
Tail sampling first receives data grouped at the Dataway side, then decides whether to retain or discard based on sampling rules, and finally writes the retained data to the center.
Currently, three types of data are supported:
tracingloggingrum
The basic processing flow is as follows:
sequenceDiagram
autonumber
participant dk as Datakit/Client
participant dw as Dataway
participant ts as TailSamplingProcessor
participant kodo as Kodo
dk ->> dw: POST /v2/tail_sampling(zstd)或 /v1/tail_sampling(raw)
alt config ready
dw ->> ts: ingest packet
ts ->> dw: kept packets
dw ->> kodo: write tracing/logging/rum
else config not ready
dw ->> dw: pending cache
dw -->> dk: 412 Precondition Failed
dk ->> dw: POST /v1/tail_sampling_config
dw ->> ts: update config and drain pending
end
Working Modes¶
Tail sampling and aggregation share the same mode configuration:
standaloneproxy
standalone¶
In standalone mode, the current Dataway directly processes tail sampling data:
- Receives protobuf-encoded
aggregate.DataPacket - Looks up the tail sampling configuration by
token + data_type - When the configuration is ready, writes directly to
TailSamplingProcessor - Periodically extracts expired groups and sends them to the corresponding data type write interface
In the current implementation:
- The sampling window advancement period is 1 second
- The derived metric refresh period is 1 minute
- The sending phase uses a worker pool for asynchronous writes
proxy¶
In proxy mode, the current Dataway does not retain local tail sampling state:
/v1/tail_sampling,/v1/tail_sampling_v2, and/v2/tail_samplingare forwarded to backend nodes/v1/tail_sampling_configis broadcast to all backend nodes
Therefore, in proxy mode:
aggregator_endpointmust be configured- The client must carry a valid
Guance-Pick-Key - The backend node is responsible for actual sampling and state maintenance
Warning
In Kubernetes deployments, if the front-end Dataway needs to stably forward tail sampling requests to a fixed back-end node, aggregator_endpoint must be filled with a stable, unchanging backend address. It is recommended to deploy the back-end Dataway using StatefulSet to ensure stable Pod addresses and DNS names, facilitating stable forwarding by the front-end Dataway.
Local Configuration¶
Dataway does not have a separate tail sampling YAML configuration item. Tail sampling uses the same mode configuration as aggregation:
Environment variables:
Explanation:
standalone: The current node holds its own tail sampling stateproxy: The current node only forwards or broadcasts
In Kubernetes, if the front-end Dataway serves as the entry layer and the back-end Dataway is responsible for actual tail sampling, the back-end nodes are better suited for StatefulSet deployment, and the stable addresses of the StatefulSet Pods should be written into aggregator_endpoint.
Sampling Configuration Delivery¶
Tail sampling rules are delivered via an API, not written in dataway.yaml:
The request body is JSON, with the top-level structure as follows:
Where:
tracecorresponds to tracing tail sampling configurationloggingcorresponds to logging tail sampling configurationrumcorresponds to RUM tail sampling configuration
Tracing Configuration Example¶
{
"version": 1,
"trace": {
"version": 1,
"data_ttl": "5m",
"group_key": "trace_id",
"pipelines": [
{
"name": "keep-all",
"type": "probabilistic",
"rate": 1
}
],
"builtin_metrics": [
{
"name": "trace_total_count",
"enabled": true
}
]
}
}
Explanation:
trace.group_keycan only betrace_idtrace.data_ttldefaults to5mwhen emptypipelinessupportsconditionandprobabilisticconditionusesaction=keep/dropprobabilisticusesrate=0~1
Logging Configuration Example¶
{
"version": 1,
"logging": {
"version": 1,
"data_ttl": "1m",
"group_dimensions": [
{
"group_key": "service",
"pipelines": [
{
"name": "keep-all",
"type": "probabilistic",
"rate": 1
}
]
}
]
}
}
RUM Configuration Example¶
{
"version": 1,
"rum": {
"version": 1,
"data_ttl": "1m",
"group_dimensions": [
{
"group_key": "session_id",
"pipelines": [
{
"name": "keep-all",
"type": "probabilistic",
"rate": 1
}
]
}
]
}
}
Info
logging and rum use group_dimensions to configure grouping dimensions; when data_ttl is empty, both default to 1m.
Warning
The current implementation validates the configuration content. trace only allows group_key=trace_id; derived_metrics is not yet supported, and configuring it will return an error.
Data Reporting API¶
Tail sampling data interfaces:
Explanation:
/v1/tail_samplingreceives uncompressed PBPoints payload; additionally, it is compatible with the zstd packet sent by Datakit 2.10 without compression negotiation header andPayloadCompression=1/v1/tail_sampling_v2is a legacy raw compatibility path, sharing the same processing logic as/v1/tail_sampling; it is not a zstd protocol path/v2/tail_samplingonly receives zstd payload; the request must satisfy both:- header
Guance-Tail-Sampling-Payload-Compression: zstd aggregate.DataPacket.PayloadCompression=1- In
standalonemode, the request body must be a protobuf-encodedaggregate.DataPacket - In
proxymode, the request is forwarded to the backend node
Clients should use the following protocol combinations:
| Client Scenario | Request Path | Compression Negotiation Header | PayloadCompression |
Payload |
|---|---|---|---|---|
| Datakit versions before 2.10 | /v1/tail_sampling |
None | 0 |
raw PBPoints |
| Datakit 2.10 compatibility path | /v1/tail_sampling |
None | 1 |
zstd PBPoints |
| Datakit 2.11 and later default path | /v2/tail_sampling |
zstd |
1 |
zstd PBPoints |
| Datakit 2.11 and later fallback path | /v1/tail_sampling |
None | 0 |
raw PBPoints |
Common response status codes:
| Status Code | Meaning |
|---|---|
200 |
Packet received |
400 |
Invalid protobuf, PBPoints, or packet fields |
412 |
Corresponding sampling configuration not yet ready, but packet has entered the pending cache |
413 |
Request body exceeds Dataway's configured size limit |
415 |
Unsupported compression method, or path, header, and packet compression field mismatch |
503 |
Pending cache is full, packet not received |
Compression Protocol and Rolling Upgrade¶
Datakit 2.11 and later send zstd payload via /v2/tail_sampling by default. Dataway explicitly validates the path, header, and packet compression fields:
- Older Dataway versions do not recognize
/v2/tail_samplingand return404 - Newer Dataway versions return
415 Unsupported Media Typewhen receiving an unsupported compression method, missing header, raw v2 packet, or a v1 zstd packet that does not belong to the Datakit 2.10 compatibility combination - Upon receiving
404or415, Datakit reverts the current packet to raw, retries with/v1/tail_sampling, and caches the endpoint's legacy capability for 10 minutes - Before fallback sending, Datakit splits the packet based on the decompressed protobuf body size to ensure each splittable raw packet does not exceed Dataway's
MaxRawBodySize, preventing high-compression-ratio packets from being rejected with413on older nodes - Datakit 2.10 sends zstd packets directly to
/v1/tail_samplingwithout a negotiation header; the new Dataway maintains precise compatibility for this released version - Datakit versions earlier than 2.10 continue to send raw v1 data; the new Dataway recalculates span predicates and, before entering the timing wheel, decides whether to compress based on benefit
With the above bidirectional compatibility, upgrades to Datakit 2.11+ and the new Dataway can be performed with mixed rolling. Datakit 2.10 is still incompatible with older Dataway versions that do not support this compatibility; one end should be upgraded to a version with compatibility logic first.
Kept Packet Delivery and Exit Recovery¶
Dataway uses a bounded worker pool and a disk overflow queue to send packets that have been decided to be retained:
- On send failure, it backs off and retries up to 3 times; only after retries are exhausted is the packet counted as
failure/drop - When the memory queue is full, it first enters an asynchronous overflow channel, then writes to the disk queue; after Dataway restarts, it actively opens the existing queue and continues sending
- Upon process exit, packets in the overflow, memory queue, and backoff are written to healthy disk first
- When disk is unavailable, the network fallback retries during exit share a 5-second budget; packets that exhaust the budget are explicitly counted as failure metrics and output a summary log
412 and Pending Cache¶
In standalone mode, if Dataway has just started and the sampling configuration for the corresponding token + data_type has not yet been delivered:
- Dataway first places this batch of data into the local pending cache
- Then returns
412 Precondition Failed
Current behavior:
- The pending cache is an in-memory cache
- Stored by
token + data_type - After the configuration is successfully delivered, available data is automatically drained into
TailSamplingProcessor - The default maximum cache size is
100000packets
Contractual behavior:
- Upon receiving
412, the client considers this batch of data as accepted by Dataway - The client only needs to continue sending
/v1/tail_sampling_config - The client does not need to resend this batch of data
Exception:
- If the pending cache is full, Dataway returns
503 - In this case, the request can no longer be considered as received
Tail Sampling Measurement (tail_sampling)¶
The tail sampling configuration supports builtin_metrics. These metrics are generated by the tail sampling processor during the sampling process and written to the center during periodic refresh. After being written to the center, the measurement name is tail_sampling, for example, in Guance you can query the field trace_dropped_count and tags stage/decision/data_type.
The current built-in metrics are as follows.
Tracing¶
trace_total_counttrace_kept_counttrace_dropped_counttrace_error_countspan_total_counttrace_duration
Where:
trace_durationis a duration distribution metric- Others are count metrics
Logging¶
logging_total_countlogging_error_countlogging_kept_countlogging_dropped_count
RUM¶
rum_total_countrum_kept_countrum_dropped_count
Explanation:
- When
builtin_metricsis empty, all built-in metrics supported by that data type are enabled by default - These metrics originate from the tail sampling process itself, not from Dataway's own operational metrics
Dataway Auto-Reported Metrics (Measurement dataway_aggregate)¶
In addition to the sampler's own builtin_metrics (written to the tail_sampling measurement), apis/metrics_special.go automatically maintains a set of Dataway self-observation metrics to describe the processing status of the tail sampling API. These metrics are aggregated and enter the center's dataway_aggregate measurement, with field prefixes dataway_http_tail_sampling_*.
Currently, the tail-sampling-related metrics include:
| Metric Name | Type | Tags | Description |
|---|---|---|---|
dataway_http_api_body_size_bytes_total |
Counter | api, token |
Cumulative bytes of tail sampling API request bodies |
dataway_http_tail_sampling_trace_total |
Counter | token |
Total number of tracing groups received |
dataway_http_tail_sampling_span_total |
Counter | token |
Total number of tracing spans received |
dataway_http_tail_sampling_packet_stage_total |
Counter | token, data_type, stage, result |
Number of groups per stage (receive/ingest/decision/submit/kodo) |
dataway_http_tail_sampling_point_stage_total |
Counter | token, data_type, stage, result |
Number of points per stage |
dataway_http_tail_sampling_rule_packet_total |
Counter | token, data_type, rule_name, rule_index, rule_type, action, result |
Number of groups counted by matched sampling rule |
dataway_http_tail_sampling_rule_point_total |
Counter | Same as above | Number of points counted by rule |
dataway_http_tail_sampling_packet_send_total |
Counter | token, data_type, result |
Send result statistics; result includes success, failure, drop |
dataway_http_tail_sampling_submit_queue_event_total |
Counter | token, data_type, result |
Submit queue enqueue result (memory/wait/overflow/disk/drop/closed) |
dataway_http_tail_sampling_submit_queue_depth |
Gauge | - | Current depth of the submit queue (backlog) |
dataway_http_tail_sampling_submit_queue_capacity |
Gauge | - | Submit queue capacity |
dataway_http_tail_sampling_submit_worker_total |
Gauge | - | Current number of workers |
dataway_http_tail_sampling_submit_worker_busy |
Gauge | - | Current number of busy workers |
dataway_http_tail_sampling_submit_disk_depth |
Gauge | - | Disk overflow queue depth |
dataway_http_tail_sampling_submit_queue_wait_seconds |
Summary | source |
Submit queue waiting time (source is memory/wait/overflow/disk) |
These metrics will:
- Be collected every 1 minute
- Be converted to
dataway_aggregatemetric points - Be reported to
/v1/write/metricusing the Dataway default token - Reset the current accumulated value after reporting
- The
tokentag in the metrics is fixed toredacted, and no fragment of the original token is retained
This set of metrics reflects the operational status of Dataway's own processing of tail sampling traffic, not the business statistics of the sampling rules themselves.
Division of responsibilities between the two central measurements:
tail_sampling: Business statistics of sampling rules (one per token), such astrace_kept_count/trace_dropped_countdataway_aggregate: Operational status of the Dataway processing process (aggregated by the Dataway default token), such as per-stage counts, send/backlog, and worker status