1 - 可观测性概述

Dapr的可观测性概述

可观测性/Observability构建块

2 - 可观测性的文档

Dapr可观测性的文档

2.1 - 可观测性文档的文档

Dapr可观测性的文档概述

Observability

https://docs.dapr.io/developing-applications/building-blocks/observability/

查看和度量跨组件和网络服务的消息调用。

本节包括在可观测性方面对开发者的指导。关于Dapr中可观测性概念的总体概述和关于监测的操作指导,请参见其他章节。

相关资料:

2.2 - 可观测性的概念

Dapr可观测性的概念

内容节选自:https://docs.dapr.io/concepts/observability-concept/

How to monitor applications through tracing, metrics, logs and health

如何通过跟踪、指标、日志和健康状况来监控应用程序

可观测性是控制理论中的一个术语。可观测性意味着您可以通过观察系统外部来回答系统内部发生了什么问题,而无需发布新的代码来回答新的问题。在生产环境和服务中,可观测性对于调试、运维和监控Dapr系统服务、组件和用户应用至关重要。

可观测性能力使用户能够监控Dapr系统服务、它们与用户应用程序的交互,并了解这些被监控的服务的行为。可观测性的功能分为以下几个方面。

分布式跟踪

分布式跟踪用于描述和监控Dapr系统服务和用户应用程序。分布式跟踪有助于确定故障发生的位置和导致性能不佳的原因。分布式跟踪特别适合于调试和监控分布式软件架构,如微服务。

您可以使用分布式跟踪来帮助调试和优化应用程序代码。分布式跟踪包含Dapr运行时、Dapr系统服务和用户应用程序之间跨越进程、节点、网络和安全边界的跟踪span。它提供了对服务调用(调用流)和服务依赖的详细了解。

Dapr使用W3C追踪上下文进行分布式追踪。

一般建议在生产中运行Dapr时开启跟踪。

Open Telemetry

Dapr与OpenTelemetry集成,用于跟踪、度量和日志。通过OpenTelemetry,您可以根据您的环境配置各种导出器,用于跟踪和度量,无论它是在云端还是在内部运行。

Metrics

度量是指随着时间的推移收集和存储的一系列测量值和计数。Dapr指标可以监控和了解Dapr系统服务和用户应用的行为。

例如,Dapr sidecar和用户应用之间的服务指标显示调用延迟、流量故障、请求的错误率等。

Dapr系统服务指标显示sidecar注入故障、系统服务的健康度,包括CPU使用情况、做出的actor放置次数等。

Logs

日志是事件发生的记录,可以用来判断故障或其他状态。

日志事件包含Dapr系统服务产生的警告、错误、信息和调试消息。每个日志事件包括元数据,如消息类型、主机名、组件名、App ID、ip地址等。

Health

Dapr为托管平台提供了一种使用HTTP端点确定其健康状况的方法。有了这个端点,Dapr进程或sidecar可以被探测到,以确定它的准备度(readiness)和活力(liveness),并采取相应的行动。

2.3 - 可观测性文档的Tracing

Dapr可观测性文档中的Tracing

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/tracing/

Dapr 使用 OpenTelemetry(以前称为OpenCensus)进行分布式追踪和指标收集。OpenTelemetry支持各种后端,包括Azure Monitor、Datadog、Instana、Jaeger、SignalFX、Stackdriver、Zipkin等。

追踪设计

Dapr 向 Dapr sidecar 中添加了 HTTP/gRPC 中间件(middleware)。中间件拦截所有Dapr和应用流量,并自动注入相关ID以跟踪分布式事务。此设计具有以下优点:

  • 无需代码检测。将自动跟踪所有流量(追踪级别可配置)。
  • 跨微服务的一致追踪行为。追踪是在 Dapr Sidecar 上配置和管理的,因此它在服务中可能保持一致,这些服务是不同团队提供的,并且可能以不同的编程语言编写。
  • 可配置和可扩展。通过利用 OpenTelemetry,可以将 Dapr 追踪配置为与流行的追踪后端一起使用,包括客户可能拥有的自定义后端。
  • OpenTelemetry 导出器被定义为一等公民的 Dapr 组件。可以同时定义并启用多个导出器。

W3C Correlation ID

Dapr使用标准的W3C跟踪上下文头文件。对于HTTP请求,Dapr使用 traceparent header。对于gRPC请求,Dapr使用 grpc-trace-bin header。当请求到达时没有trace ID时,Dapr会创建新的ID。否则,它将沿着调用链传递跟踪ID。

阅读W3C分布式跟踪,了解更多关于W3C Trace Context的背景。

这里有很大变化,早期的文档是这样描述,实现方式和现在的差异很大:

对于HTTP请求,Dapr会向请求注入 X-Correlation-ID header。对于gRPC调用,Dapr插入 X-Correlation-ID 作为 header 元数据的字段。当没有 Correlation ID 的请求到达时,Dapr将创建一个新的 Correlation。否则,它将沿调用链传递 Correlation ID。

配置

Dapr使用OpenCensus定义的概率才样 (probabilistic sampling) 。采样率定义了tracing span被采样的概率,其值可以在0和1之间(包括)。默认采样率是0.0001(即每10,000个span中采样一个)。

要改变默认的跟踪行为,请使用配置文件(在自托管模式下)或Kubernetes配置对象(在Kubernetes模式下)。例如,以下配置对象将采样率改为1(即每个span都会采样)。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: tracing
  namespace: default
spec:
  tracing:
    samplingRate: "1"

同样,将 samplingRate 改为 0 将完全禁用跟踪。

有关如何在本地环境和Kubernetes环境中配置跟踪的更多细节,请参见参考文档部分。

Dapr支持可插拔的导出器,由配置文件(在自托管模式下)或Kubernetes自定义资源对象(在Kubernetes模式下)定义。例如,下面的清单(manifest)定义了一个Zipkin导出器。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: zipkin
  namespace: default
spec:
  type: exporters.zipkin
  metadata:
  - name: enabled
    value: "true"
  - name: exporterAddress
    value: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans"

参考文档

2.4 - 可观测性文档的W3C追踪上下文

Dapr可观测性文档中的W3C追踪上下文

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/w3c-tracing/

使用Dapr进行W3C追踪的背景和场景。

2.5 - 可观测性文档的W3C追踪上下文概述

Dapr可观测性文档中的W3C追踪上下文概述

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/w3c-tracing/w3c-tracing-overview/

使用Dapr进行W3C追踪的背景和场景

介绍

Dapr使用W3C跟踪上下文对服务调用和pub/sub消息进行分布式跟踪。Dapr主要完成了生成和传播跟踪上下文信息的所有繁重工作,这些信息可以被发送到许多不同的诊断工具进行可视化和查询。只有极少数情况下,作为开发者,你需要传播或生成tracing header。

背景

分布式跟踪是一种由跟踪工具实现的方法,用于跟踪、分析和调试跨多个软件组件的事务。通常情况下,分布式跟踪会遍历一个以上的服务,这就要求它具有唯一的标识性。跟踪上下文传播将这种唯一标识传递出去。

在过去,跟踪上下文传播通常由每个不同的跟踪供应商单独实现。在多厂商的环境中,这会造成互操作性的问题,比如:

  • 由于没有共享的唯一标识符,不同追踪供应商收集的tracing无法相互关联。
  • 跨越不同追踪供应商边界的trace无法传播,因为没有统一协商的标识符集可以被转发。
  • 厂商特定的元数据可能会被中介机构放弃
  • 云平台厂商、中间商和服务商,由于没有标准可循,不能保证支持追踪上下文传播。

在过去,这些问题并没有产生重大影响,因为大多数应用程序由单一的跟踪供应商监控,并停留在单一平台供应商的边界内。今天,越来越多的应用是分布式的,并利用了多个中间件服务和云平台。

现代应用的这种转变呼唤一个分布式的跟踪上下文传播标准。W3C跟踪上下文规范为跟踪上下文传播数据的交换定义了一种普遍认同的格式–称为跟踪上下文。trace context通过以下方式解决了上述问题:

  • 为单个跟踪和请求提供独特的标识符,允许将多个供应商的跟踪数据链接在一起。
  • 提供一个约定俗成的机制,以转发特定供应商的跟踪数据,并避免在多个跟踪工具参与单一交易时出现跟踪中断的情况。
  • 提供一个中间商、平台和硬件提供商可以支持的行业标准。

传播跟踪数据的统一方法提高了分布式应用行为的可视性,便于问题和性能分析。

场景

有两种情况下,你需要了解跟踪是如何被使用的:

  1. Dapr生成并在服务之间传播跟踪上下文。
  2. Dapr生成跟踪上下文,你需要将跟踪上下文传播给另一个服务,或者你生成跟踪上下文,Dapr将跟踪上下文传播给一个服务。

Dapr在服务之间生成和传播跟踪上下文

在这些情况下,Dapr为你做了所有的工作。你不需要创建和传播任何跟踪头。Dapr会负责创建所有的跟踪头并传播它们。让我们通过实例来了解一下这些场景。

  1. 单个服务调用(service A -> service B

    Dapr在服务A中生成跟踪头,这些跟踪头从服务A传播到服务B。

  2. 多个顺序的服务调用 ( service A -> service B -> service C)

    Dapr在服务A请求开始时生成跟踪头,这些跟踪头从服务A->服务B->服务C,以此类推传播到更多的启用了Dapr的服务。

  3. 请求来自外部端点(例如从网关服务到启用Dapr的服务A的请求)

    Dapr 在服务 A 中生成跟踪头,这些跟踪头从服务 A 进一步传播到启用 Dapr 的服务服务 A->服务 B ->服务 C。和上面的场景2类似。

  4. Pub/sub消息 Dapr在发布的消息主题中生成跟踪头,这些跟踪头被传播到该主题上的任何监听服务。

你需要在服务之间传播或生成跟踪上下文

在这些情况下,Dapr为你做了一些工作,你需要创建或传播跟踪头。

  1. 从单个服务对不同服务的多次服务调用

    当你从一个服务中调用多个服务时,比如像这样从服务A中调用,你需要传播跟踪头。

     service A -> service B
     [ .. some code logic ..]
     service A -> service C
     [ .. some code logic ..]
     service A -> service D
     [ .. some code logic ..]
    

    在这种情况下,当服务A第一次调用服务B时,Dapr会在服务A中生成跟踪头,然后将这些跟踪头传播给服务B,这些跟踪头在服务B的响应中作为响应头的一部分返回。然而你需要将返回的跟踪上下文传播给下一个服务C和服务D,因为Dapr不知道你要重用同一个头。

    要了解如何从响应中提取跟踪头,并将跟踪头添加到请求中,请参阅 如何使用跟踪上下文 一文。

  2. 你选择了生成自己的跟踪上下文头。这是很少会遇到的。在某些情况下,您可能会特别选择将 W3C 跟踪头添加到服务调用中,例如,如果您有一个现有的应用程序目前没有使用 Dapr。在这种情况下,Dapr仍然会为您传播跟踪上下文头。如果你决定自己生成跟踪头,有三种方法可以实现:

    1. 您可以使用行业标准的 OpenCensus/OpenTelemetry SDK 来生成跟踪头,并将这些跟踪头传递给启用 Dapr 的服务。这是首选的建议。

    2. 你可以使用供应商SDK来生成W3C跟踪头,如DynaTrace SDK,并将这些跟踪头传递给启用Dapr的服务。

    3. 你可以按照W3C跟踪上下文规范手工制作一个跟踪上下文,并将这些跟踪头传递给启用Dapr的服务。

W3C trace headers

这些是由Dapr为HTTP和gRPC生成和传播的特定的跟踪上下文头。

跟踪上下文的HTTP header格式

当将HTTP响应的跟踪上下文头传播到HTTP请求时,你需要复制这些头。

Traceparent Header

traceparent header在跟踪系统中以通用的格式表示传入的请求,所有厂商都能理解。下面是一个traceparent header的例子:

traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01

traceparent字段在 这里 有详细说明

Tracestate Header

tracestate头 header包含了可能是特定于厂商的格式的parent。

tracestate: congo=t61rcWkgMzE

这里 是详细的 tracestate 字段的说明。

跟踪上下文的gRPC header格式

在gRPC API调用中,跟踪上下文是通过 grpc-trace-bin heaer传递的。

2.6 - 可观测性文档中的日志

Dapr可观测性文档中的日志

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/logs/

Dapr以纯文本或JSON格式生成结构化日志到stdout。默认情况下,所有的Dapr进程(运行时和系统服务)都以纯文本的形式写入控制台。要启用JSON格式的日志,需要在运行Dapr进程时添加-log-as-json命令标志。

如果要使用搜索引擎(如 Elastic Search 或 Azure Monitor)搜索日志,建议使用 JSON 格式的日志,日志收集器和搜索引擎可以使用内置的 JSON 分析器进行解析。

Log schema

Dapr根据以下模式生成日志:

字段 描述 例子
time ISO8601 Timestamp 2011-10-05T14:48:00.000Z
level Log Level (info/warn/debug/error) info
type Log Type log
msg Log Message hello dapr!
scope Logging Scope dapr.runtime
instance Container Name dapr-pod-xxxxx
app_id Dapr App ID dapr-app
ver Dapr Runtime Version 0.5.0

纯文本和JSON格式的日志

  • 纯文本日志示例
time="2020-03-11T17:08:48.303776-07:00" level=info msg="starting Dapr Runtime -- version 0.5.0-rc.2 -- commit v0.3.0-rc.0-155-g5dfcf2e" instance=dapr-pod-xxxx scope=dapr.runtime type=log ver=0.5.0-rc.2
time="2020-03-11T17:08:48.303913-07:00" level=info msg="log level set to: info" instance=dapr-pod-xxxx scope=dapr.runtime type=log ver=0.5.0-rc.2
  • JSON格式日志示例
{"instance":"dapr-pod-xxxx","level":"info","msg":"starting Dapr Runtime -- version 0.5.0-rc.2 -- commit v0.3.0-rc.0-155-g5dfcf2e","scope":"dapr.runtime","time":"2020-03-11T17:09:45.788005Z","type":"log","ver":"0.5.0-rc.2"}
{"instance":"dapr-pod-xxxx","level":"info","msg":"log level set to: info","scope":"dapr.runtime","time":"2020-03-11T17:09:45.788075Z","type":"log","ver":"0.5.0-rc.2"}

配置纯文本或JSON格式的日志

Dapr支持纯文本和JSON格式的日志。默认的格式是纯文本。如果您想使用纯文本与搜索引擎,您不需要更改任何配置选项。

要使用JSON格式的日志,您需要在安装Dapr和部署应用程序时添加额外的配置。建议使用JSON格式的日志,因为大多数日志收集器和搜索引擎可以通过内置的解析器更容易地解析JSON。

在Kubernetes中配置日志格式

以下步骤描述了如何为Kubernetes配置JSON格式的日志。

使用Helm chart将Dapr安装到集群中

您可以通过在Helm命令中添加--set global.logAsJson=true选项为Dapr系统服务启用JSON格式的日志。

helm install dapr dapr/dapr --namespace dapr-system --set global.logAsJson=true

为 Dapr Sidecar启用 JSON 格式的日志。

您可以通过在 deployment 中添加 dapr.io/log-as-json: "true " 注解,在Dapr sidecars-injector服务激活的Dapr sidecars中启用JSON格式的日志。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pythonapp
  namespace: default
  labels:
    app: python
spec:
  replicas: 1
  selector:
    matchLabels:
      app: python
  template:
    metadata:
      labels:
        app: python
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "pythonapp"
        dapr.io/log-as-json: "true"
...

日志收集器

如果你在Kubernetes集群中运行Dapr,Fluentd是一个流行的容器日志收集器。你可以使用Fluentd和json解析器插件来解析Dapr JSON格式的日志。本攻略介绍了如何在集群中配置Fleuntd。

如果你使用Azure Kubernetes服务,你可以使用默认的OMS代理与Azure Monitor收集日志,而不需要安装Fluentd。

搜索引擎

如果你使用Fluentd,我们建议使用Elastic Search和Kibana。这篇攻略介绍了如何在Kubernetes集群中设置Elastic Search和Kibana。

如果你使用的是Azure Kubernetes服务,你可以使用Azure监控容器,而无需安装任何额外的监控工具。另请阅读如何为容器启用Azure Monitor。

2.7 - 如何在Dapr中使用的W3C跟踪上下文

如何在Dapr中使用的W3C跟踪上下文

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/w3c-tracing/w3c-tracing-howto/

使用Dapr的W3C追踪标准。

如何从响应中检索跟踪上下文。

注意:在Dapr SDK中没有暴露的帮助方法来传播和检索跟踪上下文。你需要使用http/gRPC客户端通过http头和gRPC元数据来传播和检索跟踪头。

在Go中检索跟踪上下文

对于HTTP调用

OpenCensus Go SDK提供ochttp包,它提供了从http响应中获取跟踪上下文的方法。

要从HTTP响应中获取跟踪上下文,你可以这样:

f := tracecontext.HTTPFormat{}
sc, ok := f.SpanContextFromRequest(req)

对于gRPC调用

要在gRPC调用返回时检索跟踪上下文头,可以将响应头引用作为gRPC调用选项传递,该选项包含响应头。

var responseHeader metadata.MD

// Call the InvokeService with call option
// grpc.Header(&responseHeader)

client.InvokeService(ctx, &pb.InvokeServiceRequest{
		Id: "client",
		Message: &commonv1pb.InvokeRequest{
			Method:      "MyMethod",
			ContentType: "text/plain; charset=UTF-8",
			Data:        &any.Any{Value: []byte("Hello")},
		},
	},
	grpc.Header(&responseHeader))

如何在请求中传播跟踪上下文

注意:在Dapr SDK中没有暴露的帮助方法来传播和检索跟踪上下文。你需要使用http/gRPC客户端通过http头和gRPC元数据来传播和检索跟踪头。

在Go中传递跟踪上下文

对于HTTP调用

OpenCensus Go SDK提供ochttp包,提供在http请求中附加跟踪上下文的方法。

f := tracecontext.HTTPFormat{}
req, _ := http.NewRequest("GET", "http://localhost:3500/v1.0/invoke/mathService/method/api/v1/add", nil)

traceContext := span.SpanContext()
f.SpanContextToRequest(traceContext, req)

对于gRPC调用

traceContext := span.SpanContext()
traceContextBinary := propagation.Binary(traceContext)

然后你可以通过gRPC元数据用 grpc-trace-bin 头传递跟踪上下文。

ctx = metadata.AppendToOutgoingContext(ctx, "grpc-trace-bin", string(traceContextBinary))

2.8 - 可观测性文档中的Metrics

Dapr可观测性文档中的Metrics

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/metrics/

Dapr公开了一个Prometheus指标端点(metrics endpoint),您可以通过刮削该端点来更好地了解Dapr的行为方式,并针对特定条件设置警报。

配置

Dapr系统进程默认启用metrics端点,您可以通过命令行参数--enable-metrics=false来禁用它。

默认的metrics端口是9090。可以通过向Daprd传递命令行参数--metrics-port来重写这个端口。

如果要禁用Dapr Sidecar中的度量,可以使用 metrics spec 配置,并设置 enabled: false来禁用Dapr运行时的度量。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: tracing
  namespace: default
spec:
  tracing:
    samplingRate: "1"
  metric:
    enabled: false

Metrics

每个Dapr系统进程都会默认发出Go运行时/进程指标,并有自己的指标

2.9 - 可观测性文档中的sidecar健康状态

Dapr可观测性文档中的sidecar健康状态

内容节选自:https://docs.dapr.io/developing-applications/building-blocks/observability/sidecar-health/

Dapr提供了一种使用HTTP /healthz 端点来确定其健康状况的方法。有了这个端点,Dapr进程或sidecar可以被探测到它的健康状况,从而确定它的准备度(readiness)和活力(liveness)。参见健康API

Dapr /healthz 端点可以被应用托管平台的健康探针使用。本主题介绍了Dapr如何与来自不同托管平台的探针集成。

作为用户,当将Dapr部署到托管平台(例如Kubernetes)时,Dapr健康端点会自动为您配置。你不需要配置任何东西。

注意:Dapr actor 也有一个健康 API 端点,Dapr 会探测应用程序,以响应 Dapr 发出的信号,即 actor 应用程序是健康且正在运行的。请参阅actor健康API

健康端点:与Kubernetes的整合

Kubernetes使用就绪(readiness)和活泼度(liveness)探针来确定容器的健康状况。

kubelet使用 liveness probes 来知道何时重启容器。例如,liveness探针可以捕捉到一个死锁,即应用程序正在运行,但无法取得进展。在这样的状态下重启容器,可以帮助使应用在有bug的情况下仍有更多的可用性。

kubelet使用 readiness probes 来了解一个容器何时准备好开始接受流量。当一个pod的所有容器都准备好时,就认为它已经准备好了。这个就绪信号的一个用途是控制哪些pod被用作Kubernetes服务的后端。当一个pod没有准备好时,它将从Kubernetes服务负载平衡器中移除。

当与Kubernetes集成时,Dapr sidecar被注入一个Kubernetes探针配置,告诉它使用Dapr healthz端点。这是由Sidecar Injector系统服务完成的。与kubelet的集成如下图所示。

如何在Kubernetes中配置Liveness探针?

在pod配置文件中,在容器规范部分添加了活泼度(Liveness)探针,如下图所示。

 livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 3
      periodSeconds: 3

在上面的例子中,periodSeconds字段指定kubelet应该每3秒执行一次活度探测。initialDelaySeconds字段告诉kubelet在执行第一个探测之前应该等待3秒。要执行探测,kubelet会向在容器中运行并在本例中监听端口8080的服务器发送HTTP GET请求。如果服务器的 /healthz 路径的处理程序返回一个成功代码,那么kubelet认为容器还活着并且是健康的。如果处理程序返回失败代码,kubelet就会杀死容器并重新启动它。

任何大于或等于200且小于400的代码表示成功。任何其他代码表示失败。

如何在Kubernetes中配置readiness探针?

就绪(readiness)探针的配置与活度探针类似,唯一的区别是使用readinessProbe字段而不是活度探针字段。

readinessProbe:
			httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 3
      periodSeconds: 3

Dapr sidecar健康端点如何用Kubernetes配置?

如上所述,这个配置是由Sidecar Injector服务自动完成的。本节介绍了在活泼度和准备度探针上设置的具体数值。

Dapr在端口3500上有其HTTP健康端点 /v1.0/healthz,这可以和Kubernetes一起用于就绪和活泼度探针。当Dapr sidecar被注入时,在pod配置文件中用以下值配置就绪和活泼度探针。

livenessProbe:
      httpGet:
        path: v1.0/healthz
        port: 3500
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds : 5
      failureThreshold : 3
readinessProbe:
      httpGet:
        path: v1.0/healthz
        port: 3500
      initialDelaySeconds: 5
      periodSeconds: 10
      timeoutSeconds : 5
      failureThreshold: 3