2. Нетривиальные ботлнеки Как искать и находить проблемы с памятью и производительностью в высоконагруженных .Net приложениях,которые уже якобы до конца оптимизированны.
3. О самых распространённых, но скрытых проблемах. Об оптимизации уже существующих приложений. Тривиальные проблемы. Нетривиальные проблемы. О том, как быстро найти тормозное место. И о всяком другом помаленьку... О чём это всё?
5. Кто хоть иногда чинит скорость работы кода? Кто хоть иногда чинит количество занимаемой памяти? О вас
6. Обсудим как улучшать существующее, а не о том как надо правильно разрабатывать новое. Внутренние тормоза DB/SQL или Apache/IIS здесь разбираться не будут. Это архитектурные проблемы, а не кодерские. О презентации
7. Узкое место Проблема Oптимизация ... спрашивайте меня, будем определяться по ходу. Определимся с терминами
8. Частые обращения к вычисляемым данным Один поток Долгоиграющая операция не зависящая от нас Медленный SQL скрипт Прокси/очередь сообщений Много итераций/выделений памяти Бесполезное исполнение кода/выделение памяти Медленный алгоритм Банальные ботлнеки
9. Нетривиальный ботлнек №1 Сохранение данных в хранилище (файл) длилось 2-3 минуты. Размер файла был огромен – гигабайты. Чтение, соответственно, тоже самое. Во время сохранения выделялось огромное количество памяти.
11. Решение: рукописная сериализация. Вывод: бинарная сериализация в .Net – Нетривиальный ботлнек №1 Сохранение данных в хранилище (файл) длилось 2-3 минуты. Размер файла был огромен – гигабайты. Чтение, соответственно, тоже самое. Во время сохранения выделялось огромное количество памяти.
12. Решение: найти повисший указатель. Нетривиальный ботлнек №2 Почему-то память не высвобождалась.
15. Решение: найти повисший указатель. Вывод: static – Нетривиальный ботлнек №2 Почему-то память не высвобождалась.
16. Решение: создать единое универсальное хранилище информации. Вывод: не храните дважды одно и тоже. Доступ к данным можно всегда ускорить. Нетривиальный ботлнек №3 Приложение занимало много памяти. Хранение одной и той же информации в двух разных видах. Это делалось для быстрого поиска необходимого.
17. Решение: вычислять только необходимое. Нетривиальный ботлнек №4 Вычислялись цифры, которые впоследствии никуда не выводились.
19. Решение: вычислять только необходимое. Вывод: не ленитесь создавать отдельные запросы для отдельных нужд. Нетривиальный ботлнек №4 Вычислялись цифры, которые впоследствии никуда не выводились.
20. Решение: попробовать не вычислять её. Нетривиальный ботлнек №5 Для вычисления одной из 10 цифр использовалось 50% памяти и 90% CPU.
21. - Hi, Nikolaj. Do you think “Value X” is that necessary? The matter is, it takes 50% of RAM and 90% of CPU. Can we remove it? - Hi, Vasiliy. Sure, get rid of it! Разговор с Product Specialist Эта цифра бесполезна!!!
22. Решение: попробовать не вычислять её. Вывод: нужно знать специфику пользователей, их стандартные User Cases. Нетривиальный ботлнек №5 Для вычисления одной из 10 цифр использовалось 50% памяти и 90% CPU.
23. Решение: переписать Dictionary -> стало занимать в 2,5 раз меньше памяти. Вывод: используйте оптимальное правильное хранилище для данных. Нетривиальный ботлнек №6 Всё ещё отжирает кучу памяти. Оказалось, что самый ресурсоёмкий класс в системе был Dictionary<int, int>.
24. Решение: Перевести на потоковое чтение данных. Нетривиальный ботлнек №7 Часто выделялись и освобождались ненужные куски памяти. Иногда выделяется ещё 200% к уже выделенной памяти.
25. int[] a1; int[] a2; // Проще всего написать вот так: publicIEnumerable<ItemClass> GetItemsByCondition() { List<int> result = newList<int>(); result.AddRange(this.a1.Where(item => ...condition...)); result.AddRange(this.a2.Where(item => ...condition...)); returnresult; } // А надо бы вот так: publicIEnumerable<ItemClass> GetItemsByCondition() { foreach(var item inthis.a1) if(...condition...) yieldreturn item; foreach(var item inthis.a2) if(...condition...) yieldreturn item; } Например, выбрать элементы по условию
26. Решение: Перевести на потокровое чтение данных. Вывод: создавайте как можно меньше коллекций. Нетривиальный ботлнек №7 Часто выделялись и освобождать ненужные куски памяти. Иногда выдеяется ещё 200% к уже выделенной памяти.
27. 0) Найти узкое место. 1) Узнать, нужна ли эта функция пользователю? 2) Нужно ли вызывать именно это место для достижения результата? 3) Как можно сократить количество итераций? 4) Оптимизировать код. Алгоритм борьбы с проблемами
28. Redgate ANTS – $ JetBrains dotTrace – $ Scitech Memory Profiler - $ EQATEC Profiler – $ nProf – free!!! SlimTune – free!!! ... И т.д. И т.п. И пр. Профайлер
29. Redgate ANTS –$400-$800 (удобный, точный, быстрый, много фичей, самый популярный из всех) JetBrains dotTrace –$400-$800 (чуть менее удобный,чуть менее точный, быстрый, много фичей, free для OpenSource) Scitech Memory Profiler – $100-$300(толко для памяти, много фичей, чуть менее удобный) EQATEC Profiler – $150-$400 (быстрый, память не профайлит, менее точный, free для некоммерческих целей) nProf – free!!! (но не поддерживается уже 2 года, или больше) SlimTune – free!!! (но нифига не понятно как им пользоваться, сложный интерфейс) Профайлер
Разрабатываю десктопное приложение, которое загружает в себя миллиард записей из базы данных, где каждая запись - минимум 150 байт. Итого имеем 150ГБ. Хотя нашими усилиями оно занимает всего 0,5ГБ.Когда мы только получили приложение на доработку (как всегда да? украинцы переделывают чье-то плохой в хорошее), каких-то там миллион записей съедал 4ГБ ОЗУ и обрабатывался 6 часов.Сейчас эта же операция занимает 5-10 минут и съедает до 20МБ.
Здесь будут высказаны несколько полезных идей, которые должны натолкнуть вас на идею по улучшению продукта, над которым вы сейчас работаете.На этой презентации не будет банальщины вроде "Сервер перегружен запросами, что делать?" или "БД не справляется, как переписать SQL скрипт?". Ответы на подобное очевидны. На этой презентации вы узнаете как оптимально оперировать с большими объемами информации в памяти. Разбираться будет тот момент, когда вы определили, что узкое место не IIS/Апач или БД, а какой-то C# код.
Узкое место - не всегда проблема.Проблема – не всегда узкое место.Например, если приложение стартует довольно долго, то это мало кого волнует, ибо одноразово и пользователя не напрягает особо.Или идёт длительная работа с данными, результат которой потом игнорируется. Зачем тогда оптимизировать код, если его можно вообще выкинуть?Оптимизация - это выбор правильного оператора (типа for или foreach). НЕТ! Оптимизация - это сокращение количества итераций.
Хранение одной и той же информации больше одного раза.Во-первых поддержка нескольких хранилищ - это гемор по синхронизации и доступу. Во-вторых при больших объемах экономится куча памяти. Даже если две копии дублируют между собой 50% информации - уже пора избавляться.Сложность здесь в том, что нужно очень хорошо продумать хранилище. Доступ должен быть быстрым и удобным. Можно даже кеширование прикручивать.
Где можно string заменяйте на int (например номера телефонов, или глобальные координаты)
Например с байтовых буферов перевести на Stream.
Есть у нас две коллекции.И надо из них выбрать элементы по спец. условию.Но здесь мы СОЗДАЛИ НОВУЮ коллекцию. Создание – это и есть проход по новой коллекции. Потом есть второй проход по коллекции, собсно чтение новой коллекции.А во втором случае, коллекции нет первого прохода, сразу второй. И память экономим.
Например с байтовых буферов перевести на Stream.
Это основной слайд презентации.Итак, есть проблема от продакт специалистов – тупит! Алгоритм решения этой проблемы следующий...