Asp полезные советы по оптимизации asp приложений


Содержание

Оптимизация приложений ASP.NET. Приложения для iPhone и Android для приложений ASP.NET.

У меня есть приложение ASP.NET(не MVC).

Я хотел бы создать версию, оптимизированную для браузеров на IPhone и на Android.

  • Возможно ли обнаружение IPhone/Android при доступе к сайту.
  • Есть ли какие-либо проблемы/советы по разработке ASP.NET для этих устройств.

Мы используем комбинацию .net webforms и jQuery mobile.

Для нашего viewstate это было довольно хорошо стерилизовано, так что только незначительные вещи идут к устройству.

Имейте в виду, что существует около 3 различных мобильных api. Каждый из них имеет свои недостатки. Вы можете изучить их.

Кроме того, мы приняли подход к тому, что мобильный сайт был совершенно другим сайтом, чем наш стандартный. Когда пользователь приходит, мы делаем некоторые нюансы браузера и нажимаем их на мобильный, если он соответствует ссылке, чтобы вернуться к полной, если они захотят.

Webforms не подходит для мобильных устройств, он генерирует большие страницы, потому что viewstate. И вы не можете управлять рендерингом (еще немного .net4).

Вы можете обнаружить устройство, используя db возможностей, таких как WURFL (я рекомендую 51degrees) o возможно, используя некоторые, например http://detectmobilebrowser.com/

Я не знаю, что такое webapp, но вы можете создать новое приложение, возможно, используя MVC. Посмотрите этот ресурс.

замечания по поводу «25 советов по оптимизации. «

18.11.2007, 00:13

Как «Истина»/»Ложь» переделать в «True»/»False»?
собснно сабж. есть w2000 server. русский IE. где-то в скрипте на сервере (VB) выдает CStr(True) =.

Ошибка после конвертации метода на С++ к С#: «Неявное преобразование типа «int» в «bool» невозможно»
Ошибка после преобразования метода на С++ к С#: «Неявное преобразование типа «int» в «bool».

Ошибка CS0019: Оператор «*» не может применяться к операндам типа «decimal» и «float»
Здравствуйте! Писал приложение и наткнулся на интересную ошибку (честно говоря, я не совсем понимаю.

Переопределить операции «+» «=» «-» для экземпляров моего класса
Добрый день. Мне нужно переопределить операции «+» «=» «-» для экземпляров моего класса. Я вижу это.

Оптимизация ASP.NET приложений

Стоимость семинара — 10,000 рублей с человека.

Платить 10 косарей для того, чтобы поприсутствовать на бреднях Стасика? Это просто эпик фэйл!

Средние школы закрыть, учителей уволить. Они ведь прописным истинам учат. Так?

МСУ, hVosttСредние школы закрыть, учителей уволить. Они ведь прописным истинам учат. Так?

Какие средние школы, бро? Тут уровень ниже продлёнки

Эй люди, кто-то на такие смешные мероприятия ходит??

МСУ, hVosttСредние школы закрыть, учителей уволить. Они ведь прописным истинам учат. Так?

30 октября состоится «Пятая технологическая конференция Яндекса», так что Стасян в пролёте. :)

31 октября и 1 ноября HighLoad++Вот там есть чему поучиться :)

Это скорее место для знакомств. Считаю, компании должны отправлять своих перспективных сотрудников на такие тусовки.

А вообще было бы неплохо цикл статей от местных гуру увидеть.

Зря шумите. Во-первых, gandjustas не так уж плох, как может показаться по вашим замечаниям.

По WPF, WCF и EF уже есть. :-)зы: по Asp.Net и JS, надеюсь, в следующем году добавятся.

А вообще было бы неплохо цикл статей от местных гуру увидеть. Или скомпилированные статьи по темам, с учетом замечаний и правок остальных участников.

МСУ тоже может, но почему-то свой дар красноречия растрачивает на форумных троллей. Нет, чтобы на основе своего codearticles написать ряд статей.

Кто программирует, у того нет времени этим всем заниматься.

Кто программирует, у того нет времени этим всем заниматься.

Есть еще более важный аргумент, по сути мы здесь все конкуренты и инфа наш хлеб. Вылаживать действительно передовые, эффективные подходы никто не хочет, что логично. Есть так же NDA.

Я не умею преподавать и никогда не имел преподавательских способностей. Нужно иметь эти способности, тогда будет толк. Как блогера я себя тоже не вижу, тем более это занимает очень много времени. Если хочешь реально качество и смысл. А следовательно нужна внятная материальная составляющая.

Что-то применил, что-то узнал, что-то написал — просто скопировал рецептик, чтобы в следующий раз заново не городить лисапед, когда всё забудешь.

Так что я лучше тут потроллю, как ты выразился :)

Советы по ускорению работы веб-приложения asp.net

Что мы можем сделать, чтобы веб-приложение asp.net работало быстрее, чем раньше. Что для этого нужно настроить?

5 ответов

Чтобы ускорить работу любого приложения, сначала выясните, на что оно тратит время, а затем заставьте его проводить меньше времени. Используйте профилировщик.

Профилировщик упрощает процесс разбиения приложения на более мелкие части, а затем ускоряет работу отдельных частей. Вы можете сделать это самостоятельно, если не можете позволить себе профилировщик.

Например, вы говорите, что ваше среднее время ответа составляет 4-5 секунд. Это долго. Что происходит в эти 5 секунд? Это все ждет базы данных? Вы можете попробовать выполнить свои запросы вне приложения, чтобы узнать, сколько времени они занимают. Вы можете запустить SQL Server Profiler для записи транзакций базы данных в течение определенного периода времени, а затем запустить результат с помощью мастера настройки базы данных. Может быть несколько рекомендаций по изменению индексов базы данных.

Вы можете использовать Fiddler или включить трассировку страниц, чтобы выяснить, слишком ли велики ваши страницы. Трассировка может сказать вам, сколько времени занимает выполнение определенных этапов работы с страницей. Может быть, вы занимаетесь много времени, чтобы сделать определенные страницы.

Также вам нужно посмотреть на производительность вашего сервера. Вы используете слишком много процессора? Слишком много памяти? Вы тратите свое время на перебивание страниц, выбивая страницы рабочего процесса ASP.NET из памяти, чтобы перенести страницы SQL Server, только чтобы эти страницы были выбиты, когда запрос к базе данных завершен и рабочий процесс нуждается снова бежать?

Разбейте проблему на более мелкие части, затем исправьте их.

Рекомендации по повышению производительности ASP.NET Core ASP.NET Core Performance Best Practices

В этой статье приводятся рекомендации по обеспечению оптимальной производительности с помощью ASP.NET Core. This article provides guidelines for performance best practices with ASP.NET Core.


Агрессивный кэш Cache aggressively

Кэширование рассматривается в нескольких частях этого документа. Caching is discussed in several parts of this document. Для получения дополнительной информации см. Кэширование ответов в ASP.NET Core. For more information, see Кэширование ответов в ASP.NET Core.

Общие сведения о путях к горячему коду Understand hot code paths

В этом документе путь к горячему коду определяется как часто называемый путь к коду и где возникает большая часть времени выполнения. In this document, a hot code path is defined as a code path that is frequently called and where much of the execution time occurs. Пути с горячим кодом обычно ограничивают масштаб и производительность приложения и обсуждаются в нескольких частях этого документа. Hot code paths typically limit app scale-out and performance and are discussed in several parts of this document.

Избегайте блокирующих вызовов Avoid blocking calls

ASP.NET Core приложения предназначены для одновременной обработки нескольких запросов. ASP.NET Core apps should be designed to process many requests simultaneously. Асинхронные интерфейсы API позволяют небольшому пулу потоков работать с тысячами одновременных запросов, не дожидаясь блокировки вызовов. Asynchronous APIs allow a small pool of threads to handle thousands of concurrent requests by not waiting on blocking calls. Вместо ожидания завершения длительной синхронной задачи поток может работать с другим запросом. Rather than waiting on a long-running synchronous task to complete, the thread can work on another request.

Распространенная проблема производительности в ASP.NET Core приложениях — блокировка вызовов, которые могут быть асинхронными. A common performance problem in ASP.NET Core apps is blocking calls that could be asynchronous. Многие синхронные блокирующие вызовы ведут к нехватке пула потоков и снижению времени отклика. Many synchronous blocking calls lead to Thread Pool starvation and degraded response times.

Не выполнять: Do not:

  • Блокировать асинхронное выполнение путем вызова Task. Wait или Task. Result. Block asynchronous execution by calling Task.Wait or Task.Result.
  • Получение блокировок в общих путях кода. Acquire locks in common code paths. ASP.NET Core приложения являются наиболее производительными при разработке архитектуры для параллельного выполнения кода. ASP.NET Core apps are most performant when architected to run code in parallel.

Выполнитеследующие действия. Do:

  • Сделайте неактивные пути к коду асинхронными. Make hot code paths asynchronous.
  • Асинхронный вызов API-интерфейсов доступа к данным и долгосрочных операций. Call data access and long-running operations APIs asynchronously.
  • Выполнение асинхронных действий контроллера/Razor Page. Make controller/Razor Page actions asynchronous. Весь стек вызовов является асинхронным, чтобы воспользоваться преимуществами шаблонов async/await . The entire call stack is asynchronous in order to benefit from async/await patterns.

Профилировщик, например PerfView, можно использовать для поиска потоков, часто добавляемых в пул потоков. A profiler, such as PerfView, can be used to find threads frequently added to the Thread Pool. Событие Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start указывает поток, добавленный в пул потоков. The Microsoft-Windows-DotNETRuntime/ThreadPoolWorkerThread/Start event indicates a thread added to the thread pool.

Сведение к минимальному выделению больших объектов Minimize large object allocations

Сборщик мусора .NET Core управляет выделением и освобождением памяти автоматически в ASP.NET Core приложениях. The .NET Core garbage collector manages allocation and release of memory automatically in ASP.NET Core apps. Автоматическая сборка мусора обычно означает, что разработчикам не нужно беспокоиться о том, как или когда освобождается память. Automatic garbage collection generally means that developers don’t need to worry about how or when memory is freed. Тем не менее очистка объектов, на которые нет ссылок, занимает время ЦП, поэтому разработчики должны максимально сокращать выделение объектов в путях горячего кода. However, cleaning up unreferenced objects takes CPU time, so developers should minimize allocating objects in hot code paths. Сборка мусора особенно затратна на большие объекты (> 85 КБайт). Garbage collection is especially expensive on large objects (> 85 K bytes). Большие объекты хранятся в куче больших объектов и для очистки требуется полная сборка мусора (поколение 2). Large objects are stored on the large object heap and require a full (generation 2) garbage collection to clean up. В отличие от коллекций поколений 0 и поколения 1, сборка поколения 2 требует временной приостановки выполнения приложения. Unlike generation 0 and generation 1 collections, a generation 2 collection requires a temporary suspension of app execution. Частое выделение и освобождение больших объектов могут привести к нестабильной производительности. Frequent allocation and de-allocation of large objects can cause inconsistent performance.

  • Рассмотрите возможность кэширования больших объектов, которые часто используются. Do consider caching large objects that are frequently used. Кэширование больших объектов предотвращает дорогостоящее выделение памяти. Caching large objects prevents expensive allocations.
  • Сделайте буферы пула, используя ArrayPool для хранения больших массивов. Do pool buffers by using an ArrayPool to store large arrays.
  • Не выделяйте большое количество кратковременных больших объектов в пути горячего кода. Do not allocate many, short-lived large objects on hot code paths.

Проблемы с памятью, например предшествующие, можно диагностировать путем просмотра статистики сборщика мусора (GC) в PerfView и изучения: Memory issues, such as the preceding, can be diagnosed by reviewing garbage collection (GC) stats in PerfView and examining:

  • Время остановки сборки мусора. Garbage collection pause time.
  • Процент времени процессора, затраченный на сборку мусора. What percentage of the processor time is spent in garbage collection.
  • Количество сборок мусора, которые являются поколением 0, 1 и 2. How many garbage collections are generation 0, 1, and 2.

Дополнительные сведения см. в разделе сбор мусора и производительность. For more information, see Garbage Collection and Performance.

Оптимизация доступа к данным Optimize Data Access

Взаимодействие с хранилищем данных и другими удаленными службами часто является наиболее медленной частью ASP.NET Core приложения. Interactions with a data store and other remote services are often the slowest parts of an ASP.NET Core app. Эффективное чтение и запись данных крайне важно для обеспечения высокой производительности. Reading and writing data efficiently is critical for good performance.

  • Вызывайте все API доступа к данным в асинхронном режиме. Do call all data access APIs asynchronously.
  • Не извлекать больше данных, чем требуется. Do not retrieve more data than is necessary. Напишите запросы, возвращающие только те данные, которые необходимы для текущего HTTP-запроса. Write queries to return just the data that’s necessary for the current HTTP request.
  • Рассмотрите возможность кэширования часто используемых данных, полученных из базы данных или удаленной службы, если это приемлемо для более неактуальных данных. Do consider caching frequently accessed data retrieved from a database or remote service if slightly out-of-date data is acceptable. В зависимости от сценария используйте MemoryCache или DistributedCache. Depending on the scenario, use a MemoryCache or a DistributedCache. Для получения дополнительной информации см. Кэширование ответов в ASP.NET Core. For more information, see Кэширование ответов в ASP.NET Core.
  • Сократите круговые обходов сети. Do minimize network round trips. Целью является получение необходимых данных в одном вызове, а не в нескольких вызовах. The goal is to retrieve the required data in a single call rather than several calls.
  • Не используйте запросы без отслеживания в Entity Framework Core при доступе к данным в целях только для чтения. Do use no-tracking queries in Entity Framework Core when accessing data for read-only purposes. EF Core могут более эффективно возвращать результаты запросов без отслеживания. EF Core can return the results of no-tracking queries more efficiently.
  • Выполните фильтрацию и агрегирование запросов LINQ (например, с помощью .Where , .Select или инструкций .Sum ), чтобы фильтрация выполнялась базой данных. Do filter and aggregate LINQ queries (with .Where , .Select , or .Sum statements, for example) so that the filtering is performed by the database.
  • Учтите, что EF Core разрешает некоторые операторы запросов на клиенте, что может привести к неэффективному выполнению запроса. Do consider that EF Core resolves some query operators on the client, which may lead to inefficient query execution. Дополнительные сведения см. в статье проблемы с производительностью оценки клиента. For more information, see Client evaluation performance issues.
  • Не Используйте проекции запросов к коллекциям, что может привести к выполнению запросов SQL N + 1. Do not use projection queries on collections, which can result in executing «N + 1» SQL queries. Дополнительные сведения см. в разделе Оптимизация коррелированных вложенных запросов. For more information, see Optimization of correlated subqueries.

Методы, которые могут повысить производительность в крупномасштабных приложениях, см. в статье Высокая производительность . See EF High Performance for approaches that may improve performance in high-scale apps:

Мы рекомендуем оценить влияние предыдущих высокопроизводительных подходов перед фиксацией базы кода. We recommend measuring the impact of the preceding high-performance approaches before committing the code base. Дополнительная сложность скомпилированных запросов может не отнять повышение производительности. The additional complexity of compiled queries may not justify the performance improvement.

Проблемы запросов можно обнаружить, просмотрев время, затраченное на доступ к данным с помощью Application Insights или с помощью средств профилирования. Query issues can be detected by reviewing the time spent accessing data with Application Insights or with profiling tools. В большинстве баз данных также доступна статистика, касающаяся часто выполняемых запросов. Most databases also make statistics available concerning frequently executed queries.

HTTP-соединения пула с Хттпклиентфактори Pool HTTP connections with HttpClientFactory

Хотя HttpClient реализует интерфейс IDisposable , он предназначен для повторного использования. Although HttpClient implements the IDisposable interface, it’s designed for reuse. Закрытые экземпляры HttpClient оставлять сокеты открытыми в TIME_WAIT состоянии в течение короткого периода времени. Closed HttpClient instances leave sockets open in the TIME_WAIT state for a short period of time. Если часто используется путь кода, который создает и уничтожает объекты HttpClient , приложение может вычерпать доступные сокеты. If a code path that creates and disposes of HttpClient objects is frequently used, the app may exhaust available sockets. Хттпклиентфактори был представлен в ASP.NET Core 2,1 в качестве решения этой проблемы. HttpClientFactory was introduced in ASP.NET Core 2.1 as a solution to this problem. Он обрабатывает подключения по протоколу HTTP для оптимизации производительности и надежности. It handles pooling HTTP connections to optimize performance and reliability.

  • Не Создавайте и удаляйте экземпляры HttpClient напрямую. Do not create and dispose of HttpClient instances directly.
  • Используйтехттпклиентфактори для получения экземпляров HttpClient . Do use HttpClientFactory to retrieve HttpClient instances. Дополнительные сведения см. в статье Использование хттпклиентфактори для реализации устойчивых HTTP-запросов. For more information, see Use HttpClientFactory to implement resilient HTTP requests.

Быстрое отслеживание общих путей кода Keep common code paths fast

Необходимо, чтобы весь код был быстрым, часто называемым путями кода, наиболее критичным для оптимизации: You want all of your code to be fast, frequently called code paths are the most critical to optimize:

  • Компоненты по промежуточного слоя в конвейере обработки запросов приложения, особенно по промежуточного слоя выполняются на раннем этапе конвейера. Middleware components in the app’s request processing pipeline, especially middleware run early in the pipeline. Эти компоненты сильно влияют на производительность. These components have a large impact on performance.
  • Код, который выполняется для каждого запроса или несколько раз для каждого запроса. Code that’s executed for every request or multiple times per request. Например, пользовательское ведение журнала, обработчики авторизации или инициализацию временных служб. For example, custom logging, authorization handlers, or initialization of transient services.
  • Не используйте пользовательские компоненты промежуточного слоя с долго выполняющимися задачами. Do not use custom middleware components with long-running tasks.
  • Используйте средства профилирования производительности, такие как Visual Studio средства диагностики или PerfView), для указания путей использования горячих кодов. Do use performance profiling tools, such as Visual Studio Diagnostic Tools or PerfView), to identify hot code paths.

Выполнение длительных задач за пределами HTTP-запросов Complete long-running Tasks outside of HTTP requests

Большинство запросов к ASP.NET Core приложению могут обрабатываться контроллером или моделью страницы, вызывающими необходимые службы и возвращающими ответ HTTP. Most requests to an ASP.NET Core app can be handled by a controller or page model calling necessary services and returning an HTTP response. Для некоторых запросов, в которых задействованы длительные задачи, лучше сделать весь процесс «запрос-ответ» асинхронным. For some requests that involve long-running tasks, it’s better to make the entire request-response process asynchronous.

  • Не дожидаться завершения длительных задач в рамках обычной обработки HTTP-запросов. Do not wait for long-running tasks to complete as part of ordinary HTTP request processing.
  • Рассмотрите возможность обработки долго выполняющихся запросов с помощью фоновых служб или вне процесса с помощью функции Azure. Do consider handling long-running requests with background services or out of process with an Azure Function. Завершение работы вне процесса особенно полезно для ресурсоемких задач. Completing work out-of-process is especially beneficial for CPU-intensive tasks.
  • Используйте параметры связи в режиме реального времени, такие как SignalR, для асинхронной связи с клиентами. Do use real-time communication options, such as SignalR, to communicate with clients asynchronously.

Ресурсы клиента уменьшение Minify client assets

ASP.NET Core приложения с комплексными внешними интерфейсами часто обслуживают множество файлов JavaScript, CSS или изображений. ASP.NET Core apps with complex front-ends frequently serve many JavaScript, CSS, or image files. Производительность запросов начальной загрузки можно улучшить следующим образом. Performance of initial load requests can be improved by:

  • Объединение, объединяющее несколько файлов в один. Bundling, which combines multiple files into one.
  • Минификация, что сокращает размер файлов, удаляя пробелы и комментарии. Minifying, which reduces the size of files by removing whitespace and comments.
  • Используйтевстроенную поддержку ASP.NET Core для объединения и Минификация клиентских ресурсов. Do use ASP.NET Core’s built-in support for bundling and minifying client assets.
  • Ознакомьтесь с другими сторонними инструментами, такими как веб- пакет, для комплексного управления клиентскими ресурсами. Do consider other third-party tools, such as Webpack, for complex client asset management.

Сжатие ответов Compress responses


Уменьшение размера ответа обычно значительно увеличивает скорость реагирования приложения. Reducing the size of the response usually increases the responsiveness of an app, often dramatically. Одним из способов уменьшения размера полезных данных является сжатие ответов приложения. One way to reduce payload sizes is to compress an app’s responses. Дополнительные сведения см. в разделе сжатие ответов. For more information, see Response compression.

Илон Маск рекомендует:  Что такое код mcal_event_set_alarm

Использование последней версии ASP.NET Core Use the latest ASP.NET Core release

Каждый новый выпуск ASP.NET Core включает улучшения производительности. Each new release of ASP.NET Core includes performance improvements. Оптимизация в .NET Core и ASP.NET Core означает, что более новые версии обычно более эффективны старые версии. Optimizations in .NET Core and ASP.NET Core mean that newer versions generally outperform older versions. Например, в .NET Core 2,1 добавлена поддержка скомпилированных регулярных выражений и выиграли из Span . For example, .NET Core 2.1 added support for compiled regular expressions and benefitted from Span . В ASP.NET Core 2,2 добавлена поддержка HTTP/2. ASP.NET Core 2.2 added support for HTTP/2. ASP.NET Core 3,0 добавляет множество улучшений , которые уменьшают использование памяти и увеличивают пропускную способность. ASP.NET Core 3.0 adds many improvements that reduce memory usage and improve throughput. Если производительность является приоритетной, рассмотрите возможность обновления до текущей версии ASP.NET Core. If performance is a priority, consider upgrading to the current version of ASP.NET Core.

Уменьшение числа исключений Minimize exceptions

Исключения должны быть редкими. Exceptions should be rare. Создание и перехват исключений происходит очень долго относительно других шаблонов потока кода. Throwing and catching exceptions is slow relative to other code flow patterns. Поэтому исключения не должны использоваться для управления нормальным выполнением программы. Because of this, exceptions shouldn’t be used to control normal program flow.

  • Не используйте генерацию или перехват исключений в качестве средства обычного потока программы, особенно в путях горячего кода. Do not use throwing or catching exceptions as a means of normal program flow, especially in hot code paths.
  • Включите в приложение логику для обнаружения и обработки условий, вызывающих исключение. Do include logic in the app to detect and handle conditions that would cause an exception.
  • Вызывайте или перехватите исключения для необычных или непредвиденных условий. Do throw or catch exceptions for unusual or unexpected conditions.

Средства диагностики приложений, такие как Application Insights, могут помочь в определении распространенных исключений в приложении, которое может повлиять на производительность. App diagnostic tools, such as Application Insights, can help to identify common exceptions in an app that may affect performance.

Производительность и надежность Performance and reliability

Следующие разделы содержат советы по повышению производительности и известным проблемам надежности и решениям. The following sections provide performance tips and known reliability problems and solutions.

Избегайте синхронного чтения или записи в тексте HttpRequest/HttpResponse Avoid synchronous read or write on HttpRequest/HttpResponse body

Все операции ввода-вывода в ASP.NET Core являются асинхронными. All IO in ASP.NET Core is asynchronous. Серверы реализуют интерфейс Stream , который имеет как синхронные, так и асинхронные перегрузки. Servers implement the Stream interface, which has both synchronous and asynchronous overloads. Асинхронные объекты должны быть предпочтительнее, чтобы избежать блокирования потоков пула потоков. The asynchronous ones should be preferred to avoid blocking thread pool threads. Блокировка потоков может привести к нехватке пула потоков. Blocking threads can lead to thread pool starvation.

Не Выменяйте это: В следующем примере используется ReadToEnd. Do not do this: The following example uses the ReadToEnd. Он блокирует текущий поток для ожидания результата. It blocks the current thread to wait for the result. Это пример синхронизации через Async. This is an example of sync over async.

В приведенном выше коде Get синхронно считывает весь текст HTTP-запроса в память. In the preceding code, Get synchronously reads the entire HTTP request body into memory. Если клиент медленно отправляется, приложение выполняет синхронизацию асинхронно. If the client is slowly uploading, the app is doing sync over async. Приложение выполняет синхронизацию асинхронно, так как Kestrel не поддерживает синхронные операции чтения. The app does sync over async because Kestrel does NOT support synchronous reads.

Выполните следующие действия. В следующем примере используется ReadToEndAsync и не блокируется поток при чтении. Do this: The following example uses ReadToEndAsync and does not block the thread while reading.

Приведенный выше код асинхронно считывает весь текст HTTP-запроса в память. The preceding code asynchronously reads the entire HTTP request body into memory.

Если запрос имеет большой размер, чтение всего текста HTTP-запроса в память может привести к нехватке памяти. If the request is large, reading the entire HTTP request body into memory could lead to an out of memory (OOM) condition. Сбой может привести к отказу в обслуживании. OOM can result in a Denial Of Service. Дополнительные сведения см. в разделе избежание считывания текста большого запроса или тела ответа в память в этом документе. For more information, see Avoid reading large request bodies or response bodies into memory in this document.

Выполните следующие действия. Следующий пример полностью асинхронно использует текст запроса без буферизации: Do this: The following example is fully asynchronous using a non buffered request body:

Приведенный выше код асинхронно десериализует текст запроса в C# объект. The preceding code asynchronously de-serializes the request body into a C# object.

Предпочитать Реадформасинк по запросу. Form Prefer ReadFormAsync over Request.Form

Используйте HttpContext.Request.ReadFormAsync вместо HttpContext.Request.Form . Use HttpContext.Request.ReadFormAsync instead of HttpContext.Request.Form . HttpContext.Request.Form может быть безопасно прочитана только со следующими условиями: HttpContext.Request.Form can be safely read only with the following conditions:

  • Форма была считана вызовом ReadFormAsync и The form has been read by a call to ReadFormAsync , and
  • Кэшированное значение формы считывается с помощью HttpContext.Request.Form The cached form value is being read using HttpContext.Request.Form

Не Выменяйте это: В следующем примере используется HttpContext.Request.Form . Do not do this: The following example uses HttpContext.Request.Form . HttpContext.Request.Form использует синхронизацию асинхронно и может привести к нехватке пула потоков. HttpContext.Request.Form uses sync over async and can lead to thread pool starvation.

Выполните следующие действия. В следующем примере HttpContext.Request.ReadFormAsync используется для асинхронного чтения текста формы. Do this: The following example uses HttpContext.Request.ReadFormAsync to read the form body asynchronously.

Избегайте считывания текста крупного запроса или тела ответа в память Avoid reading large request bodies or response bodies into memory

В .NET каждое выделение объектов, превышающее 85 КБ, заканчивается в куче больших объектов (LOH). In .NET, every object allocation greater than 85 KB ends up in the large object heap (LOH). Большие объекты являются ресурсоемкими двумя способами: Large objects are expensive in two ways:

  • Стоимость выделения высока, так как память для вновь выделенного большого объекта должна быть сброшена. The allocation cost is high because the memory for a newly allocated large object has to be cleared. Среда CLR гарантирует, что память для всех вновь выделяемых объектов будет сброшена. The CLR guarantees that memory for all newly allocated objects is cleared.
  • LOH собирается вместе с остальной частью кучи. LOH is collected with the rest of the heap. Для LOH требуется полная сборка мусора или коллекция Gen2. LOH requires a full garbage collection or Gen2 collection.

Эта запись блога кратко описывает проблему: This blog post describes the problem succinctly:

При выделении большого объекта он помечается как объект Gen 2. When a large object is allocated, it’s marked as Gen 2 object. Не Gen 0 как для небольших объектов. Not Gen 0 as for small objects. Последствия в том, что если в LOH исчерпана память, сборщик мусора очищает всю управляемую кучу, а не только LOH. The consequences are that if you run out of memory in LOH, GC cleans up the whole managed heap, not only LOH. Он очищает Gen 0, Gen 1 и Gen 2, включая LOH. So it cleans up Gen 0, Gen 1 and Gen 2 including LOH. Это называется полной сборкой мусора и является наиболее длительным сбором мусора. This is called full garbage collection and is the most time-consuming garbage collection. Для многих приложений это может быть приемлемым. For many applications, it can be acceptable. Но определенно не для высокопроизводительных веб-серверов, где несколько больших буферов памяти требуются для обработки среднего веб-запроса (чтение из сокета, распаковка, декодирование JSON & больше). But definitely not for high-performance web servers, where few big memory buffers are needed to handle an average web request (read from a socket, decompress, decode JSON & more).

Простое хранение большого запроса или текста ответа в одном byte[] или string : Naively storing a large request or response body into a single byte[] or string :

  • Может привести к быстрому запуску пространства в LOH. May result in quickly running out of space in the LOH.
  • Может вызвать проблемы с производительностью приложения из-за выполнения полных GC. May cause performance issues for the app because of full GCs running.

Работа с синхронным интерфейсом API обработки данных Working with a synchronous data processing API

При использовании сериализатора или отмены сериализатора, поддерживающего только синхронные операции чтения и записи (например, JSON.NET): When using a serializer/de-serializer that only supports synchronous reads and writes (for example, JSON.NET):

  • Асинхронная буферизация данных в память перед их передачей в сериализатор/de-сериализатор. Buffer the data into memory asynchronously before passing it into the serializer/de-serializer.

Если запрос большой, это может привести к нехватке памяти («нехватки»). If the request is large, it could lead to an out of memory (OOM) condition. Сбой может привести к отказу в обслуживании. OOM can result in a Denial Of Service. Дополнительные сведения см. в разделе избежание считывания текста большого запроса или тела ответа в память в этом документе. For more information, see Avoid reading large request bodies or response bodies into memory in this document.

ASP.NET Core 3,0 по умолчанию использует System.Text.Json для сериализации JSON. ASP.NET Core 3.0 uses System.Text.Json by default for JSON serialization. System.Text.Json. System.Text.Json:

  • асинхронно считывает и записывает JSON; Reads and writes JSON asynchronously.
  • оптимизирован для текста UTF-8; Is optimized for UTF-8 text.
  • предоставляет более высокую производительность, чем Newtonsoft.Json . Typically higher performance than Newtonsoft.Json .

Не хранить Ихттпконтекстакцессор. HttpContext в поле Do not store IHttpContextAccessor.HttpContext in a field

Ихттпконтекстакцессор. HttpContext возвращает HttpContext активного запроса при доступе из потока запроса. The IHttpContextAccessor.HttpContext returns the HttpContext of the active request when accessed from the request thread. IHttpContextAccessor.HttpContext не должны храниться в поле или переменной. The IHttpContextAccessor.HttpContext should not be stored in a field or variable.

Не Выменяйте это: В следующем примере HttpContext сохраняется в поле, а затем попытается использовать его позже. Do not do this: The following example stores the HttpContext in a field, and then attempts to use it later.

В приведенном выше коде часто записывается значение null или неверный HttpContext в конструкторе. The preceding code frequently captures a null or incorrect HttpContext in the constructor.

Выполните следующие действия. Следующий пример: Do this: The following example:

  • Хранит IHttpContextAccessor в поле. Stores the IHttpContextAccessor in a field.
  • Использует поле HttpContext в нужное время и проверяет наличие null . Uses the HttpContext field at the correct time and checks for null .

Не обращаться к HttpContext из нескольких потоков Do not access HttpContext from multiple threads

HttpContext не является потокобезопасным. HttpContext is NOT thread-safe. Параллельный доступ к HttpContext из нескольких потоков может привести к неопределенному поведению, такому как зависание, сбои и повреждение данных. Accessing HttpContext from multiple threads in parallel can result in undefined behavior such as hangs, crashes, and data corruption.


Не Выменяйте это: В следующем примере выполняется три параллельных запроса и записывается путь к входящему запросу до и после исходящего HTTP-запроса. Do not do this: The following example makes three parallel requests and logs the incoming request path before and after the outgoing HTTP request. Доступ к пути запроса осуществляется из нескольких потоков, которые могут быть параллельными. The request path is accessed from multiple threads, potentially in parallel.

Выполните следующие действия. В следующем примере все данные из входящего запроса копируются перед выполнением трех параллельных запросов. Do this: The following example copies all data from the incoming request before making the three parallel requests.

Не используйте HttpContext после завершения запроса Do not use the HttpContext after the request is complete

HttpContext допустимо только при условии, что в конвейере ASP.NET Core есть активный HTTP-запрос. HttpContext is only valid as long as there is an active HTTP request in the ASP.NET Core pipeline. Весь конвейер ASP.NET Core является асинхронной цепочкой делегатов, выполняющих каждый запрос. The entire ASP.NET Core pipeline is an asynchronous chain of delegates that executes every request. После завершения Task , возвращенного из этой цепочки, HttpContext перезапускается. When the Task returned from this chain completes, the HttpContext is recycled.

Не Выменяйте это: В следующем примере используется async void , который делает HTTP-запрос завершенным при достижении первого await : Do not do this: The following example uses async void which makes the HTTP request complete when the first await is reached:

  • Это всегда является неправильной практикой в ASP.NET Core приложениях. Which is ALWAYS a bad practice in ASP.NET Core apps.
  • Обращается к HttpResponse после завершения HTTP-запроса. Accesses the HttpResponse after the HTTP request is complete.
  • Завершается сбоем процесса. Crashes the process.

Выполните следующие действия. В следующем примере возвращается Task платформе, поэтому HTTP-запрос не завершается до завершения действия. Do this: The following example returns a Task to the framework so the HTTP request doesn’t complete until the action completes.

Не захватывать HttpContext в фоновых потоках Do not capture the HttpContext in background threads

Не Выменяйте это: В следующем примере показано закрытие HttpContext из свойства Controller . Do not do this: The following example shows a closure is capturing the HttpContext from the Controller property. Это неплохая практика, поскольку рабочий элемент может: This is a bad practice because the work item could:

  • Выполнение за пределами области запроса. Run outside of the request scope.
  • Попытка прочитать неправильный HttpContext . Attempt to read the wrong HttpContext .

Выполните следующие действия. Следующий пример: Do this: The following example:

  • Копирует данные, необходимые в фоновой задаче, во время запроса. Copies the data required in the background task during the request.
  • Не ссылается на что-либо из контроллера. Doesn’t reference anything from the controller.

Фоновые задачи должны быть реализованы как размещенные службы. Background tasks should be implemented as hosted services. Дополнительные сведения см. в статье Background tasks with hosted services in ASP.NET Core (Фоновые задачи с размещенными службами в ASP.NET Core). For more information, see Background tasks with hosted services.

Не захватывать службы, внедренные в контроллеры в фоновых потоках Do not capture services injected into the controllers on background threads

Не Выменяйте это: В следующем примере показано закрытие DbContext из параметра действия Controller . Do not do this: The following example shows a closure is capturing the DbContext from the Controller action parameter. Это неплохой подход. This is a bad practice. Рабочий элемент может выполняться вне области запроса. The work item could run outside of the request scope. ContosoDbContext ограничивается запросом, что приводит к ObjectDisposedException . The ContosoDbContext is scoped to the request, resulting in an ObjectDisposedException .

Выполните следующие действия. Следующий пример: Do this: The following example:

  • Внедряет IServiceScopeFactory, чтобы создать область в фоновом рабочем элементе. Injects an IServiceScopeFactory in order to create a scope in the background work item. IServiceScopeFactory является Singleton-классом. IServiceScopeFactory is a singleton.
  • Создает новую область внедрения зависимостей в фоновом потоке. Creates a new dependency injection scope in the background thread.
  • Не ссылается на что-либо из контроллера. Doesn’t reference anything from the controller.
  • Не захватывает ContosoDbContext из входящего запроса. Doesn’t capture the ContosoDbContext from the incoming request.

Выделенный ниже код: The following highlighted code:

  • Создает область в течение времени существования фоновой операции и разрешает службы из нее. Creates a scope for the lifetime of the background operation and resolves services from it.
  • Использует ContosoDbContext из правильной области действия. Uses ContosoDbContext from the correct scope.

Не изменяйте код состояния или заголовки после начала текста ответа Do not modify the status code or headers after the response body has started

ASP.NET Core не замещает текст HTTP-ответа. ASP.NET Core does not buffer the HTTP response body. При первом написании ответа: The first time the response is written:

  • Заголовки отправляются клиенту вместе с этим фрагментом текста. The headers are sent along with that chunk of the body to the client.
  • Больше нельзя изменять заголовки ответа. It’s no longer possible to change response headers.

Не Выменяйте это: Следующий код пытается добавить заголовки ответа после того, как ответ уже запущен: Do not do this: The following code tries to add response headers after the response has already started:

В приведенном выше коде context.Response.Headers[«test»] = «test value»; выдаст исключение, если next() записал в ответ. In the preceding code, context.Response.Headers[«test»] = «test value»; will throw an exception if next() has written to the response.

Выполните следующие действия. В следующем примере проверяется, начался ли HTTP-ответ перед изменением заголовков. Do this: The following example checks if the HTTP response has started before modifying the headers.

Выполните следующие действия. В следующем примере используется HttpResponse.OnStarting для установки заголовков перед очисткой заголовков ответа клиенту. Do this: The following example uses HttpResponse.OnStarting to set the headers before the response headers are flushed to the client.

Проверка того, что ответ не запущен, позволяет регистрировать обратный вызов, который будет вызываться непосредственно перед заголовком ответа. Checking if the response has not started allows registering a callback that will be invoked just before response headers are written. Проверяется, не начался ли ответ: Checking if the response has not started:

  • Предоставляет возможность добавлять или переопределять заголовки по времени. Provides the ability to append or override headers just in time.
  • Не требует знания следующего по промежуточного слоя в конвейере. Doesn’t require knowledge of the next middleware in the pipeline.

Не вызывайте Next (), если вы уже начали записывать в текст ответа. Do not call next() if you have already started writing to the response body

Компоненты должны вызываться, только если они могут обрабатывать ответ и управлять им. Components only expect to be called if it’s possible for them to handle and manipulate the response.

Исследование производительности ASP.NET-приложений

Рубрика: 1. Информатика и кибернетика

Дата публикации: 03.07.2020

Статья просмотрена: 54 раза

Библиографическое описание:

Яськов А. Д. Исследование производительности ASP.NET-приложений [Текст] // Технические науки: проблемы и перспективы: материалы V Междунар. науч. конф. (г. Санкт-Петербург, июль 2020 г.). — СПб.: Свое издательство, 2020. — С. 22-25. — URL https://moluch.ru/conf/tech/archive/231/12744/ (дата обращения: 12.11.2020).

В данной работе рассматриваются, анализируются и систематизируются факторы, оказывающие влияние на производительность ASP.NET-приложений, описываются способы повышения производительности.

Ключевые слова: ASP.NET, производительность, веб-приложение, быстродействие

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

ASP.NET представляет из себя часть технологии.NET, предназначенную для создания динамических HTML-страниц. Она позволяет писать мощные клиент-серверные веб-приложения. ASP.NET возникла в результате объединения более старой технологии ASP (active server pages) и.NET Framework. В ней содержатся готовые элементы управления, позволяющие быстро и качественно создавать готовые интерактивные интернет-сайты. Ключевое слово здесь — быстро. Также имеется возможность использовать сервисы других сайтов максимально понятно и прозрачно для пользователей.

Производительность любого веб-приложения можно рассматривать с двух сторон: с точки зрения конечного пользователя и с точки зрения сервера (или разработчика).

В первом случае пользователя интересует скорость реакции на его запрос, то есть время отклика приложения. Остальное его не интересует. При относительно малом времени отклика пользователя не будет возникать других вопросов к приложению, касающихся его производительности [1].

Во втором случае главных показателя будет два: количество одновременных запросов, направленных на сервер, и количество активных пользователей в определенный момент времени. Активными пользователями считаются те, которые осуществляют работу с приложением, и при этом получают ответ за приемлемое для них время.


Подходы к повышению производительности можно условно разделить на три группы: уменьшение времени обработки страницы на стороне клиента, на стороне сервера и уменьшение объема передаваемых данных [2].

Чтобы уменьшить время обработки страницы на стороне клиента нужно придерживаться некоторых правил:

− Максимально использовать таблицы стилей CSS.

− Минимально использовать в странице разнообразные таблицы. В первую очередь те, в которых не заданы явным образом размеры ячеек. Использование таких таблиц, особенно совместно с фоновыми изображениями внутри ячеек приводит к тому, что при загрузке страницы браузер на стороне клиента сначала строит таблицу, самостоятельно высчитывая приемлемые размеры ячейки. Затем он пытается включить в построенную ячейку изображение, заданное для нее в качестве фонового. После чего может получиться так, что изображение не помещается внутри ячейки, так как при ее построении браузер не учитывал размеры изображения, которое предстояло в ней разместить. В этом случае браузер начнет перерисовывать таблицу заново, с нуля пересчитывая габариты ячеек, что негативно скажется на времени отображения страницы у пользователя. Это объясняется особенностями работы браузеров. Поэтому, если без таблицы обойтись нельзя, то лучше всегда задавать размеры ее ячеек самостоятельно.

− Максимально оптимизировать HTML.

− Максимально оптимизировать JavaScript. Соблюдение последних двух условий может позволить добиться существенного прироста в скорости загрузки страницы.

− Не использовать вставку внешних скриптов. Если отказаться от них полностью не представляется возможным, то хотя бы минимизировать их количество. Это требование, опять же, связано с особенностями работы браузеров. В случае, если в странице вставлены внешние скрипты, может возникнуть серьезная проблема. Сама страница может загрузиться очень быстро при соблюдении остальных правил, но использованный на ней внешний скрипт может обращаться к удаленному серверу, имеющему крайне высокое время ответа. В силу особенностей работы большинства браузеров, в этом случае страница не загрузится полностью до тех пор, пока не придет ответ от удаленного сервера, даже если элемент, с которым связан внешний скрипт, сам по себе является незначительным. К счастью, существует несколько способов обойти данную проблему, но лучше по возможности полностью отказаться от вставки внешних скриптов в веб-страницу.

Илон Маск рекомендует:  Что такое код getwindowtask

Уменьшение объема передаваемых данных:

− Использование HTTP-сжатия. Это самое простое правило, так как для его соблюдения чаще всего не требуется дополнительных затрат времени. Большая часть современных браузеров и серверов поддерживает эту технологию, поэтому было бы не лишним ее использовать для уменьшения объема передаваемых от клиента к серверу и обратно данных.

− Использование идентичных URL-адресов для файлов. Здесь подразумевается, что в веб-приложении часто одни и те же файлы, например, файлы изображений, используются по несколько раз. Браузер, видя URL-адрес изображения впервые, загружает его и сохраняет в кэш. В случае, если ему встречается еще раз этот же адрес, браузер уже не загружает изображение снова с сервера, а использует сохраненную в кэше копию. Если же URL-адрес отличается от первого, то браузер загрузит изображение снова, тем самым создав дополнительную ненужную нагрузку на соединение. Это произойдет в любом случае, независимо от того, было ли ранее загружено идентичное изображение или нет. Браузер сравнивает только URL-адреса. Поэтому необходимо, чтобы у одних и тех же файлов адреса не отличались.

− Использование SSL только там, где это действительно необходимо. Любое шифрование почти всегда повышает объем передаваемых данных. Зачастую оно используется там, где не приносит пользы. Многие страницы и приложения не содержат никакой конфиденциальной или другой информации, которую следовало бы шифровать. Хотя во многих других случаях использование SSL оправданно. Необходимо стремиться к тому, чтобы шифрование применялось только в последних случаях.

− Использование AJAX. Плюсов использование этой технологии приносит очень много. AJAX позволяет передавать пользователю изначально только основную часть информации, а не весь ее объем. Затем, в процессе работы, передавать только те элементы и части страницы, которые действительно необходимо изменить. Это позволяет не передавать по сети всю страницу в полном объеме при каждом действии на стороне клиента.

− Использование клиентской валидации. Валидация на стороне сервера, особенно в случае заполнения разнообразных форм, ведет к увеличению объема передаваемых данных. Это связано с тем, что в подавляющем большинстве случаев пользователь не справляется с корректным заполнением всех полей на форме с первого раза. Но отправка данных осуществляется после каждого заполнение. Так как проверка на валидность осуществляется уже на стороне сервера. После чего пользователю приходит ответ о некорректности введенных данных, и операция повторяется. Если использовать клиентскую валидацию, то проверка на корректность будет происходить без обмена данными между клиентом и сервером. Хотя во многих случаях использование серверной валидации является необходимым в вопросах безопасности, поэтому в таких случаях следует использовать совместно клиентскую и серверную валидацию.

Существуют и другие правила, но здесь рассматриваются только самые основные, которые следует помнить в первую очередь.

Уменьшение времени обработки страницы на стороне сервера:

Здесь правил больше всего, и их выполнение особенно важно, так как время обработки запроса сервером часто превышает время на других этапах работы веб-приложения [3].

− Максимальная оптимизация кода и использования ресурсов. Здесь комментарии не требуются. Чем быстрее будет происходить обработка запроса на сервере, там быстрее ответ будет приходить к клиенту.

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

− Отключение неиспользуемых HTTPModule

− Оптимизация конфигурации ASP.NET. В большинстве случаев использования ASP.NET файлам конфигурации не уделяют должного внимания. Стандартная конфигурация ASP.NET универсальна — она удовлетворяет большинству требований, то в каждом конкретном отдельно взятом случае она не является оптимальной. Конфигурацию следует подстраивать уникально, в зависимости от функций.

− Буферизация вывода. При использовании ASP.NET эта функция включена автоматически, просто не стоит ее отключат ь. Она играет очень важную роль. Она позволяет накапливать информацию в буфере до момента ее отправки на сервер, а не отправлять каждый байт информации сразу после его появления. Это существенно разгружает соединение.

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

− Кэширование. Последние три свойства являются основными в этой группе. Кэширование — одно из них. В самом простом случае оно подразумевает сохранение копии данных на определенное время на стороне клиента. Это позволяет при большинстве запросов не выполнять загрузку данных с сервера по линии соединения, а загружать ее из кэша, что существенно снижает нагрузку на соединение. Все изменения, которые производятся со страницей, сохраняются именно в этой копии у клиента. Чаще всего кэширование производится на заданной временной промежуток. В этом случае первая операция, обращенная к странице, произошедшая по истечении этого промежутка времени, уже действительно загрузит страницу по сети, тем самым обновив ее копию в кэше, а все предыдущие операции будут работать лишь с этой копией. Причем в ASP.NET реализованы так называемые профили кэширования. Они позволяют заранее создать в файле web.config настройки кэширования, такие как время хранения копии и другие параметры, а затем лишь обращаться к этим профилям, не обозначая всех параметров. Однако, при использовании кэширования следует помнить об одном важном моменте. При использовании копии данных, сохраненных на стороне клиента, можно добиться повышения скорости работы веб-приложения, но, как только будет превышено определенное количество данных, хранящихся в кэше, произойдет серьезное падение производительности, так как память клиента имеет физические ограничения, и хранить на ней данных в полном объеме не получится. Поэтому при использовании кэширования следует соблюдать баланс между общим объемом информации и той частью, которая сохраняется в кэше клиента.

− Асинхронность. На веб-сервере платформы.NET Framework поддерживается пул потоков, которые используются для обслуживания запросов ASP.NET. При получении запроса, для его обработки из этого пула выделяется поток (thread). Если запрос обрабатывается синхронно, то поток, который обрабатывает запрос, блокируется на время обработки запроса. Такой поток не может обслуживать другой запрос. Это может не составлять проблемы, так как пул потоков можно сделать достаточно большим для вмещения множества заблокированных потоков. Однако, количество потоков в пуле ограничено. В больших приложениях, которые обрабатывают несколько одновременных запросов, которые выполняются длительное время, все доступные потоки могут быть заблокированы. Такая ситуация называется нехваткой потоков. При наступлении этой ситуации веб-сервер помещает запросы в очередь. После заполнения очереди запросов веб-сервер отклоняет запросы, возвращая код ошибки HTTP 503 (сервер перегружен). В приложениях, в которых может возникнуть нехватка потоков, можно настроить действия, которые обрабатываются асинхронно. Асинхронный запрос обрабатывается такое же количество времени, что и синхронный запрос. Например, если запрос выполняет сетевой вызов, который требует две секунды для выполнения, запрос будет обрабатываться две секунды, независимо от того, выполнен он синхронным или асинхронным способом. Однако, при асинхронном вызове сервер не заблокирован для ответов на другие запросы во время ожидания выполнения первого запроса. Поэтому асинхронные запросы предупреждают постановку запросов в очередь в ситуации, когда существует множество запросов, которые вызывают длительные по времени операции.

− Многопоточность. Это свойство позволяет достаточно просто и производительно реализовать процессы, не связанные с пользовательским интерфейсом, или требующие запуска по расписанию. Без использования многопоточности эти операции приводят к блокированию пользовательского интерфейса. Например, это может быть обращение к какому-то серверу в сети. В этом случае пользователю придется дожидаться момента, когда от этого сервера вернется ответ. Только тогда он сможет продолжить работа с приложением. Разумнее было бы предоставить в это время пользователю возможность выполнять какие-то другие действия или вообще отменить этот запрос. В любой ситуации, когда требуется ожидание, будь то запрос к базе данных, файлу или сети, может запускаться новый поток, позволяющий в это время решать другие задачи. Это и есть многопоточность. Она может быть реализована через обработку потоков одного и того же запроса разными процессорами или, что бывает чаще, разными ядрами одного процессора. При этом могут возникать определенные проблемы. Например, в случае, когда разные потоки пытаются одновременно получить доступ к одним и тем же данным. Поэтому при использовании многопоточности следует помнить о механизмах синхронизации потоков. В этом случае многопоточность оправдана и способна принести очень существенный вклад в повышение производительности приложения [4].

Стратегии масштабирования для приложений ASP.NET

Written on 13 Февраля 2009 . Posted in ASP.NET

ОГЛАВЛЕНИЕ

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

Уравнение производительности

В сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый «Field Guide to Application Delivery Systems» («Полевое руководство по системам доставки приложений»). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network – WAN), и в нем было приведено уравнение с рис. 1. Это уравнение рассматривает производительность глобальных сетей, но с несколькими мелкими изменениями его можно использовать и для измерения производительности веб-приложений. Измененное уравнение показано на рис. 2, а его элементы объяснены на рис. 3.

Рис. 1 The Original Performance Equation

Рис. 2 The Web Version of the Performance Equation

Рис. 3 Элементы уравнения производительности

Переменная Определение
R Время ответа. Общее время с запроса страницы пользователем (обычно переходом по ссылке и т.п.) до полной визуализации страницы на его компьютере. Обычно измеряется в секундах.
Объем полезных данных Общее число байтов, отправленных обозревателю, включая разметку и все ресурсы (такие как файлы CSS, JS и изображений).
Пропускная способность Скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду.
AppTurns Число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time – RTT) перед выражением AppTurns.
RTT Время, необходимое для приема и передачи данных, вне зависимости от числа переданных байтов. Каждый запрос тратит минимум одно RTT для самой страницы. Обычно измеряется в миллисекундах.
Одновременные запросы Число одновременных запросов файлов ресурсов, которые выполнит обозреватель. По умолчанию Internet Explorer выполняет два одновременных запроса. Данный параметр может быть изменен, но это делается редко.
Cs Время вычислений на сервере. Время, уходящее у кода на запуск, извлечение данных из базы данных и составление ответа, отправляемого обозревателю. Измеряется в миллисекундах.
Cc Время вычислений на клиенте. Время, уходящее у обозревателя на визуализацию HTML на экране, исполнение JavaScript, применение правил CSS, итд.

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

Объем полезных данных можно измерить с помощью различных средств (отличным вариантом является websiteoptimization.com/services/analyze), точно так же, как и пропускную способность (см. speedtest.net) и время приема-передачи (используя программу Ping). Средства вроде websiteoptimization.com/services/analyze также сообщат размер HTML, CSS, JavaScript, изображений и прочих частей веб-страницы. Число одновременных запросов по сути являются постоянной (для Internet Explorer® по умолчанию используется 2).

В результате остаются только Cs и Cc (времена вычислений на сервере и клиенте), измерение которых требует некоторых дополнительных усилий от разработчика. Написание кода на странице ASP.NET, отмечающей точную секунду, когда начинается исполнение страницы, и вычитающей это время из текущего времени при завершении исполнения, является сравнительно простой задачей. Это же верно и для клиента – небольшой кусок кода на JavaScript может быть исполнен прямо наверху страницы HTML, чтобы отметить время и затем вычесть время на момент запуска события OnLoad при завершении страницы.

Все эти элементы можно внести в программный код, если требуется создать для веб-узла режим отладки, использующий уравнение производительности. Имеется убедительная причина так и сделать: постоянное выполнение элементов уравнения производительности на обозревателе позволяет легко обнаружить, в чем состоят проблемы производительности.

Оптимизация ASP.NET приложений

Расскажите друзьям о событии

Рекомендуемые события

Извините, регистрация закрыта. Возможно, на событие уже зарегистрировалось слишком много человек, либо истек срок регистрации. Подробности Вы можете узнать у организаторов события.

30 октября пройдет семинар по оптимизация ASP.NET приложений. В программе как клиентская, так и серверная оптимизация, а также введение в оптимизацию баз данных.

Расскажите друзьям о событии

Быстродействие — это Фича. Для веб-приложений и сайтов это важнейшая фича. Быстрые сайты получают более высокие места в поисковой выдаче. Быстрые веб-приложения улучат восприятие пользователями. Масштабируемые приложения требуют меньше ресурсов и более эффективны с экономической точки зрения. Для любого веб-программиста умение делать быстрые и масштабируемые приложения является критически важным.

Но оптимизация веб-приложений — это не один навык, а целый комплекс, который включает клиентскую оптимизацию, оптимизацию работы с данными, оптимизацию архитектуры и инфраструктуры приложений, а также умение проводить нагрузочное тестирование и выявлять слабые места. Для ASP.NET это важно вдвойне, так как много фреймворков и компонент могут скрывать проблему, и докопаться до сути очень непросто. Но это того стоит!

В конце концов если вашим приложением пользуются хотя бы 1000 человек, каждый из которых делает по 10 запросов в день, то сократив время загрузки страницы на 1 секунду вы экономите суммарно почти месяц времени.

  1. Введение в оптимизацию ASP.NET приложений
    • Почему нужно заниматься оптимизацией
    • Архитектура ASP.NET приложений
    • Измерение производительности ASP.NET приложений
    • Инструменты для нагрузочного тестирования веб-приложений
    • Основные подходы оптимизации веб-приложений
  2. Оптимизация инфраструктуры
    • Настройка IIS
    • Оптимизация статического контента
  3. Кеширование динамического контента
    • HTTP-кеширование
    • Серверное кеширование
    • Варьирование кэша на сервере
    • Использование кэша ASP.NET
    • Интеграция кэша ASP.NET и распределенного кэша
  4. Оптимизация работы с данными
    • Оптимизация Linq запросов
    • Оптимизация работы с базой на примере SQL Server
    • Оптимизация записи в СУБД
  5. Клиентская оптимизация
    • Минимизация и бандлинг
    • Оптимизация динамических изображений
    • Оптимизация загрузки страницы
    • Оптимизация выполнения скриптов
    • Оптимизация CSS
  6. Оптимизация серверного кода
    • Оптимизация веб-форм
    • Оптимизация WebAPI
    • Оптимизация.NET кода

Как видите — программа очень плотная и все надо успеть за один день. Так что не будет времени переливать из пустого в порожнее. Полученные знания вы сможете сразу же применить в своих проектах.


Стоимость семинара — 10,000 рублей с человека.

Внимание: если ни один из предложенных способов вам не поможет вам увеличить скорость работы или масштабируемость, то вы можете вернуть деньги. Серьезно.

Регистрируйтесь прямо сейчас, количество мест ограничено.

Оптимизация приложений ASP.NET. Приложения для iPhone и Android для приложений ASP.NET.

У меня есть приложение ASP.NET(не MVC).

Я хотел бы создать версию, оптимизированную для браузеров на IPhone и на Android.

  • Возможно ли обнаружение IPhone/Android при доступе к сайту.
  • Есть ли какие-либо проблемы/советы по разработке ASP.NET для этих устройств.

Мы используем комбинацию .net webforms и jQuery mobile.

Для нашего viewstate это было довольно хорошо стерилизовано, так что только незначительные вещи идут к устройству.

Имейте в виду, что существует около 3 различных мобильных api. Каждый из них имеет свои недостатки. Вы можете изучить их.

Кроме того, мы приняли подход к тому, что мобильный сайт был совершенно другим сайтом, чем наш стандартный. Когда пользователь приходит, мы делаем некоторые нюансы браузера и нажимаем их на мобильный, если он соответствует ссылке, чтобы вернуться к полной, если они захотят.

Webforms не подходит для мобильных устройств, он генерирует большие страницы, потому что viewstate. И вы не можете управлять рендерингом (еще немного .net4).

Вы можете обнаружить устройство, используя db возможностей, таких как WURFL (я рекомендую 51degrees) o возможно, используя некоторые, например http://detectmobilebrowser.com/

Я не знаю, что такое webapp, но вы можете создать новое приложение, возможно, используя MVC. Посмотрите этот ресурс.

Стратегии масштабирования для приложений ASP.NET

Как советников по производительности ASP.NET нас обычно привлекают к проекту, когда проблемы уже возникли. Во многих случаях, вызов приходит только тогда, когда приложение уже в производстве. То, что работало отлично для разработчиков, не работает для пользователей. Жалоба: веб-узел работает слишком медленно. Руководство хочет знать, в чем причина и почему ее не обнаружили при тестировании. Разработчики не могут воспроизвести проблему. По крайней мере, один человек утверждает, что ASP.NET не масштабируется. Звучит знакомо?

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

Уравнение производительности

В сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый «Field Guide to Application Delivery Systems» («Полевое руководство по системам доставки приложений»). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network — WAN), и в нем было приведено уравнение с рис. 1. Это уравнение рассматривает производительность глобальных сетей, но с несколькими мелкими изменениями его можно использовать и для измерения производительности веб-приложений. Измененное уравнение показано на рис. 2, а его элементы объяснены на рис. 3.

Рис. 1 The Original Performance Equation

Рис. 2 The Web Version of the Performance Equation

Рис. 3 Элементы уравнения производительности

Переменная Определение
R Время ответа. Общее время с запроса страницы пользователем (обычно переходом по ссылке и т.п.) до полной визуализации страницы на его компьютере. Обычно измеряется в секундах.
Объем полезных данных Общее число байтов, отправленных обозревателю, включая разметку и все ресурсы (такие как файлы CSS, JS и изображений).
Пропускная способность Скорость передачи данных обозревателю и от него. Может быть асимметрична и представлять несколько скоростей, если данная страница создается из нескольких источников. Обычно усредняется для создания единого выражения пропускной способности в байтах в секунду.
AppTurns Число файлов ресурсов, требуемых страницей. Они включают файлы CSS, JS, изображений и любые другие файлы, извлекаемые обозревателем в процессе визуализации страницы. Уравнение учитывает страницу HTML отдельно, добавляя время приема-передачи (round-trip time — RTT) перед выражением AppTurns.
RTT Время, необходимое для приема и передачи данных, вне зависимости от числа переданных байтов. Каждый запрос тратит минимум одно RTT для самой страницы. Обычно измеряется в миллисекундах.
Одновременные запросы Число одновременных запросов файлов ресурсов, которые выполнит обозреватель. По умолчанию Internet Explorer выполняет два одновременных запроса. Данный параметр может быть изменен, но это делается редко.
Cs Время вычислений на сервере. Время, уходящее у кода на запуск, извлечение данных из базы данных и составление ответа, отправляемого обозревателю. Измеряется в миллисекундах.
Cc Время вычислений на клиенте. Время, уходящее у обозревателя на визуализацию HTML на экране, исполнение JavaScript, применение правил CSS, итд.

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

Объем полезных данных можно измерить с помощью различных средств (отличным вариантом является websiteoptimization.com/services/analyze), точно так же, как и пропускную способность (см. speedtest.net) и время приема-передачи (используя программу Ping). Средства вроде websiteoptimization.com/services/analyze также сообщат размер HTML, CSS, JavaScript, изображений и прочих частей веб-страницы. Число одновременных запросов по сути являются постоянной (для Internet Explorer® по умолчанию используется 2).

В результате остаются только Cs и Cc (времена вычислений на сервере и клиенте), измерение которых требует некоторых дополнительных усилий от разработчика. Написание кода на странице ASP.NET, отмечающей точную секунду, когда начинается исполнение страницы, и вычитающей это время из текущего времени при завершении исполнения, является сравнительно простой задачей. Это же верно и для клиента — небольшой кусок кода на JavaScript может быть исполнен прямо наверху страницы HTML, чтобы отметить время и затем вычесть время на момент запуска события OnLoad при завершении страницы.

Все эти элементы можно внести в программный код, если требуется создать для веб-узла режим отладки, использующий уравнение производительности. Имеется убедительная причина так и сделать: постоянное выполнение элементов уравнения производительности на обозревателе позволяет легко обнаружить, в чем состоят проблемы производительности.

Для примера, предположим, что имеется приложение ASP.NET, пользователи которого находятся на другом континенте и имеют низкую пропускную способность. При высоком времени проверки связи (> 200 мс) и низкой пропускной способности ( ASP.NET , не слишком хорошо подходит для того, чтобы поставлять эти типы файлов. По этой причине отдельная группа серверов IIS, специально настроенных для поставки файлов ресурсов, может существенно повлиять на масштабируемость используемого приложения.

Если выполняются большие объемы сжатия или шифрования (для SSL), может помочь установка специальных серверов для SSL. Следует знать, что существует даже специализированное оборудование для сжатия и терминации SSL.

Хотя более традиционные стратегии разбиения уровней сервера на составные части могут предложить выделение отдельных серверов для доступа к данным, сложных вычислений и так далее, независимых от собственно создания веб-страниц, лично я предпочитаю иметь пять веб-серверов, которые выполняют весь спектр операций, чем три веб-сервера и два сервера бизнес-объектов. Все эти внепроцессные вызовы между веб-серверами и серверами бизнес-объектов поглощают много ресурсов.

Илон Маск рекомендует:  Что такое код ceil

К специализации следует прибегать только ради известного и ожидаемого улучшения. И быстрейшее решение — не всегда лучшее. Целью масшабирования является единообразие производительности. По мере увеличения нагрузки диапазон производительность желательно сужать — будь пользователей двое или тысяча, определенная страница должна отображаться для них за одно и то же время.

Рано или поздно для более эффективного масштабирования будет необходимо оптимизировать код сервера. Практически все аспекты уравнения производительности масштабируются линейно, за исключением времени вычислений на сервере — всегда можно увеличить пропускную способность (и понять, когда это нужно, довольно просто), а время вычислений на клиенте не меняется по мере роста числа клиентов. Другие элементы уравнения производительности также сохраняют свой характер при масштабировании. Но время вычислений на сервере потребует настройки при увеличении числа пользователей.

Оптимизация кода

При оптимизации серверного кода весь фокус состоит в использовании тестирования для проверки наличия реальных результатов. Для анализа приложения и поиска мест в приложении, вызывающих наибольшие затраты времени, следует использовать профилирование. Весь процесс должен быть основан на эксперименте: используйте средства чтобы найти код, который следует улучшить, улучшите код, проведите тестирование, чтобы увидеть, улучшилась ли производительность, повторяйте до получения нужных результатов. Для действительно крупных веб-узлов настройку производительности часто сравнивают с покраской моста «Золотые врата»: к тому времени, как докрасишь его до конца, в начале краска уже облезла, и пора браться за дело снова.

Меня всегда поражает число людей, считающих, что масштабирование начинается с распределения. «Нужно больше оборудования!» — кричат они. Не поймите меня неправильно: добавление оборудования, без сомнения, может помочь. Но без специализации и оптимизации отдача будет минимальной.

Специализация позволяет распределять составные части приложения нужным образом. Например, если отделены серверы изображений, то их можно легко масштабировать независимо от остальной части приложения.

Оптимизация также дает дополнительные дивиденды при распределении, уменьшая объем работы, необходимый для определенной операции. Это напрямую выливается в уменьшение числа серверов, необходимых для обслуживания того же числа пользователей.

Балансировка нагрузки

Чтобы применить распределение, необходимо добавить новые серверы, продублировать приложение на них и организовать балансировку нагрузки. Для балансировки нагрузки можно использовать службу балансировки сетевой нагрузки (Network Load Balancing — NLB), входящую во все версии Windows Server® 2003. NLB делает каждый сервер равноправным партнером в отношении балансировки нагрузки. Все они используют одинаковый алгоритм балансировки, и все они прослушивают весь трафик на общем виртуальном IP-адресе. Основываясь на алгоритме балансировки нагрузки, каждый сервер знает, какой сервер должен работать над каждым конкретным запросом. Каждый сервер в кластере оправляет периодический сигнал, давая остальным знать, что он работоспособен. При сбое сервера периодический сигнал для него останавливается, и остальные серверы компенсируют потерю выбывшего автоматически.
NLB хорошо работает при наличии большого числа пользователей, делающих довольно похожие запросы. Однако механизм компенсации работает хуже в ситуации, где некоторые запросы создают намного большую нагрузку, чем другие. К счастью, для такого типа ситуаций доступны решения балансировки нагрузки на основе оборудования.

Сходство

В конечном счете, сложность эффективного распределения состоит в ликвидации сходства. Например, при наличии только одного веб-сервера хранение на нем данных сеанса вполне понятно. Но где хранить сведения о сеансе при наличии более чем одного веб-сервера?

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

Но в долгосрочной перспективе сходство создает затруднения. Хранение данных сеанса в процессе может быть быстрым, но если рабочий процесс ASP.NET перезапускается, все эти сеансы погибают. А рабочие процессы перезапускаются по множеству причин. При высокой нагрузке IIS может перезапустить рабочий процесс ASP.NET, посчитав его зависшим. Более того, по умолчанию IIS 6.0 перезапускает рабочий процесс каждые 23 часа. Это можно скорректировать, но, так или иначе, пользователям угрожает потеря данных их сеанса, пока они в процессе. Пока веб-узел невелик, это не такая уж проблема, но по мере его роста и увеличения занятости растет и она. И это еще не все.

В случае балансировки нагрузки по IP-адресу один из серверов непременно столкнется с мега-прокси (вроде AOL) и будет неспособен обслужить всю эту нагрузку самостоятельно. Кроме того, перевод серверов на новые версии приложения становится более сложным — необходимо либо ждать часами, пока пользователи закончат операции на веб-узле, либо раздражать этих пользователей, прерывая их сеансы. Становится проблемой и надежность: с потерей сервера теряется масса сеансов.

Устранение сходства является ключевой задачей распределения. Это требует вывода данных о состоянии сеанса из процесса, что означает уменьшение производительности ради увеличения масштабируемости. При выводе сеанса из процесса данные сеанса сохраняются там, где к ним могут получить доступ все веб-серверы — либо в SQL Server®, либо на сервере состояния ASP.NET. Это настраивается в web.config.

Поддержка внепроцессного сеанса также требует определенных усилий по написанию кода. Все классы, которые будут храниться в объекте Session («Сеанс»), следует пометить атрибутом Serializable («Сериализуемый»). Это значит, что все данные в классе должны быть либо сериализуемыми, либо помеченными как NonSerialized («Не сериализуемые»), чтобы класс был проигнорирован. Если не разметить классы, то возникнут ошибки при переносе сеанса сериализатором из процесса в хранилище.

Наконец, вывод сеанса из процесса является отличным способом обнаружить, что в объекте сеанса находится слишком много данных, поскольку теперь пользователю приходится расплачиваться за двукратное перетаскивание этой горы данных туда и сюда по сети (первый раз для получения ее в начале страницы, второй раз для возвращения ее в конце страницы) при каждом запросе страницы.

Разобравшись с объектом сеанса, переходите к другим проблемам сходства, таким как членство и диспетчер ролей. Каждая из них представляет свои сложности при устранении сходства. Но чтобы приложение ASP.NET действительно могло масштабироваться вверх, необходимо отловить все возможные формы сходства и устранить их.

Все стратегии, о которых рассказано к этому моменту, применимы для практически любого веб-приложения, нуждающегося в масштабировании. На самом деле, их можно применить к масштабированию практически любого приложения с использованием любой технологии. Теперь давайте взглянем на некоторые методики, уникальные для ASP.NET.


Сведение к минимуму объема полезных данных

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

Один из простейших способов уменьшить объем полезных данных — включить сжатие. В IIS 6.0 можно указать, следует ли сжимать статические файлы, динамически созданные ответы (страницы ASP.NET, например) или то и другое (см. рис. 4).

Рис. 4 Configuring Compression Server-Wide in IIS 6.0

IIS 6.0 сжимает статические файлы по требованию, сохраняя их в указанном кэше сжатых файлов. Для динамически созданных ответов копии не сохраняется, они сжимаются каждый раз. IIS 7.0 подходит к сжатию более разумно, сжимая только часто используемые файлы.

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

Другая область с богатыми возможностями уменьшения объема данных — состояние представления (ViewState). В ходе разработки использование состояния представления может запросто выйти из-под контроля. Большинство веб-элементов управления используют состояние представления в какой-то мере, так что на страницах, где их много, состояние представления может разрастись до тысяч байтов. Чтобы уменьшить использование состояния представления, отключайте его на элементах управления, когда оно не нужно. В некоторых случаях разработчики даже устраняют элементы управления, чтобы уменьшить состояние представления. Но это не всегда обязательно. Большинство современных веб-элементов управления чувствительны к проблеме избыточного состояния представления и предоставляют детальный контроль над его размером. Существует также оборудование, способное удалять и заменять состояние представления, не изменяя код или то, как работает приложение.

Одной из наиболее эффективных технологий уменьшения объема данных является AJAX. Если не считать, конечно, того, что AJAX, на самом деле, не уменьшает их объем — он просто уменьшает видимый объем полезных данных, увеличивая общее число байтов, отправляемых обозревателю. Использование AJAX делает родительскую страницу меньше, так что время первоначальной визуализации сокращается. Отдельные элементы на данной странице после этого направляют собственные запросы серверу для заполнения данных.

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

Если обращения AJAX к серверу для заполнения отдельных элементов заменяют запросы целых страниц, в итоге объем приемов-передач уменьшится. Но во многих случаях этот объем для каждого конкретного пользователя, наоборот, возрастает. Необходимо прилежное тестирование, чтобы узнать, улучшает ли AJAX производительность или понижает ее.

Кэширование

Специалисты по масштабированию приложений ASP.NET много говорят о кэшировании. В основе своей кэширование предназначено для перемещения данных ближе к пользователю. В типичном приложении ASP.NET до его оптимизации практически все данные, нужные пользователю, хранятся в базе данных и извлекаются из нее при каждом запросе. Кэширование изменяет это поведение. ASP.NET реально поддерживает три формы кэширования: кэширование страниц (также известное как выходное кэширование), частичное кэширование страниц и программное кэширование (также известное как кэширование данных).

Кэширование страниц намного проще остальных форм кэширования. Для его использования добавьте директиву @OutputCache к странице ASP.NET и включите правило, чтобы указать срок ее истечения. Например, можно указать, что страницу следует кэшировать в течение 60 секунд. При наличии такой директивы первый запрос страницы будет произведен как обычно и получит доступ к базе данных и прочим ресурсам, которые могут быть нужны для создания страницы. После этого страница удерживается в памяти веб-сервера 60 секунд, и все запросы к ней обслуживаются напрямую из памяти.

Увы, хотя этот пример и прост, он игнорирует фундаментальную истину кэширования страниц: практически не существует страниц ASP.NET, которые были бы достаточно статичны для кэширования их целиком на сколь-либо заметный промежуток времени. Здесь-то и помогает частичное кэширование страниц. С его помощью можно пометить части страницы ASP.NET как кэшируемые, чтобы вычислялись только регулярно изменяющиеся части. Этот метод более сложен, но эффективен.

Наибольшей, может быть, широтой возможностей (и наибольшей сложностью) отличается программное кэширование, уделяющее основное внимание объектам, используемым страницей. Наиболее распространенное использование программного кэширования — хранение данных, извлеченных из базы данных.

Наиболее очевидная проблема с кэшированием данных состоит в том, что нижележащие данные могут измениться после их кэширования. Истечение срока кэширования — это крупнейшая сложность при применении любой формы кэширования. Но необходимо также подумать и о памяти.

На загруженном сервере ASP.NET память становится существенной проблемой по ряду причин. При каждом вычислении страницы ASP.NET используется некоторое количество памяти. И Microsoft® .NET Framework настроена на очень быстрое выделение памяти, но сравнительно медленное ее высвобождение через сбор мусора. Рассказа о сборе мусора и выделении памяти .NET хватит на отдельную статью (написанную уже не раз). Достаточно сказать, что на загруженном веб-сервере 2 ГБ пространства памяти, доступных приложению ASP.NET, пользуются большим спросом. В идеале большая часть этого использования памяти является временным, поскольку память выделяется переменным и структурам, используемым при вычислении веб-страницы.

Но когда речь заходит о постоянных объектах памяти, подобных внутрипроцессному сеансу и объектам кэша, использование памяти создает куда больше проблем. И, само собой, эти проблемы всплывают только при серьезной загрузке приложения.

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

Когда общий процент используемой памяти приближается к пределу памяти кэша ASP.NET по умолчанию (90%), вызывается событие сборки мусора. Событие сборки мусора проходит по пространству памяти, перемещая вниз задержавшиеся в ней объекты (вроде объектов кэша и объектов сеанса) и освобождая более не используемую память (которая была задействована для вычисления веб-страниц). Освобождение неиспользуемой памяти происходит быстро — в отличие от перемещения задержавшихся объектов. Так что чем их больше, тем сложнее сборщику мусора выполнить его работу. Этот тип проблемы можно опознать в perform.exe по большому числу коллекций gen-2.

И помните, что пока идет сборка мусора, этот сервер ASP.NET не может обслуживать страницы; все остальное ждет в очереди, ожидая завершении процесса сборки мусора. А IIS наблюдает за этим. Если покажется, что процесс занимает слишком долго и, возможно, завис, то рабочий поток будет перезапущен. И хотя это очень быстро высвободит массу памяти, выбросив все эти задержавшиеся в памяти объекты, некоторые клиенты явно будут недовольны.

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

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

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

Возможно проблема состоит в схеме истечения срока кэширования: истечение срока по времени неудовлетворительно. Можно кэшировать число в каталоге до момента, когда кто-нибудь купит штуковину, после чего завершить пребывания объекта в кэше. Это более логично, но что произойдет при наличии более чем одного сервера ASP.NET? В зависимости от сервера, в каталоге будет указываться разное число штуковин. Если учесть, что получение нового каталога (добавляющего к цифрам) даже не пройдет через веб-приложение, то получается целый новый способ сделать все неправильно.

Синхронизация истечений срока кэширования между серверами ASP.NET возможна, но требует осторожности. Объем общения между веб-серверами возрастает в геометрической прогрессии по мере роста числа объектов кэша на них.

Также необходимо тщательно изучить влияние истечения срока кэширования на производительность. В условиях высокой загрузки истечение срока нахождения объекта в кэше может доставить массу неприятностей. Для примера, предположим, что имеется ресурсоемкий запрос, тратящий 30 секунд на возвращение из базы данных. В целях экономии ресурсов и потому, что в периоды нагрузки эту страницу запрашивают каждую секунду, запрос кэширован.

Код обработки объектов кэша довольно прост. Вместо извлечения данных из базы данных по мере нужды приложение сперва проверяет, заполнен ли объект кэша. Если да, оно использует данные из объекта кэша. Если нет, оно исполняет код для извлечения данных из базы и затем заполняет объект кэша этим данными, после этого продолжается нормальное исполнение кода.

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

А теперь пройдемся по этому случаю снова: приходит первый запрос, обнаруживает, что элемент кэша не заполнен, применяет блокировку к коду и выполняет запрос на заполнение объекта кэша. Второй запрос прибывает через секунду, пока первый еще работает, обнаруживает, что объект кэша не заполнен, но существует блокировка и блокируется. Как и следующие 28 запросов. Затем первый из них завершает свой процесс, снимает блокировку и продолжает. Что происходит с остальными 29 запросами? Они больше не блокированы, так что они также продолжают исполняться. Но они уже проверили объект кэша на заполненность (в момент, когда он не был заполнен). Так что они попытаются ухватить блокировку, одному это удастся, и он выполнит запрос снова.

Проблема ясна? Другие запросы, прибывающие после того, как первый запрос завершил заполнение объекта кэша, будут работать нормально, но запросы, прибывшие в ходе этого процесса, попадают в трудную ситуацию. Необходимо написать код для избежания этого. Если запрос сталкивается с блокировкой, то после ее отмены он должен проверить снова, не заполнен ли объект, как показано на Рис. 5. Скорее всего, теперь он заполнен, этим и было обусловлено само наличие блокировки. Хотя возможно и обратное из-за того, что какая-то другая часть кода вновь сделала объект кэша истекшим.

Рис. 5 Проверка, блокировка и повторная проверка объекта кэша

Написание хорошо работающего кода кэширования — трудная работа, но отдача может быть громадной. Однако кэширование повышает сложность, так что используйте его с умом. Убедитесь, что эта сложность даст реальные выгоды. Всегда тестируйте код кэширования для подобных сложных случаев. Что произойдет при нескольких одновременных запросах? Что произойдет при быстрых истечениях срока кэширования? Ответы на эти вопросы необходимо знать. Код кэширования должен решать, а не обострять проблемы масштабирования,.

Масштабирование баз данных

Нормальный подход к масштабированию веб-узлов — это добавление систем вместо их наращивания. В основном это обусловлено ограничениями потоков и памяти ASP.NET в сочетании с краткосрочной природой веб-запросов.

Однако, когда дело доходит до масштабирования баз данных, обычной практикой является наращивание — одна гигантская система, возможно две в кластере (хотя только одна реально несет на себе базу данных в каждый конкретный момент времени). Но рано или поздно каждое крупное веб-приложение доходит до стадии, когда одной базы данных недостаточно. Необходимо расширяться. Если возможно, достаточно применить те же стратегии масштабирования, что и к самому веб-приложению. Первым действием всегда является специализация — разбиение базы данных на логические разделы. Эти разделы могут быть основаны на разделении данных, возможно по регионам. В результате получится несколько баз данных, каждая из которых содержит часть изначальной базы данных. Например, один сервер будет содержать данные по восточному берегу США, а второй по западному берегу.

Однако действительно большие веб-приложения разделяют свои базы данных на базы чтения и записи (см. рис. 6). Базы данных чтения предназначены только для чтения, они получают свои данные от баз данных записи посредством репликации. Все запросы данных направляются базам данных чтения, оптимизированным на как можно более быстрое чтение данных. Базы данных чтения по своей природе легко распределяемы.

Рис. 6 Distributed Database Architecture

Все запросы на запись данных отправляются базам данных записи, которые разбиты на разделы и настроены на эффективную запись. Репликация перемещает новые данные с баз записи на базы чтения.

Создание таких специализированных баз данных ведет к задержке: у записи будет уходить некоторое время на распределение по базам данных чтения. Но если с задержкой удастся разобраться, то потенциал масштабирования огромен.

Бесконечная работа над масштабированием

Пока приложение продолжает расти, продолжит расти и работа по его масштабированию. Приемы ASP.NET, эффективно работающие с 10 000 одновременно подключенных пользователей, не так эффективны для 100 000, а для 1 миллиона пользователей правила меняются снова. Конечно, производительность может полностью зависеть от приложения, в некоторых из тех, что мы видели, проблемы с масштабированием начинались при менее чем тысяче пользователей!

Правило эффективного масштабирования — семь раз отмерь, один раз отрежь. Используйте тестирование, чтобы убедиться, что работа делается там, где нужно. Тестируйте свою работу, чтобы убедиться, что внесены улучшения, а не просто изменения. Даже в конце цикла разработки концентрируйтесь на оптимизации для масштабирования. Необходимо знать, где находятся самые медленные части приложения. Будем надеяться, они достаточно быстры для сегодняшних пользователей, позволяя работать над тем, что потребуется пользователям завтра.

Ричард Кэмпбелл (Richard Campbell) является региональным директором Майкрософт, обладателем звания MVP по ASP.NET и одним из ведущих ток-шоу с передачей звука через Интернет .NET Rocks для разработчиков для .NET (dotnetrocks.com). Он провел три года консультируясь с компаниями по вопросам производительности и масштабирования ASP.NET, а также является одним из основателей компании Strangeloop Networks.

Kent Alstad является техническим директором компании Strangeloop Networks (strangeloopnetworks.com) и основным автором либо одним из соавторов всех ожидающих регистрации патентов Strangeloop. Прежде чем принять участие в создании Strangeloop, он занимался созданием многочисленных высокопроизводительных, высокомасштабируемых приложений ASP.NET и консультациями по ним.

Ссылки по теме

Популярные статьи
Информационная безопасность Microsoft Офисное ПО Антивирусное ПО и защита от спама Eset Software


Бестселлеры
Курсы обучения «Atlassian JIRA — система управления проектами и задачами на предприятии»
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год. Электронный ключ
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2020. Все языки. Электронный ключ
Курс «Oracle. Программирование на SQL и PL/SQL»
Курс «Основы TOGAF® 9»
Microsoft Windows Professional 10 Sngl OLP 1 License No Level Legalization GetGenuine wCOA (FQC-09481)
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Windows Server 2020 Standard
Курс «Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации»
Антивирус ESET NOD32 Antivirus Business Edition
Corel CorelDRAW Home & Student Suite X8

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL