输出缓存序列化并发请求

本文关键字:请求 并发 序列化 缓存 输出 | 更新日期: 2023-09-27 18:31:35

OutputCache 是在 ASP.NET <=4.6 MVC 中提高性能的简单方法。我们应该将此属性应用于非常昂贵的操作,但是在第一个请求和正在创建的缓存之间,我们可能会有很多并发请求 - 并且会消耗我们试图保护的服务器资源(内存、CPU、I/O)。

如果多个请求来自同一用户,则默认情况下,aspnet 序列化我们在此链接中看到的请求, ASP.NET 服务器国的缺点:

默认情况下,ASP.NET 管道不会处理属于 同一会话同时进行。它序列化它们,即对它们进行排队 按照收到的顺序进行处理 串行而不是并行。

因此,为了模拟这种情况,我们需要创建多个请求(来自不同用户)。可以通过从多个浏览器创建请求或使用具有多个线程的任何类型的工作负载来完成。

因此,我正在尝试从OutputCacheAttribute继承并创建类似OutputCacheConcurrentRequestAttribute的东西,并序列化来自多个用户的请求。有人尝试过这样做吗?

这个想法是在第一个请求未完成的情况下Thread.Sleep对同一资源的所有后续请求(通过 OutputCache 属性和操作考虑唯一性OnActionExecuting)。

在ILSpy中查找IL,一些可以帮助我完成这项工作的方法都是私有和内部的,例如:

汇编:系统.Web.Mvc

命名空间:System.Web.Mvc

class OutputCacheAttribute
{
private GetChildActionUniqueId
private BuildUniqueIdFromActionParameters
}
internal class DescriptorUtil

我试图不复制代码也不使用反射器(出于性能原因)。

有没有人遇到过同样的问题?


编辑 1

经过一些研究,我发现MVC Donut缓存在OutputCacheAttribute内部遇到了很多困难,他们已经完全重写了它:

在实现甜甜圈缓存方面,挂钩到 OutputCacheModule HttpModule 将非常困难/不可能,因此 相反,我们必须完全重写 OutputCacheAttribute

使用DonutOutputCacheAttribute完成我的想法要容易得多。

输出缓存序列化并发请求

您实际上是将其视为性能问题还是只是理论上的问题? 我要提醒的是,在这条路上走得太远可能会损害性能...... 也许考虑预热缓存的解决方案?

也就是说,您可能运气更好,只需锁定您尝试执行一次的操作。 创建一个变量,并在操作筛选器中锁定该变量(在操作触发之前),并在操作触发后在操作筛选器中释放,这应该序列化您的请求。

public class SerializedOutputCacheAttribute : OutputCacheAttribute
{
    private readonly object lockObject = new object();
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Monitor.Enter(this.lockObject);
        base.OnActionExecuting(filterContext);
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        Monitor.Exit(this.lockObject);
    }
}

然后,您可以将其应用于任何操作,该操作将被序列化,但不会影响其他操作。

    [SerializedOutputCache(Duration = 5000)]
    public ActionResult About()

编辑:这种方法不起作用,因为OutputCacheAttribute实际上推送到IIS进行缓存,因此该操作仍将触发多次。