找回密码
 立即注册
首页 业界区 业界 [.NET] Aspire Dashboard: 云原生可观测性

[.NET] Aspire Dashboard: 云原生可观测性

岑韬哎 2025-9-28 18:13:43
Aspire Dashboard 遥测数据采集机制详解

概述

.NET Aspire Dashboard是一个专门为分布式应用程序设计的可观测性平台,它通过OpenTelemetry协议(OTLP)采集和展示应用程序的日志(Logs)指标(Metrics)追踪(Traces)三大类遥测数据。Dashboard同时支持gRPC和HTTP两种传输协议,为应用程序提供了灵活的数据上报方式。
整体架构

Aspire Dashboard的遥测数据采集架构主要包含以下几个核心组件:
graph TB    subgraph "应用程序/服务"        A1["日志生成"]        A2["指标生成"]         A3["追踪生成"]        A1 --> OTEL        A2 --> OTEL        A3 --> OTEL        OTEL["OpenTelemetry SDK
(OTLP Export)"]    end        OTEL -->|HTTP/gRPC| DASHBOARD        subgraph DASHBOARD ["Aspire Dashboard"]        subgraph ENDPOINTS ["OTLP 接收端点"]            subgraph HTTP_EP ["HTTP 端点"]                H1["/v1/logs"]                H2["/v1/traces"]                H3["/v1/metrics"]            end                        subgraph GRPC_EP ["gRPC 端点"]                G1["OtlpGrpcLogsService"]                G2["OtlpGrpcTraceService"]                G3["OtlpGrpcMetricsService"]            end        end                ENDPOINTS --> STORAGE                subgraph STORAGE ["数据处理与存储层"]            subgraph REPO ["TelemetryRepository"]                subgraph STORES ["存储组件"]                    S1["Logs 存储
CircularBuffer<OtlpLogEntry>"]                    S2["Metrics 存储
Resource Based Storage"]                    S3["Traces 存储
CircularBuffer<OtlpTrace>"]                end            end        end                STORAGE --> UI                subgraph UI ["Dashboard UI"]            U1["日志查看器"]            U2["指标图表"]            U3["追踪分析器"]        end    end        style A1 fill:#e1f5fe    style A2 fill:#e8f5e8    style A3 fill:#fff3e0    style OTEL fill:#f3e5f5    style S1 fill:#e1f5fe    style S2 fill:#e8f5e8    style S3 fill:#fff3e0核心组件详解

1. OTLP接收端点

Dashboard提供两种接收遥测数据的方式:
HTTP端点 (OtlpHttpEndpointsBuilder)


  • 路径: /v1/logs, /v1/traces, /v1/metrics
  • 支持格式: Protocol Buffers (application/x-protobuf)
  • CORS支持: 可配置跨域资源共享
  • 认证: 支持API Key认证
  1. // HTTP端点映射示例
  2. group.MapPost("logs", static (MessageBindable<ExportLogsServiceRequest> request, OtlpLogsService service) =>
  3. {
  4.     if (request.Message == null)
  5.     {
  6.         return Results.Empty;
  7.     }
  8.     return OtlpResult.Response(service.Export(request.Message));
  9. });
复制代码
gRPC端点


  • 服务: OtlpGrpcLogsService, OtlpGrpcTraceService, OtlpGrpcMetricsService
  • 协议: OpenTelemetry标准gRPC服务
  • 性能: 更高效的二进制传输
  1. [Authorize(Policy = OtlpAuthorization.PolicyName)]
  2. public class OtlpGrpcLogsService : LogsService.LogsServiceBase
  3. {
  4.     public override Task<ExportLogsServiceResponse> Export(ExportLogsServiceRequest request, ServerCallContext context)
  5.     {
  6.         return Task.FromResult(_logsService.Export(request));
  7.     }
  8. }
复制代码
2. 数据处理服务

日志处理 (OtlpLogsService)
  1. public ExportLogsServiceResponse Export(ExportLogsServiceRequest request)
  2. {
  3.     var addContext = new AddContext();
  4.     _telemetryRepository.AddLogs(addContext, request.ResourceLogs);
  5.    
  6.     return new ExportLogsServiceResponse
  7.     {
  8.         PartialSuccess = new ExportLogsPartialSuccess
  9.         {
  10.             RejectedLogRecords = addContext.FailureCount
  11.         }
  12.     };
  13. }
复制代码
追踪处理 (OtlpTraceService)
  1. public ExportTraceServiceResponse Export(ExportTraceServiceRequest request)
  2. {
  3.     var addContext = new AddContext();
  4.     _telemetryRepository.AddTraces(addContext, request.ResourceSpans);
  5.    
  6.     return new ExportTraceServiceResponse
  7.     {
  8.         PartialSuccess = new ExportTracePartialSuccess
  9.         {
  10.             RejectedSpans = addContext.FailureCount
  11.         }
  12.     };
  13. }
复制代码
指标处理 (OtlpMetricsService)
  1. public ExportMetricsServiceResponse Export(ExportMetricsServiceRequest request)
  2. {
  3.     var addContext = new AddContext();
  4.     _telemetryRepository.AddMetrics(addContext, request.ResourceMetrics);
  5.    
  6.     return new ExportMetricsServiceResponse
  7.     {
  8.         PartialSuccess = new ExportMetricsPartialSuccess
  9.         {
  10.             RejectedDataPoints = addContext.FailureCount
  11.         }
  12.     };
  13. }
复制代码
3. 数据存储层 (TelemetryRepository)

TelemetryRepository是Dashboard的核心数据管理组件,负责:
存储结构


  • 日志存储: CircularBuffer - 循环缓冲区,FIFO方式管理
  • 追踪存储: CircularBuffer - 支持容量管理和自动清理
  • 指标存储: 基于Resource的存储模式
  • 资源管理: ConcurrentDictionary
数据容量管理
  1. public sealed class TelemetryLimitOptions
  2. {
  3.     public int MaxLogCount { get; set; } = 10_000;        // 最大日志条数
  4.     public int MaxTraceCount { get; set; } = 10_000;      // 最大追踪条数  
  5.     public int MaxMetricsCount { get; set; } = 50_000;    // 最大指标点数
  6.     public int MaxAttributeCount { get; set; } = 128;     // 最大属性数量
  7.     public int MaxAttributeLength { get; set; } = int.MaxValue; // 最大属性长度
  8.     public int MaxSpanEventCount { get; set; } = int.MaxValue;  // 最大Span事件数
  9. }
复制代码
数据插入机制

日志插入:支持乱序插入和时间戳排序
  1. public void AddLogsCore(AddContext context, OtlpResourceView resourceView, RepeatedField<ScopeLogs> scopeLogs)
  2. {
  3.     _logsLock.EnterWriteLock();
  4.     try
  5.     {
  6.         foreach (var record in sl.LogRecords)
  7.         {
  8.             var logEntry = new OtlpLogEntry(record, resourceView, scope, _otlpContext);
  9.             
  10.             // 基于时间戳插入到正确位置
  11.             var added = false;
  12.             for (var i = _logs.Count - 1; i >= 0; i--)
  13.             {
  14.                 if (logEntry.TimeStamp > _logs[i].TimeStamp)
  15.                 {
  16.                     _logs.Insert(i + 1, logEntry);
  17.                     added = true;
  18.                     break;
  19.                 }
  20.             }
  21.             if (!added)
  22.             {
  23.                 _logs.Insert(0, logEntry);
  24.             }
  25.         }
  26.     }
  27.     finally
  28.     {
  29.         _logsLock.ExitWriteLock();
  30.     }
  31. }
复制代码
4. 实时订阅机制

Dashboard使用发布-订阅模式实现实时数据更新:
  1. // 订阅管理
  2. private readonly List<Subscription> _resourceSubscriptions = new();
  3. private readonly List<Subscription> _logSubscriptions = new();
  4. private readonly List<Subscription> _metricsSubscriptions = new();
  5. private readonly List<Subscription> _tracesSubscriptions = new();
  6. // 触发订阅更新
  7. private void RaiseSubscriptionChanged(List<Subscription> subscriptions)
  8. {
  9.     lock (_lock)
  10.     {
  11.         foreach (var subscription in subscriptions)
  12.         {
  13.             subscription.TryExecute();
  14.         }
  15.     }
  16. }
复制代码
5. 暂停管理 (PauseManager)

支持暂停数据采集功能,避免在调试期间数据过载:
  1. public void AddLogs(AddContext context, RepeatedField<ResourceLogs> resourceLogs)
  2. {
  3.     if (_pauseManager.AreStructuredLogsPaused(out _))
  4.     {
  5.         _logger.LogTrace("{Count} incoming structured log(s) ignored because of an active pause.", resourceLogs.Count);
  6.         return;
  7.     }
  8.     // ... 处理日志
  9. }
复制代码
6. 组件关系图

graph TD    subgraph "Dashboard Web Application"        DWA[DashboardWebApplication] --> OTLP_HTTP[OtlpHttpEndpointsBuilder]        DWA --> OTLP_GRPC[gRPC Services]        DWA --> CONFIG[Configuration]                subgraph "OTLP Services"            OTLP_HTTP --> LS[OtlpLogsService]            OTLP_HTTP --> TS[OtlpTraceService]            OTLP_HTTP --> MS[OtlpMetricsService]                        OTLP_GRPC --> GLS[OtlpGrpcLogsService]            OTLP_GRPC --> GTS[OtlpGrpcTraceService]            OTLP_GRPC --> GMS[OtlpGrpcMetricsService]                        GLS --> LS            GTS --> TS            GMS --> MS        end                subgraph "Data Layer"            LS --> TR[TelemetryRepository]            TS --> TR            MS --> TR                        TR --> PM[PauseManager]            TR --> CB1[CircularBuffer<Logs>]            TR --> CB2[CircularBuffer<Traces>]            TR --> RM[Resource Manager]            TR --> SUB[Subscription System]        end                subgraph "UI Components"            SUB --> LV[Log Viewer]            SUB --> MV[Metrics Viewer]            SUB --> TV[Trace Viewer]        end    end        subgraph "Host Integration"        RP[ResourcePublisher] --> DC[DashboardClient]        DC --> TR    end        style DWA fill:#f9f,stroke:#333,stroke-width:3px    style TR fill:#bbf,stroke:#333,stroke-width:2px    style SUB fill:#bfb,stroke:#333,stroke-width:2px配置与端点

端点配置 (OtlpOptions)
  1. public sealed class OtlpOptions
  2. {
  3.     public string? PrimaryApiKey { get; set; }          // 主API密钥
  4.     public string? SecondaryApiKey { get; set; }        // 备用API密钥  
  5.     public OtlpAuthMode? AuthMode { get; set; }         // 认证模式
  6.     public string? GrpcEndpointUrl { get; set; }        // gRPC端点URL
  7.     public string? HttpEndpointUrl { get; set; }        // HTTP端点URL
  8.     public OtlpCors Cors { get; set; } = new();         // CORS配置
  9. }
复制代码
CORS配置
  1. public sealed class OtlpCors
  2. {
  3.     public string? AllowedOrigins { get; set; }   // 允许的来源域名
  4.     public string? AllowedHeaders { get; set; }   // 允许的请求头
  5.    
  6.     [MemberNotNullWhen(true, nameof(AllowedOrigins))]
  7.     public bool IsCorsEnabled => !string.IsNullOrEmpty(AllowedOrigins);
  8. }
复制代码
应用程序配置

Dashboard在DashboardWebApplication中进行完整的服务配置:
  1. // 注册OTLP服务
  2. builder.Services.AddSingleton<TelemetryRepository>();
  3. builder.Services.AddTransient<OtlpLogsService>();
  4. builder.Services.AddTransient<OtlpTraceService>();
  5. builder.Services.AddTransient<OtlpMetricsService>();
  6. // 配置gRPC
  7. builder.Services.AddGrpc();
  8. // 映射端点
  9. _app.MapHttpOtlpApi(dashboardOptions.Otlp);      // HTTP端点
  10. _app.MapGrpcService<OtlpGrpcMetricsService>();   // gRPC指标服务
  11. _app.MapGrpcService<OtlpGrpcTraceService>();     // gRPC追踪服务  
  12. _app.MapGrpcService<OtlpGrpcLogsService>();      // gRPC日志服务
复制代码
与Aspire宿主的集成

资源发布 (ResourcePublisher)

Dashboard通过ResourcePublisher与Aspire宿主通信,获取应用程序资源信息:
  1. internal sealed class ResourcePublisher
  2. {
  3.     private readonly Dictionary<string, SourceAndResourceSnapshot> _snapshot = [];
  4.     private ImmutableHashSet<Channel<ResourceSnapshotChange>> _outgoingChannels = [];
  5.    
  6.     // 集成资源变更并广播给订阅者
  7.     internal async ValueTask IntegrateAsync(IResource source, ResourceSnapshot snapshot, ResourceSnapshotChangeType changeType)
  8.     {
  9.         lock (_syncLock)
  10.         {
  11.             switch (changeType)
  12.             {
  13.                 case ResourceSnapshotChangeType.Upsert:
  14.                     _snapshot[snapshot.Name] = new SourceAndResourceSnapshot(source, snapshot);
  15.                     break;
  16.                 case ResourceSnapshotChangeType.Delete:
  17.                     _snapshot.Remove(snapshot.Name);
  18.                     break;
  19.             }
  20.         }
  21.         
  22.         // 通知所有订阅者
  23.         foreach (var channel in channels)
  24.         {
  25.             await channel.Writer.WriteAsync(new(changeType, snapshot), cancellationToken);
  26.         }
  27.     }
  28. }
复制代码
Dashboard客户端 (DashboardClient)

实现与资源服务的gRPC通信:
  1. internal sealed class DashboardClient : IDashboardClient
  2. {
  3.     private readonly Dictionary<string, ResourceViewModel> _resourceByName = new();
  4.     private readonly GrpcChannel? _channel;
  5.     private Aspire.DashboardService.Proto.V1.DashboardService.DashboardServiceClient? _client;
  6.    
  7.     // 订阅资源变更
  8.     public async IAsyncEnumerable<IReadOnlyList<ResourceViewModelChange>> SubscribeResourcesAsync()
  9.     {
  10.         // 通过gRPC流式接收资源更新
  11.     }
  12. }
复制代码
数据流转过程

1. 数据接收流程

sequenceDiagram    participant App as 应用程序    participant OTLP as OTLP Exporter    participant HTTP as HTTP端点    participant GRPC as gRPC端点    participant Service as 数据处理服务    participant Repo as TelemetryRepository    participant Storage as 存储层    App->>OTLP: 生成遥测数据    OTLP->>HTTP: HTTP/JSON 请求    OTLP->>GRPC: gRPC 调用        HTTP->>Service: OtlpLogsService.Export()    GRPC->>Service: OtlpGrpcLogsService.Export()        Service->>Repo: AddLogs/AddTraces/AddMetrics    Repo->>Storage: 写入CircularBuffer    Storage-->>Repo: 存储确认    Repo-->>Service: 处理结果    Service-->>HTTP: ExportResponse    Service-->>GRPC: ExportResponse2. 数据查询流程

sequenceDiagram    participant UI as Dashboard UI    participant Sub as 订阅系统    participant Repo as TelemetryRepository    participant Filter as 数据过滤器    participant Storage as 存储层    UI->>Sub: 订阅数据更新    Sub->>Repo: 注册订阅回调        loop 实时数据查询        UI->>Repo: 查询遥测数据        Repo->>Filter: 应用过滤条件        Filter->>Storage: 读取数据        Storage-->>Filter: 返回数据        Filter-->>Repo: 过滤后数据        Repo-->>UI: 返回结果    end        Note over Storage: 数据变更时    Storage->>Repo: 触发变更事件    Repo->>Sub: 通知订阅者    Sub->>UI: 实时推送更新3. 实时更新机制

flowchart LR    A[数据变更] --> B[触发订阅]    B --> C[推送到UI组件]    C --> D[前端实时刷新]        subgraph 订阅管理        E[ResourceSubscriptions]        F[LogSubscriptions]        G[MetricsSubscriptions]        H[TracesSubscriptions]    end        B --> E    B --> F    B --> G    B --> H性能优化特性

1. 内存管理


  • 循环缓冲区: 自动清理老数据,避免内存泄漏
  • 容量限制: 可配置的数据条数上限
  • 分段锁: 使用ReaderWriterLockSlim减少锁争用
2. 数据压缩


  • HTTP压缩: 支持响应压缩
  • Protocol Buffers: 高效的二进制序列化
3. 异步处理


  • 流式处理: 支持大批量数据的流式处理
  • 异步订阅: 非阻塞的实时数据推送
总结

Aspire Dashboard采用了模块化的架构设计,通过标准的OpenTelemetry协议接收遥测数据,使用高效的存储机制和实时订阅模式,为分布式应用程序提供了完整的可观测性解决方案。其核心优势包括:

  • 标准化: 完全基于OpenTelemetry标准,确保与各种应用程序的兼容性
  • 高性能: 使用循环缓冲区和异步处理,支持高吞吐量的数据采集
  • 实时性: 基于订阅模式的实时数据更新机制
  • 可配置: 灵活的配置选项,支持不同的部署场景
  • 多协议: 同时支持HTTP和gRPC两种传输协议
该架构为.NET生态系统中的分布式应用程序监控和调试提供了强大的基础设施支持。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册