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

.NET Core站点IIS Web Garden跨工作进程共享类/内存方案咨询

解决Web Garden多进程下的重复请求控制问题

你遇到的核心问题是Web Garden中每个工作进程(WP)拥有独立的内存空间,原来单进程里的共享控制类只能在单个WP内生效,跨进程就失去了互斥作用。既然不想用SQL Server,下面给你几个基于内存级共享的可行方案,按推荐程度排序:

1. 优先使用Redis分布式内存缓存(最推荐)

Redis是纯内存键值存储,速度完全能满足你的性能需求,而且天然支持跨进程、跨机器的共享锁和数据存储,是解决这类问题的标准方案。

在.NET Core中,你可以通过IDistributedCache来集成Redis,利用它的原子性操作实现请求的互斥控制:

实现思路

  • 针对每个用户的支付请求,生成一个唯一的幂等标识(比如 $"{userId}_payment_{requestId}",其中requestId可以是前端生成的UUID或者请求的唯一哈希)。
  • 尝试将这个标识存入Redis,设置一个合理的过期时间(比如5分钟,防止死锁),并且使用原子性的"不存在则写入"操作(Redis的SETNX命令,对应.NET Core里的StringSet方法加When.NotExists参数)。
  • 如果写入成功,说明这是该用户的首次有效请求,执行支付校验逻辑;如果写入失败,直接返回"重复提交"的提示。

代码示例

public class PaymentService
{
    private readonly IDistributedCache _distributedCache;

    public PaymentService(IDistributedCache distributedCache)
    {
        _distributedCache = distributedCache;
    }

    public async Task<bool> ProcessPaymentAsync(string userId, string requestId)
    {
        // 生成唯一的请求锁键
        var lockKey = $"payment_lock:{userId}:{requestId}";
        // 设置锁的过期时间,避免异常导致锁一直存在
        var lockOptions = new DistributedCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
        };

        // 原子性写入:只有当键不存在时才写入成功
        var lockAcquired = await _distributedCache.StringSetAsync(lockKey, "locked", lockOptions, When.NotExists);

        if (!lockAcquired)
        {
            // 重复请求,直接返回
            return false;
        }

        try
        {
            // 执行你的银行支付校验和余额增加逻辑
            // ...
            return true;
        }
        finally
        {
            // 执行完成后释放锁(可选,因为有过期时间兜底)
            await _distributedCache.RemoveAsync(lockKey);
        }
    }
}

同时,建议把你的会话存储也迁移到Redis(通过AddStackExchangeRedisSession),这样跨进程的会话数据也是共享的,和请求锁配合能更全面地控制重复提交。

2. 使用内存映射文件(进程间共享内存)

如果因为某些原因无法使用Redis,可以考虑用.NET的**内存映射文件(MemoryMappedFile)**实现进程间的共享内存存储。这种方式是直接在操作系统层面开辟一块共享内存区域,所有WP都可以访问。

实现思路

  • 创建一个全局唯一命名的内存映射文件,用来存储已提交的请求标识。
  • 对共享内存的访问要加进程间互斥锁(Mutex),确保读写操作的原子性,避免并发冲突。

注意事项

  • 这种方式实现起来比Redis复杂,需要自己处理内存管理、锁的释放、异常处理等问题。
  • 只能在同一台服务器的多个WP间共享,如果以后扩展到多服务器就失效了,扩展性不如Redis。

3. IIS的传统共享缓存(仅适用于传统ASP.NET,不推荐.NET Core)

如果你是从传统ASP.NET迁移过来的,可能知道IIS有基于System.Web.Cache的共享缓存,但在.NET Core中已经被IDistributedCache替代,而且这种共享缓存依赖于IIS的配置,稳定性和扩展性都不如Redis,所以不推荐在.NET Core中使用。

关键提醒

  • 无论用哪种方案,幂等性标识的设计很重要:要确保同一个用户的同一请求(比如重复点击提交按钮)生成的标识是相同的,而不同请求的标识是唯一的。
  • 一定要设置锁的过期时间:防止因为程序异常、进程崩溃等情况导致锁一直占用,影响后续请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:26:39