昨天聊API, 今天聊SDK
SDK重要的有Sampling, Span Creation, Processor, Exporter
網路找的圖, 示意用
圖片來源Stratified Sampling | A Step-by-Step Guide with Examples
如果每個trace都要進行採樣紀錄, 能想想看, 每秒請求數幾千的小公司, 每天所產生的log容量得有多少? 對公司來說硬體存儲成本會很高.
如果能只需要採集一部分或需要的, 對我們來說是最好的.
當然這是一種tradeoff, 因為會沒辦法觀測到全部的請求.
Samping取樣, 這功能的目的是減少收集併發送到後端的trace樣本數量, 來控制
noice與開發的機制.
Samping的方式有兩種, Head-based Sampling與Tail-based Sampling
在trace一開始就決定是否要採樣, 這策略有個問題, 就是事先沒辦法知道所有事情, 只能被迫做出任意的決定, 通常就是骰骰子隨機進行採樣.
甚至也沒辦法針對只有發生ERROR的span做採樣.
在整個請求流程結束時做出採樣的決定, 因為已經收集到了數據了. 就能在後半段決定是否要被存儲起來.
缺點就是一堆噪音還是要先被處理.
2種方法沒有一定好壞, 因為沒有一個策略能適合所有人.
第一種的好處是因為源頭就決定好了, 在網路中傳輸的數據個數就被大大減少了.
但決定要更新採樣機率時, 就很可能要重新佈署啟動程式.
如果選擇在後端或者是Collector中決定, 就會有網路傳輸成本, 以及Processor的處理成本要考慮.
Sampler的interface
// Sampler decides whether a trace should be sampled and exported.
type Sampler interface {
// ShouldSample returns a SamplingResult based on a decision made from the
// passed parameters.
ShouldSample(parameters SamplingParameters) SamplingResult
// Description returns information describing the Sampler.
Description() string
}
Sampler採樣器, 需要在TraceProvider建立時就配置好
provider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
)
範例就是配置AlwaysSample採樣策略的採樣器
還有NeverSample
與TraceIDRatioBased
與ParentBased
定義 : Sample every trace.
在Production環境尚要注意流量.
定義 : Sample no traces
TraceIDRatioBased需要給[0,1]之間的fraction做參數.
如果給0.5, 則表示大概有一半的traceid的數據會被採樣.
根據Parent Span的策略做出採樣策略.
如果是Root Span, 則有默認的採樣策略. 通常是AlwaysSample或者TraceIDRatioBased.
Parent Type | Default Sampler |
---|---|
RemoteParentSampled | AlwaysOn |
RemoteParentNotSampled | AlwaysOff |
LocalParentSample | AlwaysOn |
LocalParentNotSampled | AlwaysOff |
func ParentBased(root Sampler, samplers ...ParentBasedSamplerOption) Sampler {
return parentBased{
root: root,
config: configureSamplersForParentBased(samplers),
}
}
func (pb parentBased) ShouldSample(p SamplingParameters) SamplingResult {
psc := trace.SpanContextFromContext(p.ParentContext)
if psc.IsValid() {
if psc.IsRemote() {
if psc.IsSampled() {
return pb.config.remoteParentSampled.ShouldSample(p)
}
return pb.config.remoteParentNotSampled.ShouldSample(p)
}
if psc.IsSampled() {
return pb.config.localParentSampled.ShouldSample(p)
}
return pb.config.localParentNotSampled.ShouldSample(p)
}
return pb.root.ShouldSample(p)
}
它的第一個參數是給Root Span用的.
所以Production環境上, 應該把TraceIDRatioBased與ParentBased採樣器一起使用.
RootSpan用Ratio決定, ChildSpan則根據Parent決定.
provider := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.ParentBased(sdktrace.TraceIDRationBased(0.5))),
)
OTel specification - Trace SDK
OTel https://opentelemetry.io/docs/reference/specification/trace/tracestate-probability-sampling/