首页 文章

如何使用自定义OperationId而不会导致内存泄漏并被Application Insights忽略?

提问于
浏览
5

我的问题是:

在我的方案中注入自定义关联/操作ID的正确/更好的方法是什么,这不会导致内存泄漏并且在Azure门户上正确使用和显示?

以下是我的方案的具体细节:

我有一个Azure辅助角色,它不断地从Azure队列中出列消息并进行处理 . 该消息包含相关ID(操作ID)和操作名称,我希望将其用于在该消息的处理工作期间通过Application Insights收集和推送的所有遥测 .

目前实现的方式是通过自定义 ITelemetryInitializer ,看起来像这样:

public class MiTelemetryInitialiser : ITelemetryInitializer
{
    private readonly ILoggingContext _context;

    public MiTelemetryInitialiser(ILoggingContext context)
    {
        _context = context;
    }

    public void Initialize(ITelemetry telemetry)
    {
        if (string.IsNullOrEmpty(telemetry.Context.Operation.Id) && _context != null)
        {
            telemetry.Context.Operation.Id = _context.OperationId;

            if (!String.IsNullOrWhiteSpace(_context.OperationName))
                telemetry.Context.Operation.Name = _context.OperationName;
        }
    }
}

然后我的worker角色处理循环看起来像这样(si:

while(!cancellationToken.IsCancellationRequested) {
    // 1. Get message from the queue
    // 2. Extract operation name and Correlation Id from the message
    TelemetryConfiguration config = TelemetryConfiguration.CreateDefault();

    var loggingContext = //new logging context with operation name and correlation id
    config.TelemetryInitializers.Add(new MiTelemetryInitialiser(loggingContext));
    TelemetryClient telemetryClient = new TelemetryClient(config);        

    // do work

    client.Flush();
}

我正在使用 TelemetryChannel

<TelemetryChannel Type="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel.ServerTelemetryChannel, Microsoft.AI.ServerTelemetryChannel"/>

有两个问题:

  • 内存泄漏(重要) - 我猜测由于 ServerTelemetryChannel 的实现方式(不幸的是,与大多数.NET SDK不同 - 这个通道不是开源的)并且由于紧密循环?

  • 即使 client.TrackRequest() 正在推送我的自定义关联ID(使用Fiddler验证) - Application Insights会在Azure门户上覆盖它并显示自己的操作ID而不是我的 . 请求期间的其他遥测具有我设置的正确OperationId .

这是运行循环约10分钟后内存泄漏的照片(一段时间后增长到1GB):

enter image description here

2 回答

  • 2

    对于内存泄漏问题 - 我们找到了根本原因,我们将在下一个版本中修复它 . 但是,在您的代码示例中,我们建议不要每次都创建一个新 Channels ,而是重复使用相同的 Channels . 它将允许更好的批处理和更少的内存开销:

    TelemetryConfiguration config = TelemetryConfiguration.CreateDefault();
    
    var loggingContext = //new logging context with operation name and correlation id
    config.TelemetryInitializers.Add(new MiTelemetryInitialiser(loggingContext));
    
    while(!cancellationToken.IsCancellationRequested) {
        // 1. Get message from the queue
        // 2. Extract operation name and Correlation Id from the message
        TelemetryClient telemetryClient = new TelemetryClient(config);        
    
        // do work
    
        client.Flush();
    }
    

    或者只是使用这个:

    while(!cancellationToken.IsCancellationRequested) {
        // 1. Get message from the queue
        // 2. Extract operation name and Correlation Id from the message
        TelemetryClient telemetryClient = new TelemetryClient();        
    
        // do work
    
        client.Flush();
    }
    

    并将遥测初始化程序添加到 ApplicationInsigths.config

    <Add Type="Namespace.MiTelemetryInitialiser , AssemblyName" />
    

    另请参阅my blog post,了解如何将遥测初始化程序添加到全局单例配置中:

    Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.TelemetryInitializers.Add(new MiTelemetryInitialiser());
    
  • 2

    对于操作ID问题 - 在最近的版本中,特别是对于请求遥测,为了避免 RequestTelemetry.IDTelemetryContext.Operation.ID 之间的混淆(从UI角度来看),我们初始化 TelemetryContext.Operation.ID 并在创建请求遥测时立即将其分配给 RequestTelemetry.ID . 见example at github . 解决分配自定义操作ID问题的最佳方法是强制分配您的操作ID,删除 string.IsNullOrEmpty check .

相关问题