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

Что-то случилось...

... понял я, когда в час ночи зазвонил мой телефон. Сквозь сон я выслушал все новогодние "пожелания" заказчика и краткое описание проблемы - "Страница медленно работает". Затем пока нашел штаны, пока нашел где у меня ноги, пока оделся и, спустя часы, я оказался на работе. Нагрузочное (или даже стресc-тестирование) показало, что страница действительно забирает 90% процессорного времени при больших объемах данных на ней. После небольшого разбирательства выяснилось, что показания %Time in GC счетчика производительности меньше оптимальных. После чего наш консилиум заключил, что приложение нерационально использует оперативную память сервера.

MSDN говорит:

.NET CLR Memory\% Time in GC

Threshold: This counter should average about 5 percent for most applications when the CPU is 70 percent busy, with occasional peaks. As the CPU load increases, so does the percentage of time spent performing garbage collection. Keep this in mind when you measure the CPU.

Significance: This counter indicates the percentage of elapsed time spent performing a garbage collection since the last garbage collection cycle. The most common cause of a high value is making too many allocations, which may be the case if you are allocating on a per-request basis for ASP.NET applications. You need to study the allocation profile for your application if this counter shows a higher value.

За этим последовал небольшой code review, во время которого выяснилось, что приложение создает дофига коллекций. Коллекции использовались для переноса данных из BLL в Presentation Layer, и последующей конвертации их в DataTable (для байндига в GridView). Таким образом мы создали три анти-паттерна производительности (во завернул-то!): храним много данных в памяти, создаем большое количество циклов и конвертаций типов.

Пути решения

  • Байндить коллекции сразу GridView, без конвертации в DataTable
  • Создавать DataTable сразу из XML файла, минуя коллекции во избежания больших циклов  и конвертации типов
  • Использовать XSLT для трансофрмации XML в HTML таблицу (нафиг тогда вообще ASP.NET?)
  • Использовать Response.Write(), как это предлагает сделать Майкрософт

Решили попробовать последнее.

В результате получили следующее:

GridView Response.Write()
image_2 image_8

Интересные результаты, неправда ли? И хотя мы выиграли в производительности мы проиграли как минимум в удобстве и безопасности: GridView не просто рендерит таблицу, а и реализует некий функционал для управления и взаимодействия с данными в ней. А также делает проверки на cross-site scripting и другие виды атак. Так, что настаивать на Response.Write не буду. Решение использовать зависит от конкретной ситуации и пожеланий вашего заказчика.

Полезные ссылки

Improving ASP.NET Performance

Measuring .NET Application Performance

Code Review: .NET Application Performance