• 腾讯mini项目-【指标监控服务重构】2023-07-20


    今日已办

    Trace

    otelzap :opentelemetry-go-extra/otelzap at main · uptrace/opentelemetry-go-extra (github.com)

    go get github.com/uptrace/opentelemetry-go-extra/otelzap
    
    • 1

    声明 Tracer ,一个应用创建一个 Tracer (需要从venus中来传来的trace_id构造

    var consumerTracer = otel.Tracer("profile-consumer",
    		trace.WithInstrumentationAttributes(attribute.String("profile.work", "consumer")))
    
    • 1
    • 2

    处理异常,日志记录 & Span 记录错误 & 设置状态

    func handlerErr(span trace.Span, ctx context.Context, msg string, err error) {
        // otelzap 集成zap
    	otelzap.L().Ctx(ctx).Error(msg, zap.Error(err))
    	span.RecordError(err)
    	span.SetStatus(codes.Error, msg)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在每一个Handler中使用同一个 Tracer 创建Span

    func (profileCtx *ProfileContext) UnpackKafkaMessage(ctx context.Context) (needBreak bool, tpsStatus string, contextErr error) {
    	var span trace.Span
        // 根Span,类型为内部
    	profileCtx.Ctx, span = consumerTracer.Start(profileCtx.Ctx, "UnpackKafkaMessage",
    		trace.WithNewRoot(), trace.WithSpanKind(trace.SpanKindInternal))
    	defer span.End()
    	if contextErr = json.Unmarshal(profileCtx.msg.Value, &profileCtx.Event); contextErr != nil {
    		profileCtx.Status = state.StatusUnmarshalError
    		handlerErr(span, profileCtx.Ctx, "unmarshal error", contextErr)
    		return
    	}
        // 设置属性
    	if span.IsRecording() {
    		span.SetAttributes(
    			attribute.String("event.id", profileCtx.Event.ID),
    		)
    	}
    	log.Logger.Info("[UnpackKafkaItem] unpack kafka item success", zap.Any("event", profileCtx.Event))
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Metric

    根据组员 张锐添 提供的可用性方案和代码实现

    1. 设置metric PeriodicReader的上报间隔
    2. 创建新的 MeterProvider
    3. 使用 Int64ObservableGauge 在每个测量收集周期,异步记录一次 StatusAlive的 瞬时值
    func InitAvailabilityObserver() func() {
    
    	ctx := context.Background()
    
    	res, err := createResource(ctx)
    	handleErr(err, "failed to create resource")
    
    	otelAgentAddr := config.Profile.GetString("otelclient.otelExporterOtlpEndpoint")
    	metricExp := createMetricExp(err, ctx, otelAgentAddr)
    	handleErr(err, "Failed to create the otelclient metric exporter")
    
    	mp := sdkmetric.NewMeterProvider(
    		sdkmetric.WithResource(res),
    		sdkmetric.WithReader(
    			sdkmetric.NewPeriodicReader(
    				metricExp,
    				sdkmetric.WithInterval(10*time.Second), // 10s上报一次
    				sdkmetric.WithTimeout(2*time.Second),   // 设置超时
    			),
    		),
    	)
    
    	const (
    		StatusAlive = iota // 可用状态
    	)
    
    	_, err = mp.Meter("profile-availability-meter").Int64ObservableGauge(
    		"profile/alive_observer",
    		// 每个测量值收集周期,异步记录一次瞬时 int64 测量值
    		metric.WithInt64Callback(func(ctx context.Context, observer metric.Int64Observer) error {
    			observer.Observe(
    				StatusAlive,
    				// metric.WithAttributes(attribute.String("", "")),
    			)
    			return nil
    		}),
    	)
    	handleErr(err, "Failed to create the ObservableGauge")
    
    	log.Logger.Info("init availabilityObserver success")
    
    	return func() {
    		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    		defer cancel()
    		if err := mp.Shutdown(ctx); err != nil {
    			otel.Handle(err)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    在 SigNoz Web 的 Dashboards 配置 ClickHouse Query

    SELECT
        toStartOfMinute(toTimeZone(toDateTime(timestamp_ms/1000), 'Asia/Shanghai')) AS minute,
        count(*)/6 AS result
    FROM signoz_metrics.samples_v2
    WHERE metric_name='profile_alive_observer' AND timestamp_ms >= 1000*toUnixTimestamp(toStartOfMinute(toTimeZone(now(), 'Asia/Shanghai') - INTERVAL 1 DAY))
    GROUP BY minute
    ORDER BY minute ASC
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20230720193023216

    发现问题

    请求 Venus 的 Post 接口,Profile 消费了两次,由于上报的json数据的data字段是数组(包含了多条数据)

    使用 Int64Counter 记录消费总次数时(同步且递增),在服务重新启动后,测量值会重新从0开始

    image-20230720193935744

    traefik 反向代理

    http:
      routers:
        frontend-router:
          rule: "PathPrefix(`/frontend`)"
          entrypoints:
            - web-entrypoint
          service: frontend-service
      services:
        frontend-service:
          loadBalancer:
            servers:
              - url: http://profile-frontend:3301
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    image-20230720201340226

    image-20230720201229456

    image-20230720203023389

    image-20230720201948832

    组会记录

    1. SRE报表- SLI SLO SLA (指标、具体范围或者限制, 协议)— 具体以什么形式,可视化出来
    2. 服务(进程)的CPU、内存利用率等指标,shirou/gopsutil: psutil for golang (github.com)
    3. 重启服务,Counter计数器的值会从零开始计算
    4. traefik反向代理 :指定一个端口,前缀为’/'的请求都路由到frontend服务
      • https://signoz.io/docs/faqs/product/#is-there-a-provision-to-modify-the-base-path-of-signoz-ui-and-host-it-behind-nginx-or-others-at-the-subpath
      • https://github.com/SigNoz/signoz/pull/1115image-20230721150009788
    5. Log上报目标 - [郑兆隆]
    6. Grafana配置Ck的仪表盘image-20230720225452735
    7. Trace 收集到的 Span 的延时、错误率、吞吐量需要用指标 metric 来上报吗
    8. Profile的ToDo

    明日待办

    1. 组长会议汇报项目进度和问题
  • 相关阅读:
    搜索算法(DFS和BFS 蓝桥杯 C++)
    1024程序员节主题征文 | 程序员节节日祝福语大全
    Coupang走什么物流?Coupang火箭颜色什么意思?——站斧浏览器
    JS-DOM 元素属性的操作(简单tab栏切换案例)
    Maven依赖解决
    没什么。。。。
    Maven 的安装与配置
    C++面试基础整理(私房菜)
    JMeter入门教程(14)——场景设计
    C++STL详解(三)list的使用及其模拟实现
  • 原文地址:https://blog.csdn.net/xzx18822942899/article/details/132878351