【问题标题】:SagePay (payment gateway) notification return taking long time in ASP.Net MVC applicationSagePay(支付网关)通知返回在 ASP.Net MVC 应用程序中需要很长时间
【发布时间】:2015-01-24 16:24:38
【问题描述】:

我们的网站遇到了与 CPU 使用率高相关的性能问题。在使用分析器时,我们已经确定了一个特定的方法,该方法需要大约 35 秒才能返回。

这是使用称为 SagePay 的支付网关时的回调方法。

我复制了下面这个调用的两个方法:

 public void SagePayNotificationReturn()
    {
        string vendorTxCode = Request.Form["vendortxcode"];

        var sagePayTransaction = this.sagePayTransactionManager.GetTransactionByVendorTxCode(vendorTxCode);
        if (sagePayTransaction == null)
        {
            // Cannot find the order, so log an error and return error response
            int errorId = this.exceptionManager.LogException(System.Web.HttpContext.Current.Request, new Exception(string.Format("Could not find SagePay transaction for order {0}.", vendorTxCode)));
            ReturnResponse(System.Web.HttpContext.Current, StatusEnum.ERROR, string.Format("{0}home/error/{1}", GlobalSettings.SiteURL, errorId), string.Format("Received notification for {0} but the transaction was not found.", vendorTxCode));
        }
        else
        {
            // Store the response and respond immediately to SagePay
            sagePayTransaction.NotificationValues = sagePayTransactionManager.FormValuesToQueryString(Request.Form);
            this.sagePayTransactionManager.Save(sagePayTransaction);
            ReturnResponse(System.Web.HttpContext.Current, StatusEnum.OK, string.Format("{0}payment/processtransaction/{1}", GlobalSettings.SiteURL, vendorTxCode), string.Empty);
        }
    }

 private void ReturnResponse(HttpContext context, StatusEnum status, string redirectUrl, string statusDetail)
    {
        context.Response.Clear();
        context.Response.ContentEncoding = Encoding.UTF8;
        using (StreamWriter streamWriter = new StreamWriter(context.Response.OutputStream))
        {
            streamWriter.WriteLine(string.Concat("Status=", status.ToString()));
            streamWriter.WriteLine(string.Concat("RedirectURL=", redirectUrl));
            streamWriter.WriteLine(string.Concat("StatusDetail=", HttpUtility.HtmlEncode(statusDetail)));
            streamWriter.Flush();
            streamWriter.Close();
        }

        context.ApplicationInstance.CompleteRequest();
    }

GetTransactionByVendorTxCode 方法是一个简单的实体框架调用,所以我排除了这一点。

有没有人在这方面有任何经验,或者他们是否可以看到可能导致此类问题的代码有任何明显错误?

编辑:查看分析器提供的细分表,它说 99.6% 的时间花在 System.Web.Mvc.MvcHandler.BeginProcessRequest() 中。

编辑:使用分析工具 New Relic,它表示 22% 的处理时间花在 this.sagePayTransactionManager.GetTransactionByVendorTxCode(vendorTxCode) 方法上。这只是包含对存储库的 EF6 调用。该调用确实包含一个谓词参数,而不是预定义的条件。难道是查询没有被预编译?

【问题讨论】:

  • “一个简单的实体框架调用” - 你确定吗?这个代码是什么?
  • 看看这个问题/答案,并将调试写入行代码添加到 Application_BeginRequest:stackoverflow.com/a/17073158/82333
  • 将 GetTransactionByVendorTxCode 调用更改为虚拟数据结构,并查看响应时间是否发生剧烈变化。如果它在那里你有瓶颈,如果没有,是时候看看其他地方了。
  • 请同时分析数据库查询部分。可能是 EF 使用联合等生成一个巨大的查询。这可以提供一些见解
  • Aynchronus 操作是否可用于服务调用?如果是,那么您可以在回调中做事吗?异步操作可以告诉您服务从开始请求到请求完成所用的确切时间。

标签: c# asp.net opayo


【解决方案1】:

这是我解决问题的第一步:

在此语句之前放置一个计时器启动,然后在它完成时停止它。告诉我们时间跨度。

var sagePayTransaction = this.sagePayTransactionManager.GetTransactionByVendorTxCode(vendorTxCode);

为此代码块添加另一个计时器:告诉我们与上述方法相比的相对时间。

   using (StreamWriter streamWriter = new StreamWriter(context.Response.OutputStream))
    {
        streamWriter.WriteLine(string.Concat("Status=", status.ToString()));
        streamWriter.WriteLine(string.Concat("RedirectURL=", redirectUrl));
        streamWriter.WriteLine(string.Concat("StatusDetail=", HttpUtility.HtmlEncode(statusDetail)));
        streamWriter.Flush();
        streamWriter.Close();
    }

最后在这里放一个计时器:

context.ApplicationInstance.CompleteRequest();

将信息发回给我们,我将指导您进行下一步。我们在上面所做的是获取跨越本地和远程访问的指标,以找出主要问题。我们将首先选择它,然后在需要时进一步发展。请告诉我们测量值是多少。

【讨论】:

  • 用于这种计时的类是 System.Diagnostics.Stopwatch.StartNew() 因为它通常比使用 DateTime.Now() 获得更准确的计时
【解决方案2】:

您可能需要在此处考虑许多事项。

如果 GetTransactionByVendorTxCode 占总处理时间的 22%,那么您将需要简化该方法涉及的所有内容,但仍要继续解决整个处理管道中的其他瓶颈。

您说该方法抽象了对 EF6 的调用,并传入了一个谓词表达式,该表达式在 Where 子句中用于构建最终查询。

如果查询很复杂,您是否考虑过委托给 StoredProcedure?由于您要返回一个实体,因此您可以将其挂在 DbSet 之外。 (在 DTO 的情况下,它将挂起 DbContext 的 Database 属性)。

此外,您还需要查看谓词中使用的列的索引。当前的记录数是多少?您的查询是否会导致搜索或扫描?您将需要查看生成的查询计划;如果使用 SQL Server,则运行您的查询数据库引擎优化顾问。

也许有关您当前设置的更多详细信息将有助于提供更好的指导。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-13
    • 2014-07-21
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    相关资源
    最近更新 更多