Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
微服务开发中的常见问题之一是通过处理过程中涉及的所有服务跟踪来自客户端的操作的能力。 此能力对于进行调试、性能分析、A/B 测试和其他典型诊断方案相当有用。 此问题的一部分是跟踪逻辑工作单元,其中包括消息处理结果、延迟以及外部依赖调用。 另一个组成部分是这些诊断事件在流程边界之外的关联。
当生成者通过队列发送消息时,此活动通常发生在其他某个逻辑操作的范围内,并由其他客户端或服务启动。 当使用者收到消息时,会继续相同的操作。 生成者与使用者(以及其他处理该操作的服务)推测会发出遥测事件,以跟踪操作流和结果。 若要将此类事件相关联并以端到端的方式跟踪操作,报告遥测数据的每个服务必须为每个事件附加跟踪上下文。
Azure 服务总线消息传递已定义生成者与使用者应该用来传递此类跟踪上下文的有效负载属性。 协议基于 W3C Trace-Context。
| 属性名称 | 说明 |
|---|---|
Diagnostic-Id |
生成者针对队列发出的外部调用的唯一标识符。 有关格式,请参阅 W3C Trace-Context trace parent 标头 |
服务总线 .NET 客户端自动跟踪
ServiceBusProcessor
适用于 .NET 的 Azure 消息传送服务总线客户端的类提供了可由跟踪系统或某段客户端代码挂接的跟踪插桩点。 使用检测功能可以从客户端跟踪对服务总线消息传递服务发出的所有调用。 如果消息处理是使用 ProcessMessageAsync 的 ServiceBusProcessor(消息处理程序模式)完成的,则还会对消息处理进行插桩。
使用 Azure 应用程序 Insights 跟踪
Microsoft Application Insights 提供丰富的性能监视功能,包括自动请求和依赖项跟踪。
请根据项目类型安装 Application Insights SDK:
- ASP.NET - 安装版本 2.5-beta2 或更高版本
- ASP.NET Core - 安装版本 2.2.0-beta2 或更高版本。 这些链接提供了有关安装 SDK、创建资源和配置 SDK(如果需要)的详细信息。 针对非 ASP.NET 应用程序,请参阅适用于控制台应用程序的 Azure 应用程序 Insights 一文。
如果你使用 ProcessMessageAsync 的 ServiceBusProcessor(消息处理程序模式)来处理消息,则还会对消息处理进行插桩。 系统会自动跟踪由你的服务发出的所有服务总线调用,并将其与其他遥测项关联。 否则,请参考以下示例手动进行消息处理跟踪。
跟踪消息处理
async Task ProcessAsync(ProcessMessageEventArgs args)
{
ServiceBusReceivedMessage message = args.Message;
if (message.ApplicationProperties.TryGetValue("Diagnostic-Id", out var objectId) && objectId is string diagnosticId)
{
var activity = new Activity("ServiceBusProcessor.ProcessMessage");
activity.SetParentId(diagnosticId);
// If you're using Microsoft.ApplicationInsights package version 2.6-beta or higher, you should call StartOperation<RequestTelemetry>(activity) instead
using (var operation = telemetryClient.StartOperation<RequestTelemetry>("Process", activity.RootId, activity.ParentId))
{
telemetryClient.TrackTrace("Received message");
try
{
// process message
}
catch (Exception ex)
{
telemetryClient.TrackException(ex);
operation.Telemetry.Success = false;
throw;
}
telemetryClient.TrackTrace("Done");
}
}
}
在本示例中,系统针对每个已处理的消息报告请求遥测,并提供时间戳、持续时间和结果(成功)。 遥测功能也具有一组关联属性。 在消息处理期间报告的嵌套跟踪和异常也会被加上关联属性,表示它们是 RequestTelemetry 的“子级”。
如果在消息处理期间对支持的外部组件发出调用,则还会自动跟踪和关联这些调用。 请参阅使用 Application Insights .NET SDK 跟踪自定义操作以进行手动跟踪和关联。
如果除 Application Insights SDK 之外还运行了外部代码,则在查看 Application Insights 日志时,你会发现 持续时间 延长。
这并不意味着接收消息时存在延迟。 在这种情况下,消息已经被接收,因为消息以参数的形式传递给 SDK 代码。 而且,App Insights 日志(Process)中的 name 标记表明,该消息现正由你的外部事件处理代码进行处理。 此问题与 Azure 无关。 相反,这些指标指示的是外部代码的效率,前提是已从服务总线接收到消息。
使用 OpenTelemetry 进行跟踪
服务总线 .NET 客户端库版本 7.5.0 及更高版本支持实验模式下的 OpenTelemetry。 有关详细信息,请参阅 .NET SDK 中的分布式跟踪。
无追溯系统的跟踪
如果跟踪系统不支持自动 服务总线 调用跟踪,可以考虑将此类支持添加到跟踪系统或应用程序中。 本部分介绍服务总线 .NET 客户端发送的诊断事件。
服务总线 .NET Client 使用 .NET 跟踪基元 System.Diagnostics.Activity 和 System.Diagnostics.DiagnosticSource 进行检测。
Activity 充当跟踪上下文,而 DiagnosticSource 是通知机制。
如果没有针对 DiagnosticSource 事件的侦听器,插桩会关闭,从而保持插桩成本为零。 DiagnosticSource 将所有控制权授予监听器:
- 侦听器控制要侦听的源和事件
- 侦听器控制事件速率和采样
- 事件连同某个有效负载一起发送,该有效负载可提供完整上下文,使你能够在事件发生期间访问和修改 Message 对象
在继续实现之前,请先熟悉DiagnosticSource 用户指南。
让我们在 ASP.NET Core 应用中为服务总线事件创建一个侦听器,以通过 Microsoft.Extensions.Logging 写入日志。 它使用 System.Reactive.Core 库来订阅 DiagnosticSource(不使用它也能轻松订阅 DiagnosticSource)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory factory, IApplicationLifetime applicationLifetime)
{
// configuration...
var serviceBusLogger = factory.CreateLogger("Azure.Messaging.ServiceBus");
IDisposable innerSubscription = null;
IDisposable outerSubscription = DiagnosticListener.AllListeners.Subscribe(delegate (DiagnosticListener listener)
{
// subscribe to the Service Bus DiagnosticSource
if (listener.Name == "Azure.Messaging.ServiceBus")
{
// receive event from Service Bus DiagnosticSource
innerSubscription = listener.Subscribe(delegate (KeyValuePair<string, object> evnt)
{
// Log operation details once it's done
if (evnt.Key.EndsWith("Stop"))
{
Activity currentActivity = Activity.Current;
serviceBusLogger.LogInformation($"Operation {currentActivity.OperationName} is finished, Duration={currentActivity.Duration}, Id={currentActivity.Id}, StartTime={currentActivity.StartTimeUtc}");
}
});
}
});
applicationLifetime.ApplicationStopping.Register(() =>
{
outerSubscription?.Dispose();
innerSubscription?.Dispose();
});
}
在此示例中,侦听器记录每个服务总线操作的持续时间、结果、唯一标识符和开始时间。
活动
所有事件都会具有以下属性,这些属性符合开放式遥测规范: https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md 。
-
message_bus.destination- 队列/主题/订阅路径 -
peer.address- 完全限定的命名空间 -
kind- 生成者、消费者或客户端。 发送消息时使用生产者,接收时使用消费者,结算时使用客户端。 messaging.system-servicebus
所有事件还具有 Entity 和 Endpoint 属性。
-
Entity- 实体(队列、主题等)的名称 -
Endpoint- 服务总线终结点 URL
已插桩的操作
下面是已插桩操作的完整列表:
| 操作名称 | 已跟踪的 API |
|---|---|
| ServiceBusSender.Send | ServiceBusSender.SendMessageAsync ServiceBusSender.SendMessagesAsync |
| ServiceBusSender.Schedule | ServiceBusSender.ScheduleMessageAsync ServiceBusSender.ScheduleMessagesAsync |
| ServiceBusSender.Cancel | ServiceBusSender.CancelScheduledMessageAsync ServiceBusSender.CancelScheduledMessagesAsync |
| ServiceBusReceiver.Receive | ServiceBusReceiver.ReceiveMessageAsync ServiceBusReceiver.ReceiveMessagesAsync |
| ServiceBusReceiver.ReceiveDeferred | ServiceBusReceiver.ReceiveDeferredMessagesAsync |
| ServiceBusReceiver.Peek | ServiceBusReceiver.PeekMessageAsync ServiceBusReceiver.PeekMessagesAsync |
| ServiceBusReceiver.Abandon | ServiceBusReceiver.AbandonMessagesAsync |
| ServiceBusReceiver.Complete | ServiceBusReceiver.CompleteMessagesAsync |
| ServiceBusReceiver.DeadLetter | ServiceBusReceiver.DeadLetterMessagesAsync |
| ServiceBusReceiver.Defer | ServiceBusReceiver.DeferMessagesAsync |
| ServiceBusReceiver.RenewMessageLock | ServiceBusReceiver.RenewMessageLockAsync |
| ServiceBusSessionReceiver.RenewSessionLock | ServiceBusSessionReceiver.RenewSessionLockAsync |
| ServiceBusSessionReceiver.GetSessionState | ServiceBusSessionReceiver.GetSessionStateAsync |
| ServiceBusSessionReceiver.SetSessionState | ServiceBusSessionReceiver.SetSessionStateAsync |
| ServiceBusProcessor.ProcessMessage | 已在 ServiceBusProcessor 上设置处理器回调。 ProcessMessageAsync 属性 |
| ServiceBusSessionProcessor.ProcessSessionMessage | 已在 ServiceBusSessionProcessor 上设置处理器回调。 ProcessMessageAsync 属性 |
筛选和采样
在某些情况下,我们可能只需记录一部分事件,以减少性能开销或存储耗用量。 可以只记录“Stop”事件(如上述示例所示),或者对一定比例的事件进行采样。
DiagnosticSource 提供了通过 IsEnabled 谓词实现这一点的方法。 有关详细信息,请参阅 DiagnosticSource 中基于上下文的筛选。
可以针对单个操作调用 IsEnabled 多次,以将性能影响降到最低。
按以下顺序调用 IsEnabled:
IsEnabled(<OperationName>, string entity, null),例如IsEnabled("ServiceBusSender.Send", "MyQueue1")。 请注意,末尾没有“Start”或“Stop”。 使用此语句可以筛选出特定的操作或队列。 如果回调方法返回false,则不会发送该操作的事件。- 对于“Process”和“ProcessSession”操作,还会收到
IsEnabled(<OperationName>, string entity, Activity activity)回调。 使用它可根据activity.Id或 Tags 属性筛选事件。
- 对于“Process”和“ProcessSession”操作,还会收到
IsEnabled(<OperationName>.Start),例如IsEnabled("ServiceBusSender.Send.Start")。 检查是否应激发“Start”事件。 结果只影响“Start”事件,但进一步的检测不依赖它。
“Stop”事件没有 IsEnabled。
如果某个操作的结果是异常,则会调用 IsEnabled("ServiceBusSender.Send.Exception")。 只能订阅“Exception”事件并阻止其余的插桩。 在此情况下,仍需处理此类异常。 由于其他插桩已被禁用,因此你不应期望跟踪上下文会连同消息一起从使用者流向生成者。
您也可以使用 IsEnabled 来实现采样策略。 基于 Activity.Id 或 Activity.RootId 的采样可确保所有追踪都获得一致的采样结果(前提是该值由跟踪系统或你自己的代码传播)。
当同一个源有多个 DiagnosticSource 侦听器时,只需一个侦听器接受该事件,因此无法保证调用 IsEnabled。
相关内容
- NServiceBus 是一个可以帮助默认发出这些遥测数据的库。
- Application Insights 相关性
- 使用 Application Insights .NET SDK 跟踪自定义操作