10 лучших способов улучшить производительность приложений ASP.Net
Автор:Eve Cole
Время обновления:2009-06-30 15:49:49
В этой статье обсуждаются:
Распространенные мифы об улучшении производительности приложений asp.net. Полезные советы по повышению производительности приложений asp.net.
Рекомендации по работе баз данных с приложениями Asp.net
Кэширование и фоновая обработка в Asp.net
В настоящее время написание веб-приложения ASP.NET стало очень простым, и многие программисты не желают тратить время на создание приложения с хорошей производительностью. В этой статье будут обсуждаться десять основных способов повышения производительности веб-приложений. Я не буду ограничивать свое обсуждение только приложениями ASP.NET, поскольку они представляют собой лишь подмножество веб-приложений. Эта статья также не может предоставить полное руководство по повышению производительности веб-приложений, поскольку для этого потребуется объем книги. Эта статья представляет собой лишь хорошую отправную точку для повышения производительности веб-приложений. (Осталось только потихоньку учиться самим).
Вне работы я часто занимаюсь скалолазанием. Перед каждым восхождением я просматриваю карту маршрута скалолазания и читаю советы предыдущих успешных скалолазов. Потому что нам нужен их успешный опыт. Точно так же, когда вам нужно изменить программу с проблемами производительности или разработать высокопроизводительный веб-сайт, вам также необходимо научиться писать высокопроизводительное веб-приложение.
Мой личный опыт в основном связан с работой менеджером программы в группе Microsoft asp.net, запуском и управлением веб-сайтом www.asp.net , а также оказанием помощи в разработке Сервера совместной работы (который представляет собой интегрированную и обновленную версию форумов asp.net). , .Text и программное обеспечение nGallery). Я думаю, что этот опыт может мне помочь.
Вы можете подумать о разделении вашего приложения на разные логические уровни. Возможно, вы также слышали о трехуровневой физической архитектуре или N-уровневой архитектуре, которая является наиболее часто используемой моделью архитектуры. Она физически назначает различные программные функции различным аппаратным средствам для выполнения. Таким образом, если мы хотим повысить производительность приложения, добавление некоторого оборудования может достичь цели. Само собой разумеется, что этот метод может улучшить производительность приложения, но нам следует избегать его использования. Поэтому, когда это возможно, мы должны помещать страницу ASP.NET и используемые ею компоненты в приложение.
Из-за распределенного развертывания и использования веб-сервисов или удаленного взаимодействия производительность приложения снизится на 20 % и более.
Уровень данных немного отличается. Лучше развернуть его независимо и использовать для его запуска отдельное оборудование. Несмотря на это, база данных по-прежнему остается узким местом производительности приложений. Поэтому, когда вы хотите оптимизировать свою программу, первое, что приходит на ум, — это оптимизация уровня данных.
Прежде чем изменять область вашего приложения, вызывающую проблемы с производительностью, вам необходимо убедиться, что программа, вызывающая проблему, выглядит тщательно. Профилировщики производительности очень полезны для определения того, где в вашем приложении это занимает какое-то время. Это места, которые мы не можем почувствовать интуитивно.
В этой статье обсуждаются два типа оптимизации производительности: одна — большая оптимизация производительности (большая оптимизация), например использование кэша asp.net, другая — небольшая оптимизация производительности (крошечная оптимизация); Небольшая оптимизация производительности иногда может быть очень полезной. Вы вносите небольшое изменение в свой код и вызываете его тысячу или десять тысяч раз за раз. Сделайте большую оптимизацию производительности, и вы увидите значительное улучшение скорости вашего приложения. Небольшая оптимизация производительности может повысить производительность всего на одну микросекунду на каждый запрос, но если количество запросов в день велико, производительность приложения значительно увеличится.
Производительность уровня данных
Если вы хотите оптимизировать производительность приложения, вы можете действовать в следующем порядке: Нужен ли вашему коду доступ к базе данных? Если да, то как часто следует обращаться к базе данных? Аналогично, этот метод тестирования также можно использовать в программном коде, использующем веб-сервисы или удаленное взаимодействие. В этой статье не будет обсуждаться вопрос оптимизации программ с использованием веб-сервисов и удаленного взаимодействия.
Если в вашем коде есть запрос, который должен получить доступ к базе данных, и вы видите код, реализующий ту же функцию где-то еще, то вам необходимо сначала его оптимизировать. Изменяйте, улучшайте и продолжайте тестирование. Если у вас нет очень серьезных проблем с производительностью, лучше потратить время на оптимизацию запросов, подключение к базе данных, возврат размера набора данных и время, необходимое для возврата запроса.
Основываясь на обобщении опыта, давайте рассмотрим десять вариантов, которые помогут вам улучшить производительность вашего приложения. Я объясню их в порядке от самого большого к самому маленькому с точки зрения того, насколько они повышают эффективность.
1. Возврат нескольких наборов данных
Проверьте код доступа к базе данных, чтобы узнать, есть ли запросы, которые возвращаются несколько раз. Каждый цикл обработки уменьшает количество запросов в секунду, на которые может ответить ваше приложение. Возвращая несколько наборов результатов в одном запросе к базе данных, вы сокращаете время, необходимое для взаимодействия с базой данных, делаете вашу систему масштабируемой и снижаете рабочую нагрузку на сервер базы данных для ответа на запросы.
Если вы используете операторы динамического SQL для возврата нескольких наборов данных, я рекомендую вам использовать хранимые процедуры вместо операторов динамического SQL. Вопрос о том, следует ли записывать бизнес-логику в хранимые процедуры, является несколько спорным. Но я думаю, что запись бизнес-логики в хранимые процедуры может ограничить размер возвращаемого набора результатов, уменьшить сетевой трафик данных и устранить необходимость фильтрации данных на логическом уровне. Это хорошо.
Используйте метод ExecuteReader объекта SqlCommand, чтобы вернуть строго типизированный бизнес-объект, а затем вызовите метод NextResult, чтобы переместить указатель набора данных и найти набор данных. В примере 1 показан пример возврата нескольких строго типизированных объектов ArrayList. Возвращение из базы данных только тех данных, которые вам нужны, может значительно снизить потребление памяти вашего сервера.
2. Пейджинг данных
АСП. NET DataGrid имеет очень полезную функцию: разбиение на страницы. Если DataGrid разрешает разбиение по страницам, он будет загружать данные только определенной страницы в определенное время. Кроме того, он имеет панель навигации для разбиения по страницам, которая позволяет вам просматривать определенную страницу и загружать только одну страницу. данные за раз.
Но у него есть небольшой недостаток, то есть необходимо привязывать все данные к DataGrid. Другими словами, ваш уровень данных должен вернуть все данные, а затем DataGrid отфильтровывает данные, необходимые текущей странице, и отображает их. Если имеется набор результатов из 10 000 записей, которые необходимо разбить на страницы с помощью DataGrid, при условии, что DataGrid отображает только 25 фрагментов данных на странице, это означает, что 9975 фрагментов данных будут отброшены в каждом запросе. Каждый запрос должен возвращать такой большой набор данных, что оказывает огромное влияние на производительность приложения.
Хорошим решением является написание хранимой процедуры подкачки. Пример 2 — это хранимая процедура подкачки для таблицы заказов базы данных Northwind. Вам нужно только передать номер текущей страницы и количество элементов, отображаемых на каждой странице, и хранимая процедура вернет соответствующие результаты.
На стороне сервера я специально написал элемент управления подкачкой для управления подкачкой данных. Здесь я использовал первый метод и вернул в хранимой процедуре два набора результатов: общее количество записей данных и требуемый набор результатов.
Общее количество возвращаемых записей зависит от выполняемого запроса, например, условиеwhere может ограничить размер возвращаемого набора результатов; Поскольку общее количество страниц должно рассчитываться на основе размера записей набора данных в интерфейсе разбиения на страницы, необходимо вернуть количество записей в результирующем наборе. Например, если всего имеется 1 000 000 записей, если вы используете условиеwhere, вы можете отфильтровать только 1000 записей. Логика подкачки хранимой процедуры должна знать, что нужно возвращать данные, которые необходимо отобразить.
3. Пул соединений
Использование TCP для подключения вашего приложения к базе данных является дорогостоящим (и отнимает много времени). Разработчики Microsoft могут использовать пулы соединений для повторного использования подключений к базе данных. Вместо использования TCP для подключения к базе данных для каждого запроса пул соединений создает новое TCP-соединение только при отсутствии действительного соединения. Когда соединение закрывается, оно помещается в пул и продолжает поддерживать соединение с базой данных, тем самым уменьшая количество TCP-соединений с базой данных.
Конечно, следует обратить внимание на те соединения, которые вы забыли закрыть. Закрывать их следует сразу после каждого использования. Я хочу подчеркнуть следующее: что бы кто ни говорил, GC (сборщик мусора) в .net framework всегда будет вызывать метод Close или Dispose объекта соединения, чтобы явно закрыть ваше соединение после того, как вы закончите использовать объект соединения. Не ждите, что CLR закроет соединение за то время, которое вы себе представляете. Хотя CLR в конечном итоге уничтожит объект и закроет соединение, мы не уверены, когда она это сделает.
Чтобы использовать оптимизацию пула соединений, существует два правила: сначала откройте соединение, обработайте данные, а затем закройте соединение. Если вам приходится открывать или закрывать соединение несколько раз за запрос, это лучше, чем постоянно открывать стороннее соединение и передавать его каждому методу. Во-вторых, используйте ту же строку подключения (или тот же идентификатор пользователя, если вы используете встроенную аутентификацию). Если вы не используете ту же строку подключения, например, если вы используете строку подключения на основе вошедшего в систему пользователя, это не позволит воспользоваться преимуществами оптимизации пула соединений. Если вы используете интегрированные аргументы, вы не сможете в полной мере воспользоваться функцией оптимизации пула соединений, поскольку имеется много пользователей. .NET CLR предоставляет счетчик производительности данных, который очень полезен, когда нам нужно отслеживать характеристики производительности программы, включая отслеживание пула соединений.
Всякий раз, когда ваше приложение подключается к ресурсу на другом компьютере, например к базе данных, вам следует сосредоточиться на оптимизации времени, необходимого вам для подключения к ресурсу, времени, необходимого для получения и отправки данных, а также количества раз, когда вы возвращаетесь к нему. . Оптимизация каждого перехода процесса в вашем приложении — это отправная точка для повышения производительности вашего приложения.
Уровень приложения содержит логику для подключения к уровню данных, передачи данных в экземпляры соответствующих классов и бизнес-обработки. Например, в Сервере совместной работы вам необходимо собрать коллекцию Форумов или Тем, а затем применить бизнес-логику, например авторизацию. Что еще более важно, здесь необходимо доработать логику кэширования.
4. АСП. API NET-кэша
Прежде чем писать приложение, первое, что вам нужно сделать, — это заставить приложение максимально использовать возможности кэширования ASP.NET.
Если ваш компонент будет запускаться в приложении Asp.net, вам нужно будет только сослаться на System.Web.dll в свой проект. Затем используйте свойство HttpRuntime.Cache для доступа к кешу (доступ к нему также можно получить через Page.Cache или HttpContext.Cache).
Существует несколько правил кэширования данных. Во-первых, данные могут использоваться часто, и эти данные можно кэшировать. Во-вторых, частота доступа к данным очень высока или частота доступа к фрагменту данных невысока, но его жизненный цикл очень длинный. Лучше всего кэшировать такие данные. Третья проблема, которую часто игнорируют. Иногда мы кэшируем слишком много данных. Обычно на машине X86, если объем данных, которые вы хотите кэшировать, превышает 800 МБ, возникает ошибка переполнения памяти. Таким образом, кэш ограничен. Другими словами, вам следует оценить размер набора кэша и ограничить размер набора кэша менее 10, иначе это может вызвать проблемы. В Asp.net, если кэш слишком велик, будет сообщено об ошибке переполнения памяти, особенно если кэшируется большой объект DataSet.
Вот несколько важных механизмов кэширования, которые вы должны понимать. Во-первых, в кеше реализован принцип «последнего использования» (алгоритм «наименее недавно использованного»). Когда кешей мало, он автоматически принудительно очищает ненужные кеши. Во-вторых, принцип принудительного устранения «условных зависимостей» (зависимостей по истечении срока действия), условиями могут быть время, ключевые слова и файлы. Время как условие используется чаще всего. В asp.net2.0 добавлено более строгое условие, которое является условием базы данных. При изменении данных в базе данных кэш принудительно очищается. Более подробный обзор условных зависимостей базы данных см. в колонке Дино Эспозито «Передовой край» в июльском выпуске журнала MSDN Magazine за 2004 год. Архитектура кэша Asp.net показана на рисунке ниже:
5. Кеширование предварительного запроса
Ранее я упоминал, что даже если мы лишь немного улучшим производительность в некоторых местах, мы можем получить значительное улучшение производительности. Мне очень нравится использовать кэширование предварительного запроса для повышения производительности программы.
Хотя Cache API предназначен для сохранения данных в течение определенного периода времени, кеш предварительного запроса сохраняет содержимое определенного запроса только в течение определенного периода времени. Если частота доступа к определенному запросу высока, и этому запросу необходимо извлечь, применить, изменить или обновить данные только один раз. Тогда запрос можно предварительно кэшировать. Приведем пример для иллюстрации.
В приложении форума CS для серверного управления каждой страницей требуются настроенные данные для определения ее скина, определения того, какую таблицу стилей использовать, и других персонализированных вещей. Некоторые данные здесь, возможно, потребуется сохранить в течение длительного времени, а некоторые — нет. Например, данные скина элемента управления необходимо применить только один раз, и их можно использовать постоянно.
Чтобы реализовать кэширование предварительного запроса, используйте класс HttpContext Asp.net. Экземпляр класса HttpContext создается при каждом запросе, и доступ к нему можно получить через свойство HttpContext.Current в любом месте во время запроса. Класс HttpContext имеет свойство коллекции Items, и все объекты и данные добавляются в эту коллекцию и кэшируются во время запроса. Точно так же, как вы используете Cache для кэширования часто используемых данных, вы можете использовать HttpContext.Items для кэширования основных данных, которые используются в каждом запросе. Логика проста: мы добавляем данные в HttpContext.Items, а затем читаем из них данные.
6. Фоновая обработка
При использовании описанного выше метода ваше приложение должно работать очень быстро, верно? Но в какой-то момент в запросе в программе может быть выполнена очень трудоемкая задача. Например, отправка электронных писем или проверка правильности отправленных данных и т. д.
Когда мы интегрировали форумы asp.net 1.0 в CS, мы обнаружили, что отправка нового сообщения будет происходить очень медленно. Каждый раз, когда добавляется новое сообщение, приложение должно сначала проверить, является ли сообщение дубликатом, затем отфильтровать его с помощью фильтра «недопустимых слов», проверить код вложения изображения, проиндексировать сообщение и добавить его в соответствующую очередь, провести проверку. его вложение и, наконец, отправьте электронное письмо в почтовый ящик подписчика. Очевидно, это большой труд.
В результате он тратит много времени на индексацию и отправку электронных писем. Индексирование сообщений — трудоемкая операция, а отправка электронных писем подписчикам требует подключения к службе SMTP и последующей отправки электронного письма каждому подписчику. По мере увеличения количества подписчиков время, необходимое для отправки электронных писем, будет увеличиваться.
Индексирование и отправка электронных писем не обязательно должны запускаться при каждом запросе. В идеале мы хотели бы обрабатывать эти операции пакетно, отправляя только 25 электронных писем за раз или все новые электронные письма будут отправляться каждые 5 минут. Мы решили использовать тот же код, что и для кэша прототипов базы данных, но это не удалось, поэтому нам пришлось вернуться к VS.NET 2005.
Мы находим класс Timer в пространстве имен System.Threading. Этот класс очень полезен, но о нем знают немногие, и еще меньше веб-разработчиков. Как только он создаст экземпляр этого класса, класс Timer будет вызывать указанную функцию обратного вызова из потока в пуле потоков каждый указанный раз. Это означает, что ваше приложение ASP.NET может работать даже при отсутствии запросов. Это решение, с которым мы разберемся позже. Вы можете запустить работу по индексированию и отправке по электронной почте в фоновом режиме вместо того, чтобы выполнять ее при каждом запросе.
Есть две проблемы с технологией фонового запуска. Первая заключается в том, что при удалении домена приложения экземпляр класса Timer перестает работать. То есть метод обратного вызова вызываться не будет. Кроме того, поскольку в каждом процессе CLR выполняется множество потоков, вам будет сложно получить поток для выполнения Timer, либо он сможет его выполнить, но будет с задержкой. Уровень Asp.net должен использовать этот метод как можно реже, чтобы уменьшить количество потоков в процессе, или разрешить запросам использовать только небольшую часть потоков. Конечно, использовать его можно только в том случае, если у вас много асинхронной работы.
Недостаточно места для размещения кода. Вы можете загрузить образец программы с http://www.rob-howard.net/ . Загрузите образец программы Blackbelt TechEd 2004.
7. Кэширование вывода страниц и прокси-сервисы.
Asp.net — это ваш уровень интерфейса (или должен им быть), он содержит страницы, пользовательские элементы управления, серверные элементы управления (HttpHandlers и HttpModules) и контент, который они генерируют. Если у вас есть страница Asp.net, которая выводит html, xml, imgae или другие данные, и вы используете код для генерации одного и того же выходного содержимого для каждого запроса, вам необходимо рассмотреть возможность использования кэширования вывода страницы.
Вы можете сделать это, просто скопировав на свою страницу следующую строку кода:
<%@ PageOutputCache VaryByParams="none" Duration="60" %>
Вы можете эффективно использовать страницу, созданную в первом запросе, для вывода кэшированного содержимого и повторно создать содержимое страницы через 60 секунд. Эта технология фактически реализована с использованием некоторого низкоуровневого API кэша. Существует несколько параметров, которые можно настроить для кэширования вывода страницы, например параметр VaryByParams, упомянутый выше. Этот параметр указывает, когда запускать условия повторного вывода. Вы также можете указать кэширование вывода в режиме запроса Http Get или Http Post. Например, если мы установим для этого параметра значение VaryByParams="Report", выходные данные, запрошенные default.aspx?Report=1 или default.aspx?Report=2, будут кэшироваться. Значением параметра может быть несколько параметров, разделенных точкой с запятой.
Многие люди не осознают, что при использовании кэширования вывода страницы ASP.NET также генерирует набор заголовков HTTP (HTTP-заголовок) и сохраняет его на нижестоящем сервере кэширования. Эта информация может использоваться для обеспечения безопасности Интернета Microsoft и для ускорения работы. скорость ответа сервера. Когда заголовок кэша HTTP сбрасывается, запрошенный контент будет кэшироваться в сетевом ресурсе. Когда клиент снова запрашивает контент, он больше не будет получать контент с исходного сервера, а будет получать контент напрямую из кэша.
Хотя использование кэширования вывода страниц не повышает производительность вашего приложения, оно уменьшает количество загрузок кэшированного содержимого страницы с сервера. Конечно, это ограничивается кэшированием страниц, доступных анонимным пользователям. Потому что как только страница кэшируется, операции авторизации больше не могут быть выполнены.
8. Используйте кэширование ядра IIS6.0.
Если ваше приложение не работает в IIS 6.0 (Windows Server 2003), вы потеряли несколько отличных способов повышения производительности приложения. В седьмом методе я рассказал о том, как использовать кэширование вывода страниц для повышения производительности приложений. В IIS5.0, когда запрос поступает в IIS, IIS передает его в asp.net. При применении кэша вывода страницы HttpHandler в ASP.NET получит запрос, а HttpHandler передаст содержимое из кэша. .Вынь и верни.
Если вы используете IIS6.0, у него есть очень хорошая функция под названием «Кэширование ядра», и вам не нужно изменять какой-либо код в программе asp.net. Когда asp.net получает кэшированный запрос, кэш ядра IIS получит его копию из кэша. Когда запрос поступает из сети, уровень ядра получит запрос. Если запрос кэширован, он напрямую вернет кэшированные данные, и все готово. Это означает, что при использовании кэширования ядра IIS для кэширования вывода страницы вы получите невероятный прирост производительности. При разработке asp.net для VS.NET 2005 я был менеджером программы, ответственным за производительность asp.net. Мои программисты использовали этот метод. Я просматривал все данные ежедневных отчетов и обнаружил результаты использования кэширования модели ядра. самый быстрый. Их общей особенностью является то, что сетевые запросы и ответы большие, но IIS занимает всего 5% ресурсов ЦП. Это потрясающе. Существует множество причин использовать IIS 6.0, но кэширование ядра — лучшая из них.
9. Сжатие данных с помощью Gzip
Если загрузка вашего процессора не слишком высока, необходимо использовать методы повышения производительности сервера. Использование gzip для сжатия данных может уменьшить объем данных, отправляемых на сервер, повысить скорость работы страницы, а также снизить сетевой трафик. Как лучше сжать данные, зависит от данных, которые вы хотите отправить, и от того, поддерживает ли их браузер клиента (IIS отправляет клиенту данные, сжатые с помощью gzip, и клиент должен поддерживать gzip для их анализа, IE6.0 и Firefox). Таким образом, ваш сервер может отвечать на большее количество запросов в секунду. Аналогичным образом вы также уменьшаете объем данных, отправляемых в ответе, и можете отправлять больше запросов.
Хорошие новости: в IIS6.0 интегрировано сжатие gzip, оно лучше, чем gzip в IIS5.0. К сожалению, чтобы включить сжатие gzip в IIS 6.0, вы не можете установить его в диалоговом окне свойств IIS 6.0. Команда разработчиков IIS разработала функцию сжатия gzip, но забыла облегчить администраторам возможность включения ее в окне администратора. Чтобы включить сжатие gzip, вы можете изменить его конфигурацию только в XML-файле конфигурации IIS6.0.
Помимо чтения этой статьи, мне нужно прочитать статью <<Сжатие IIS6>>, написанную Брэдом Уилсоном ( http://www.dotnetdevs.com/articles/IIS6compression.aspx ), там также есть статья, знакомящая с базовыми знаниями; сжатия aspx Включите сжатие ASPX в IIS. Но имейте в виду, что динамическое сжатие и кэширование ядра в IIS6 являются взаимоисключающими.
10. ViewState серверных элементов управления
ViewState — это функция asp.net, которая используется для сохранения значения состояния, используемого для создания страницы, в скрытом поле. Когда страница отправляется обратно на сервер, сервер анализирует, проверяет и применяет данные в ViewState для восстановления дерева управления страницей. ViewState — очень полезная функция, которая позволяет сохранять состояние клиента без использования файлов cookie или памяти сервера. Большинство серверных элементов управления используют ViewState для сохранения значений состояния элементов, которые взаимодействуют с пользователем на странице. Например, чтобы сохранить номер текущей страницы для перелистывания.
Использование ViewState приведет к некоторым негативным последствиям. Во-первых, это увеличивает время ответа и запроса сервера. Во-вторых, каждая обратная передача добавляет время на сериализацию и десериализацию данных. Наконец, он также потребляет больше памяти на сервере.
Многие серверные элементы управления, как правило, используют ViewState, например хорошо известный DataGrid, и иногда в его использовании нет необходимости. ViewState включен по умолчанию. Если вы не хотите использовать ViewState, вы можете отключить его на уровне элемента управления или страницы. В элементе управления вам нужно только установить для свойства EnableViewState значение False. Вы также можете установить его на странице, чтобы распространить его область действия на всю страницу:
<%@ Page EnableViewState="false" %>
Если страница не требует обратной передачи или страница просто отображается с элементами управления каждый раз, когда ее запрашивают. Вам следует отключить ViewState на уровне страницы.
Подвести итог
Я просто даю несколько советов, которые, по моему мнению, помогут улучшить написание высокопроизводительных приложений ASP.NET. Советы по повышению производительности ASP.NET, упомянутые в этой статье, являются лишь отправной точкой. NET «Перформанс». Книга. Только благодаря собственной практике вы сможете найти методы, которые будут наиболее полезны для вашего проекта. Однако эти советы могут послужить руководством на вашем пути развития. В разработке программного обеспечения ни один из них не является абсолютно полезным, поскольку каждый проект индивидуален.