Подтвердить что ты не робот

Сообщение SagePay (платежный шлюз), получающее много времени в приложении ASP.Net MVC

Мы испытываем проблемы с производительностью на нашем веб-сайте, связанные с высоким уровнем использования процессора. При использовании профилировщика мы определили конкретный метод, который возвращает ~ 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 - это простой вызов Entity Framework, поэтому я решил это.

Есть ли у кого-нибудь какой-либо опыт в этом или они могут увидеть что-то очень плохое с кодом, который может вызвать такую ​​проблему?

РЕДАКТИРОВАТЬ. Рассматривая таблицу разбивки, предоставленную профилировщиком, говорится, что 99,6% времени тратится на System.Web.Mvc.MvcHandler.BeginProcessRequest().

EDIT: Используя инструмент профилирования New Relic, он говорит, что 22% всего времени обработки расходуется в методе this.sagePayTransactionManager.GetTransactionByVendorTxCode(vendorTxCode). Это просто содержит вызов EF6 в репозиторий. Вызов содержит предикатный параметр, а не предопределенное условие. Может быть, запрос не компилируется?

4b9b3361

Ответ 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();

Отправьте информацию нам, и я расскажу вам о следующем шаге. То, что мы делаем выше, - это получение показателей, которые будут охватывать как локальный, так и удаленный доступ, чтобы найти основную проблему. Сначала мы выберем это, а затем, если потребуется, продвинемся дальше. Просто сообщите нам, что такое измерения.

Ответ 2

Есть несколько вещей, которые вам, возможно, придется рассмотреть здесь.

Если GetTransactionByVendorTxCode отвечает за 22% от общего времени обработки, вам нужно будет оптимизировать все, что касается этого метода, но затем по-прежнему продолжать ловить другие узкие места в общем конвейере обработки.

Вы говорите, что метод абстрагирует вызов EF6 и передает его в предикатное выражение, которое используется в предложении Where для создания окончательного запроса.

Если запрос является сложным, считаете ли вы делегирование StoredProcedure? Поскольку вы возвращаете Entity, вы можете отключить его от DbSet. (В случае DTO он отключит свойство базы данных DbContext).

Кроме того, вам нужно будет посмотреть индексы столбцов, используемых в вашем предикате. Каков текущий показатель записи? Являются ли ваши запросы результатом поиска или сканирования? Вам нужно будет просмотреть результирующие планы запросов; если вы используете SQL Server, запустите свои запросы. Советник по настройке ядра базы данных.

Возможно, более подробная информация о вашей текущей настройке поможет в обеспечении лучшего руководства.