SDK 配置与资源属性
目标
通过环境变量配置 SDK,按照语义约定确定资源属性,并在 Kubernetes 中使用 Downward API 注入实例标识符。最后亲自创建一个检查 span 名称基数的 linter。
为什么重要
可观测性埋点中最难撤销的决定是资源属性。代码随时可以修改,但一旦更改 service.name,仪表板、告警、服务图以及与历史数据的关联都会全部中断。因此,在增加 span 之前必须先确定这些属性。名称约定出于同样原因非常重要。deployment.environment 和 deployment.environment.name 在人看来相同,但对系统而言是两个完全不同的属性,而仪表板变量只会读取其中一个。span 名称也是如此。如果名称中混入 ID,后端的聚合视图会彻底失效,而这种事故不会在部署后立即发现,往往在几周后以“服务图很奇怪”的形式出现。因此,必须由 CI 阻止,而不是依赖人的记忆。
步骤
- 创建
/root/otca-sdk/otel.env,写入OTEL_SERVICE_NAME=checkout-api、OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc:4317、OTEL_EXPORTER_OTLP_PROTOCOL=grpc。每行一项,格式为키=값。 - 在同一文件中添加
OTEL_RESOURCE_ATTRIBUTES。值是用逗号连接的service.version=2.7.1、deployment.environment.name=prod、service.namespace=commerce。不要使用旧名称deployment.environment。 - 在同一文件中添加
OTEL_TRACES_SAMPLER=parentbased_traceidratio、OTEL_TRACES_SAMPLER_ARG=0.1、OTEL_PROPAGATORS=tracecontext,baggage。 - 在同一文件中添加四个上限:
OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64、OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=2048、OTEL_BSP_MAX_QUEUE_SIZE=4096、OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512。 - 在
/root/otca-sdk/deployment.yaml中编写 Deployment。metadata.name: checkout-api、metadata.namespace: otca-sdk。在第一个容器的env中加入POD_NAME(fieldRefmetadata.name)、POD_NAMESPACE(fieldRefmetadata.namespace)、OTEL_SERVICE_NAME=checkout-api、OTEL_EXPORTER_OTLP_ENDPOINT(包含 4317)以及OTEL_RESOURCE_ATTRIBUTES;其值中必须包含deployment.environment.name=prod、service.instance.id=$(POD_NAME)、k8s.namespace.name=$(POD_NAMESPACE)。 - 创建命名空间
otca-sdk,并将第 5 步的清单应用到集群。 - 在
/root/otca-sdk/span-names.txt中写入至少 6 行 span 名称。其中至少 4 行必须像GET /...一样以 HTTP 方法开头,至少 3 行必须包含:id占位符。不能有任何一行包含连续三个或更多数字或 UUID。 - 编写
/root/otca-sdk/lint-span-names.sh。如果第一个参数指定的文件中包含连续三个或更多数字或 UUID 形式,就输出对应行并以非零代码退出;否则以 0 退出。
参考
- 第 1~4 步都写入同一个文件
/root/otca-sdk/otel.env。可以添加export前缀,也可以不添加。 - 第 5 步的
OTEL_RESOURCE_ATTRIBUTES可以使用value: >-折叠块分成多行编写。 - 第 8 步的验证包括两种输入:你创建的
span-names.txt(必须通过),以及评分器创建的 ID、UUID 列表(必须阻止)。 - 常见错误 1:协议是
grpc,却将 endpoint 端口写成 4318。这样连接本身就会失败。 - 常见错误 2:在
service.instance.id中将 Pod 名称硬编码为字符串。
服务名称与 endpoint
创建 /root/otca-sdk/otel.env,写入 OTEL_SERVICE_NAME=checkout-api、OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector.observability.svc:4317、OTEL_EXPORTER_OTLP_PROTOCOL=grpc。每行一项,格式为 키=값。
只使用环境变量即可控制 SDK。因此,埋点配置位于部署清单而非代码中,更改 endpoint 无需代码审查。端口和协议必须正确配对。
确定资源属性
在同一文件中添加 OTEL_RESOURCE_ATTRIBUTES。值是用逗号连接的 service.version=2.7.1、deployment.environment.name=prod、service.namespace=commerce。不要使用旧名称 deployment.environment。
资源属性会附加到此进程发出的所有信号上。多个属性用逗号连接,每个都采用键=值形式。环境属性名称在近期约定中发生了变化,请注意不要使用旧名称。
Sampler 与 Propagator
在同一文件中添加 OTEL_TRACES_SAMPLER=parentbased_traceidratio、OTEL_TRACES_SAMPLER_ARG=0.1、OTEL_PROPAGATORS=tracecontext,baggage。
Sampler 名称中必须带有 parentbased,才能遵循父级决定。否则各服务会独立进行概率判断,导致 trace 在中途被截断。可以用逗号指定多个 Propagator。
span 大小与队列上限
在同一文件中添加四个上限:OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT=64、OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT=2048、OTEL_BSP_MAX_QUEUE_SIZE=4096、OTEL_BSP_MAX_EXPORT_BATCH_SIZE=512。
属性数量有默认上限,但值长度没有。如果整个请求正文都被写入,一个 span 可能达到数百 KB。还要同时确定 Batch Span Processor 的队列大小和批次大小。
使用 Downward API 注入实例标识符
在 /root/otca-sdk/deployment.yaml 中编写 Deployment。metadata.name: checkout-api、metadata.namespace: otca-sdk。在第一个容器的 env 中加入 POD_NAME(fieldRef metadata.name)、POD_NAMESPACE(fieldRef metadata.namespace)、OTEL_SERVICE_NAME=checkout-api、OTEL_EXPORTER_OTLP_ENDPOINT(包含 4317)以及 OTEL_RESOURCE_ATTRIBUTES;其值中必须包含 deployment.environment.name=prod、service.instance.id=$(POD_NAME)、k8s.namespace.name=$(POD_NAMESPACE)。
如果硬编码 Pod 名称,每次重启后都会留下错误值。通过 fieldRef 将 metadata.name 和 metadata.namespace 接收到环境变量中,再在另一个环境变量中用括号表示法引用,kubelet 就会进行替换。多行值使用折叠块更易阅读。
应用到集群
创建命名空间 otca-sdk,并将第 5 步的清单应用到集群。
先创建命名空间,再应用清单。评分会读取实际进入集群的 Pod 模板,因此只修改文件而不应用就无法通过。
低基数 span 名称列表
在 /root/otca-sdk/span-names.txt 中写入至少 6 行 span 名称。其中至少 4 行必须像 GET /... 一样以 HTTP 方法开头,至少 3 行必须包含 :id 占位符。不能有任何一行包含连续三个或更多数字或 UUID。
后端按 span 名称分组,生成延迟统计和服务图。如果名称中包含订单号或 UUID,分组数量会增加到与请求数相同。路由应使用模板,具体值则作为属性发送。
span 名称 linter
编写 /root/otca-sdk/lint-span-names.sh。如果第一个参数指定的文件中包含连续三个或更多数字或 UUID 形式,就输出对应行并以非零代码退出;否则以 0 退出。
脚本通过第一个参数接收列表文件。如果其中包含连续三个或更多数字或 UUID 形式,输出该行并以失败结束即可。前一步创建的列表必须通过。