TL; Сделано рефакторинг производительности, сайт стал медленнее. Отредактируйте анализатор параллелизма, график выглядит как lock convoys, как описано в MSDN.Блокировка конвоев на веб-сайте ASP.NET
Контекст
Я помогаю с рефакторинга веб-узлы ASP.NET для переключения пользовательских элементов управления от выполнения бизнес-логики на наборах данных для выполнения логики представления о бизнес-объектах, а также уменьшить базы данных вызовов, сделанных из пользовательских элементов управления.
Вопрос
Мы заметили существенное падение производительности (зависания/Блокировки) после внесения изменений, связанных с того, что мы думали, что будет повышение производительности в нескольких областях.
Мы используем Lean Sentry для мониторинга производительности наших веб-сайтов. Согласно диагностике зависания, в пуле потоков не было потоков и (в соответствии с описаниями на странице диагностики), когда GC работает, это останавливает создание новых потоков. По данным диагностики памяти, GC Heap и Gen 0 потребляли много памяти (~ 9 ГБ).
Что я сделал до сих пор?
Я использовал профилировщика памяти в Visual Studio и определили проблемы, с нашей чрезмерной
DataAdapter
иDataTable
использования. Потребление памяти упало до 3 ГБ, но это только помогло с блокировкой ГХ. Он все еще медленнее, чем раньше, чем мы вносили изменения, и я все еще вижу блокировку при высокой нагрузке, вызванную такими функциями, какCompilationLock.GetLock()
иBuildManager.GetBuildResultFromCacheInternal()
. Попутать их не принесло ничего полезного.Это сайт, на котором используется компиляция JIT. Я предположил, что проблема с
CompilationLock
может быть из-за компиляции JIT и хотела запустить предварительно скомпилированный сайт, но один из наших глобальных классовUtilities
вызвал неоднозначность с некоторым другим классом/namespaceUtilities
, о котором я не знаю. Я узнал, что есть пространство именMicrosoft.Build.Utilities
, но на нашем сайте оно не упоминается, и я не могу воспроизвести двусмысленность в своей собственной среде, когда я ссылаюсь наMicrosoft.Build
, поэтому я не мог заставить сайт работать в прекомпилированном режиме на промежуточного сервера для проверки этой теории.Я сделал дополнительные изменения в распределении памяти и количестве обращений к базе данных, используя распределение памяти и инструментальные профайлер Visual Studio в в качестве меры, но я не заметил какой-либо прогресса на производительности.
Я использовал профилировщик параллелизма , чтобы собрать дополнительную информацию об использовании потоков. Я раньше не использовал этот инструмент, поэтому я не уверен в своих интерпретациях здесь. В каждом дескрипторе есть несколько потоков, и в одном ручке я вижу конкуренцию в 42%. Я вижу, что методы
DataAdapter.Fill
и отображаются чаще всего, когда он настроен на «Показать только мой код», аWaitForSingleObjectExImplementation
отображается чаще всего, когда он настроен на «Показать весь код».я столкнулся a SO question about ASP.NET websites’ performance issues и установить
EnableSessionState="ReadOnly"
для каждой страницы, но я не заметил разницы с этим изменением, либо.Concurrency Visualizer и Common Patterns for Poorly-Behaved Multithreaded Applications помогли мне определить проблему. Мой график не похож на серийное исполнение, но я вижу синхронизацию 80-90%, как показано на диаграмме Lock Convoys. Я также проверил a SO question on lock convoys debugging.
Тестирование подход
Я использую Кричащие лягушки ползать на сайт для того, чтобы воспроизвести проблемы и принимая число запросов в секунду и время отклика в обоих Кричащие лягушки и Lean Sentry в качестве меры производительности , Это может быть не самый лучший способ, но разница заметна, воспроизводима, и это почти все, что у меня есть на данный момент.
Архитектура сайта
Сайт изначально был закодирован в VB.NET для .NET Framework 1.0 около 10 лет назад, и повышен до .NET Framework 4.6.1, фиксируя некоторые проблемы совместимости. До сих пор никаких архитектурных изменений не было. Существует общий класс SqlHelper
, который представляет собой набор общих функций доступа к данным, таких как ExecuteDataset
или ExecuteDatareader
, которые возвращают либо значение DataSet
, DataReader
, либо String
. Эти функции считывают информацию строки соединения из файла web.config
и создают новые объекты SqlConnection
, SqlDataAdapter
, SqlDataReader
и SqlCommand
для выполнения операций с базой данных. Уровень доступа к данным, который использует этот общий класс, состоит из классов для каждого модуля, такого как корзина покупок, категория, продукт и т. Д., Которые должны быть созданы в каждом пользовательском элементе управления и состоят из функций, которые представляют хранимые процедуры в базе данных.
рефакторинг
Мы ввели некоторые новые объекты будут создаваться, либо внутри странице нагрузка соответствующего пользовательского элемента управления, или в OnItemDataBound
случае ретрансляторах и приложенные к открытым свойствам его дочерних элементы управления пользователя, которые переработаны в используйте объект. Тем не менее, есть еще другие элементы управления дочерними пользователями, которым нужны несколько таблиц данных, поэтому мы решили сохранить одну из таблиц данных в одном из объектов и передать ее связанным пользовательским элементам управления, присвоив ее своим общедоступным свойствам.
Я предполагаю, что мы повредили производительность, представив эти объекты. Несмотря на то, что вызовы базы данных и потребление памяти кажутся сокращенными, мне интересно, все ли объекты постоянно синхронизируются.
График перед любым рефакторинга случилось:
графа после всех рефакторинга я упоминал применяться:
Вы поможете мне определить проблему?
Hi @JohnH. Благодарю за ваш ответ. Я пробовал 1-й подход с 3-мя различными версиями кода, и казалось, что больше объектов мы ввели больше запросов в секунду. Затем я попытался сохранить эти объекты в кеше, чтобы избежать запросов к базе данных, и он не показал никаких улучшений. Затем я решил, что мой подход к тестированию, просматривая запросы в секунду, не помог, так как это напрямую связано с размером страницы, которую я подтвердил, сканируя только страницы с выходным кэшем. Мы развернули код и, похоже, в лучшем состоянии, чем ожидали. – Engin
Я не знаю, как я должен тестировать на этом этапе, за исключением подсчета метрик из профилировщиков. – Engin