背景
由于项目是分布式微服务架构系统,为了实现服务的可观察性,决定搭建一套可观测的系统。 由于我们当前使用的是go,而opentelemetry标准也是目前比较推荐的,并且其支持多语言,于是就想到用otel来搞了。废话不多说,进入主题
架构设计
第一方案: 如下图所示
- otel-exporter:是我们微服里面调用otel/sdk来实现。把数据上传到otel-collector
- otel-collector:作为数据收集器,可以收集trace、metric、logs数据。
- zipkin:作为trace数据的服务组件,其可以存储trace,可以可视化trace。
- elasticsearch:数据存储组件。
- web:即通过chrome或其他浏览器,通过访问zipkin提供的http服务来查看链路数据。
(补充说明: zipkin支持多种存储中间件, 默认为内存存储其重启数据就会丢失, 支持elasticsearch存储搜索快捷。 还有其他存储,有兴趣可以到其官网查看)
落地部署
otel-exporter
import (
"context"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"time"
semconv "go.opentelemetry.io/otel/semconv/v1.24.0"
)
func NewTracerProvider(cAddr string) (func(context.Context)error, error) {
ctx := context.Background()
res ,err := resource.New(ctx,
resource.WithAttributes(
semconv.ServiceName("service-name"),
semconv.ServiceInstanceID("service-instance-id"),
semconv.ContainerName("container"),
semconv.ServerAddress("ip"),
semconv.ServerPort(8888),
),
)
if err != nil {
return nil, err
}
traceExporter, err := otlptracegrpc.New(ctx, otlptracegrpc.WithInsecure(), otlptracegrpc.WithEndpoint(cAddr), otlptracegrpc.WithDialOption(grpc.WithBlock()))
if err != nil {
return nil, err
}
tracerProvider := sdktrace.NewTracerProvider(
sdktrace.WithResource(res),
sdktrace.WithBatcher(traceExporter, sdktrace.WithBatchTimeout(time.Minute)),
)
otel.SetTracerProvider(tracerProvider)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
return tracerProvider.Shutdown, nil
}
以上是初始化一个tracer exporter。
接着就可以使用全局的tracer来记录trace了
import(
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
"go.opentelemetry.io/otel"
"context"
)
func myFunc(){
ttrace := otel.Tracer("service-trace")
ctx, span := ttrace.Start(context.Background(), "parenSpanName", trace.WithAttributes(attribute.String("key","value")))
defer span.End()
// do logic
}
当然这里可以支持 配置自己的parent-traceid,支持child-trace-span。 这些都可以通过官网搜索到。
exporter 就到这结束了。
otel-collector
目前组件都是通过docker来安装
docker run -d --name=otel-collect \
-p 4317:4317 \
-p 55679:55679 \
-v ${pwd}/config.yaml:/etc/otelcol/config.yaml \
otel/collector:v0.96
配置模版
# To limit exposure to denial of service attacks, change the host in endpoints below from 0.0.0.0 to a specific network interface.
# See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/security-best-practices.md#safeguards-against-denial-of-service-attacks
extensions:
health_check:
pprof:
endpoint: 0.0.0.0:1777
zpages:
endpoint: 0.0.0.0:55679
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
opencensus:
endpoint: 0.0.0.0:55678
processors:
batch:
memory_limiter:
check_interval: 3s
limit_mib: 1024
spike_limit_mib: 1024
exporters:
debug:
verbosity: detailed
zipkin:
endpoint: http://127.0.0.1:9411/api/v2/spans
prometheus:
endpoint: 0.0.0.0:9190
prometheusremotewrite:
endpoint: http://127.0.0.1:9090/api/v1/write
tls:
insecure: true
kafka/exporter:
encoding: otlp_proto
protocol_version: 2.7.0
topic: zipkin
brokers:
- 127.0.0.1:9092
otlp/jaeger:
endpoint: 127.0.0.1:4317
tls:
insecure: true
otlp/zipkin:
endpoint: 127.0.0.1:9411
tls:
insecure: true
otlphttp/jaeger:
endpoint: http://127.0.0.1:14268/api/traces
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [zipkin]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [logging,prometheus]
extensions: [health_check, pprof, zpages]
好了 collector就这样配置完了,启动collector就可以了
zipkin
docker run \
--name zipkin-server -d \
-p 9411:9411 \
-e JAVA_OPTS="-Xmx1G -Xms1G" \
-e STORAGE_THROTTLE_MAX_QUEUE_SIZE=8000 \
-e STORAGE_TYPE=elasticsearch \
-e ES_HOSTS=127.0.0.1:9200 \
openzipkin/zipkin-slim
这里配置es作为trace的存储。
好,现在我们就可以通过 http://localhost:9411/zipkin/ 来访问trace数据了。
效果图
当执行开始写的代码时候,数据就会传输给collector,然后collector会把trace数据转到zipkin,zipkin把数据保存到es中,最后我们可以通过搜索功能搜索trace数据了。
显然这个框架需要优化的点还有很多,尤其是当并发量高的时候 zipkin经常挂。
优化待下一篇文章讲