You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET6 Blazor Server应用池回收致集合项重复Bug排查求助

.NET6 Blazor Server Azure应用池回收后集合映射重复问题分析

一、应用池回收时的SignalR Circuit行为

Azure App Service默认采用滚动部署策略:新应用池启动后,旧应用池不会立即停止,会继续处理现有请求直到超时或完成,形成新旧实例并行运行的阶段。

对于Blazor Server的SignalR Circuits:

  • 旧池中的活跃Circuit会继续在旧实例上运行,直到用户主动断开或旧池被强制回收;
  • 新的请求(包括重连请求)会被路由到新实例;
  • 旧池收到停止信号后,会逐步终止Circuit,客户端会触发自动重连,重连成功后Circuit迁移到新实例。

这种双实例并行的场景,会导致全局静态资源在两个实例中分别初始化,若初始化逻辑非线程安全,高并发下就会出现异常。

二、核心排查方向

1. Mapster全局配置的线程安全问题

  • 检查TypeAdapterConfig是否为全局静态实例,且初始化过程是否存在并发修改。例如:
    • 是否在请求线程中延迟初始化映射配置(如第一次请求时才注册规则);
    • 初始化时未加锁,导致多线程同时注册同一映射规则,最终映射器对集合项执行多次转换添加,造成重复。
  • 验证方法:将Mapster配置改为启动时一次性初始化,用lock确保初始化逻辑仅执行一次,或使用Mapster提供的线程安全配置API。

2. 集合映射规则的重复注册

  • 检查Mapster集合映射的具体配置:是否多次注册同一List<VM>→List<DM>的映射规则,或配置了PreserveReference等可能导致重复的选项。重复注册会让映射器在转换时多次处理集合项,最终生成重复数据。

3. 双实例并行下的状态隔离问题

  • 确认是否有代码在Circuit级别持有映射器实例,但初始化时未正确隔离状态;若全局静态状态存在跨实例共享逻辑(如静态缓存),也需排查是否出现状态不一致。

4. 部署策略的影响验证

  • 对比滚动部署和「先停止再启动」的差异:后者无实例并行,问题消失,进一步佐证问题出在双实例并行时的并发初始化。

三、修复建议

  • 调整部署策略:使用Azure部署槽交换,先停止旧槽再启动新槽,避免实例并行;
  • 修复Mapster初始化逻辑:在Program.cs中一次性完成全局配置,添加锁确保线程安全,示例:
    private static readonly object _mapsterLock = new object();
    if (!TypeAdapterConfig.GlobalSettings.HasConfigured<ViewModel, DomainModel>())
    {
        lock (_mapsterLock)
        {
            if (!TypeAdapterConfig.GlobalSettings.HasConfigured<ViewModel, DomainModel>())
            {
                TypeAdapterConfig<ViewModel, DomainModel>.NewConfig()
                    .Map(dest => dest.Items, src => src.Items);
                // 其他映射规则
            }
        }
    }
    
  • 添加初始化日志:记录Mapster配置初始化的线程ID和次数,生产环境中排查是否存在并发初始化。

内容的提问来源于stack exchange,提问作者Trygve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 07:47:27