注意到otlp-gin的中间件库,每次请求都会用provider获取meter对象,因此担心性能问题遂看代码...文档真的看不懂,好多包只能去go.dev查api

Meter

每次请求都会使用otel.Meter(name)获取meter进行操作.
来到文件D:\Develop\golang\pkg\mod\go.opentelemetry.io\otel\sdk\metric@v1.37.0\provider.go 第92行看关键代码

return mp.meters.Lookup(s, func() *meter {
        return newMeter(s, mp.pipes)
    })

代码调用了lookup跳转进去.这是一个实现了私有kv,解决了并发的缓存文件.
函数具体实现如下

func (c *cache[K, V]) Lookup(key K, f func() V) V {
    c.Lock()
    defer c.Unlock()

    if c.data == nil {
        val := f()
        c.data = map[K]V{key: val}
        return val
    }
    if v, ok := c.data[key]; ok {
        return v
    }
    val := f()
    c.data[key] = val
    return val
}

当首次创建时,缓存中没有查找到key,会调用之前Lookup中传递的匿名函数创建.如果缓存中查找到key会直接返回存储的value.即meter也实现了单例.同时你设置的计数器等也会存在这个单例中
 title=

计数器

随便来查看一个计数器,可以看到也使用了lookup,因此计数器等也会被缓存,旧的计数器不会被覆盖

func (m *meter) Int64Counter(name string, options ...metric.Int64CounterOption) (metric.Int64Counter, error) {
    cfg := metric.NewInt64CounterConfig(options...)
    const kind = InstrumentKindCounter
    p := int64InstProvider{m}
    i, err := p.lookup(kind, name, cfg.Description(), cfg.Unit())
    if err != nil {
        return i, err
    }

    return i, validateInstrumentName(name)
}

Trace

在你创建完provider设置到otel后
otel.Tracer(name)的注释更加清楚明了

If the same name and options are passed multiple times, the same Tracer will be returned
如果传入相同的 name 和 options,会返回相同的 Tracer

至此Meter和Trace如果opt和name全相同,则会返回相同对象,否则会创建新对象.
因而不必过于担心性能问题

Otlp col

otlp col可以理解成一个转发程序,部署在节点上接收节点上程序发送的数据,然后转发给jaeger,prometheus(或者暴露/metrics端口给prometheus采集).
因此metrics中的数据完全依赖程序传递的数据,比如计数器,之前为50,重启程序后变为了0,otlp col也会更新成0,即使是只增计数器.

文章目录