Sergii Tsypanov: "Tricky enterprise"
-
Upload
logeeknightukraine -
Category
Technology
-
view
91 -
download
1
Transcript of Sergii Tsypanov: "Tricky enterprise"
www.luxoft.com
TRICKY ENTERPRISE
www.luxoft.com
Пара слов обо мне
- работаю в «Люксофте» с 2013 г.
- пишу на Java
- люблю разбираться с проблемами производительности
Связаться со мной можно
- написав на корпоративную почту [email protected]
- написав на личную почту [email protected]
- написав ВК https://vk.com/sergei.tsypanov
- написав ФБ https://www.facebook.com/sergei.tsypanov
www.luxoft.com
Вычислительная сложностьКаноническое определение звучит так:
Вычислительная сложность — понятие в информатике и теории алгоритмов, обозначающее функцию зависимости объёма работы, которая выполняется некоторым алгоритмом, от размера входных данных.
https://ru.wikipedia.org/wiki/Вычислительная_сложность
www.luxoft.com
Итак, разминка
Ваши мысли?
www.luxoft.com
А так?
Для пропуска if-блока необходимо и достаточно, чтобы один из операндов был false
www.luxoft.com
Меняем порядок операндов
… а запрос обернём в предикат (можно и в метод, но предикат – это функционально, стильно, модно, молодёжно)
www.luxoft.com
Пример посерьёзнее
В базу один за другим летят три запроса, при том, что далеко не всегда все три необходимы.
www.luxoft.com
Почему так? Или пятиминутка скучной теории
В худшем случае мы ничего не теряем
В лучшем случае достаточно вызвать лишь одни метод
www.luxoft.com
Так лучше
www.luxoft.com
1 ПРАВИЛО КЛУБА:
ЕСЛИ МЕДЛЕННОЕ ДЕЙСТВИЕ МОЖНО ОТЛОЖИТЬ – ОТЛОЖИ ЕГО.ВОЗМОЖНО, ДЕЛАТЬ ЕГО ВОВСЕ НЕ ПРИДЁТСЯ.
Действия лучше выполнять в порядке возрастания их сложности.
www.luxoft.com
Едем дальше
«Понабирали по объявлению» (с)
www.luxoft.com
Присмотрись внимательнее
Количество обращений к репозиторию равно количеству DTO в списке
Чтобы отбросить повторяющиеся сущности, используется Set
Множественные запросы к БД?
HashSet там где достаточно ArrayList-а?
Не отчаивайся, %USERNAME% $USER, выход есть
www.luxoft.com
Грузите апельсины бочками
Посчитаем для списка из 10 ID…
www.luxoft.com
Разница почти в 10 раз
Запросы в цикле
Один запрос
www.luxoft.com
Почему так? Или пятиминутка скучной теории
Что происходит под капотом?
1 Получаем сессию2 Открываем транзакцию
3 Работаем
4 Завершаем транзакцию
5 Закрываем сессию
Это шаблон session-per-request (https://developer.jboss.org/wiki/Sessionsandtransactions)
www.luxoft.com
Почувствуйте разницу…
Пять указанных шагов выполняются при каждом вызове repository.findOne(),
т. е. вычислительная сложность равна О(n)
При вызове repository.findAll(Iterable<ID>)
пять указанных шагов выполняются всегда один раз,
т. е. вычислительная сложность равна О(1)
www.luxoft.com
2 ПРАВИЛО КЛУБА:
ГРАБЬ, ВОРУЙ, …
СОБИРАЙ И ВЛАСТВУЙ.
Однотипные действия, которые выполняются в цикле, часто можно выполнить за один проход, особенно когда речь идёт о запросах в БД.
www.luxoft.com
Внезапно вернёмся к первому примеру
Таким мы его запомнили:
www.luxoft.com
А что если…
…его можно сделать ещё чуточку лучше?
Самую малость…
www.luxoft.com
А что это у нас в третьей строке?
У свеженайденной сущности мы берём сущность-дочку, а потом – сущность-внучку.
…дочка за внучку, внучка за Жучку, и вытащили они – нет, не репку, – а полновесный OutOfMemoryError…
www.luxoft.com
Шутка,
OutOfMemoryError на таком примере не выловить, однако это вполне жизненный пример анти-паттерна под замысловатым названием Circuitous Treasure Hunt.
Его определение: Occurs when an object must look in several places to find the information that it needs. If a large amount of processing is required for each look (i. e. a database access), performance will suffer.
Способ борьбы прост: не размазывайте логику.
www.luxoft.com
Выход есть
Достанем рейтинг напрямую, минуя дочку и внучку
Подправим предикат
www.luxoft.com
Измерим
До
После
www.luxoft.com
Чё, 90 миллисекунд? Серьёзно?
www.luxoft.com
Пятиминутка арифметической объективности
1 проход = 90 мс ≈ 1 фигня
10 проходов= 900 мс ≈ 1 с
100 проходов= 9000 мс = 9 с
1000 проходов= 90000 мс = 90 с = 1,5 минуты
С уважением,
ваш Кэп
www.luxoft.com
3 ПРАВИЛО КЛУБА:
КОСИ И ЗАБИВАЙ …
НЕ ДЕЛАЙ ЛИШНЮЮ РАБОТУ ТАМ, ГДЕ ЕЁ МОЖНО НЕ ДЕЛАТЬ.
ДЕЛАЙ ВСЁ В ОДНОМ МЕСТЕ.
www.luxoft.com
Несложный, но важный пример
www.luxoft.com
Что скажете?
отсеиваем лишнее
и ещё раз отсеиваем лишнее
А теперь, внимание, вопрос.
Что мешает выбрать нужные данные сразу?
Можете ли вы с первого взгляда понять, что делают последние 3 строки?
www.luxoft.com
Переложим логику на мощные плечи БД
Обратите внимание, насколько лаконичнее и выразительнее стал код
www.luxoft.com
4 ПРАВИЛО КЛУБА:
НЕ ДЕЛАЙТЕ ТОГО, ЧТО МОЖЕТ ЗА ВАС СДЕЛАТЬ БД.
Если задача состоит в поиске данных и отсеивании лишнего – делайте это с помощью базы. Она специально заточена под это.
www.luxoft.com
На мой взгляд, самый необычный пример
www.luxoft.com
Внезапно
Транзакция открывается как для «хороших», так и для «плохих» данных.Если данные плохие, то транзакция тут же откатывается.
А зачем нам в таком случае транзакция?
Achtung !!!
www.luxoft.com
Что можно с этим сделать?Испечём «Наполеон»: всю транзакционную логику перенесём во внутренний сервис, а всю логику проверки оставим во внешнем сервисе:
Транзакция открывается только тогда, когда она необходима
www.luxoft.com
Считаем
До
После
www.luxoft.com
«Наполеон», он же шаблон Service Layers
https://en.wikipedia.org/wiki/Service_layers_pattern
• проще писать
• легче читать
• проще тестировать
• легче поддерживать
• проще рефакторить
И это просто вкусно
www.luxoft.com
5 ПРАВИЛО КЛУБА:
РАЗДЕЛЯЙ И ВЛАСТВУЙ.
УВЕЛИЧИВ КОЛИЧЕСТВО СЛОЁВ, ПРИЛОЖЕНИЕ ЛЕГЧЕ ТЕСТИРОВАТЬ И ОНО (В НЕКОТОРЫХ СЛУЧАЯХ) СТАНОВИТСЯ БОЛЕЕ ОТЗЫВЧИВЫМ.
www.luxoft.com
Лирическо-логическое отступление[режим-капитана-очевидности-вкл]
В JVM существует сборщик мусора (СМ), который включается, когда приложению не хватает памяти.
Иногда работа СМ приводит к stop-the-world задержкам в работе приложения.СМ освобождает память и не даёт приложению голодать, но всё имеет свою цену.В обмен на помощь в освобождении памяти СМ берёт дань процессорным временем.
Таким образом, если доступная вычислительная мощность равна 1, а СМ отнимает у нас х, то приложению остаётся лишь 1 - х вычислительной мощности.
Отсюда вывод: производительность можно повысить, если уменьшить дань, забираемую СМ
[режим-капитана-очевидности-выкл]
www.luxoft.com
Немного отвлечёмся от вычислительной сложностиНебольшое пояснение: это общий предок для около 50 сущностей одного из наших приложений.Метод includeInAudit() вызывается при изменении значений некоторых полей, и вызывается он очень часто
www.luxoft.com
Вернёмся к нашим баранамНа основе реальных событий: в результате 1 действия 1 пользователя данный метод вызывается 3,5 тыс. раз
И при каждом вызове метода создаётся HashSet…
www.luxoft.com
Пятиминутка арифметики:
Пустой HashSet в 64-разрядной JVM «весит» 240 байт*.
Путём сложнейших вычислений определим, что 3,5 тыс. пустых (берём по нижней границе) HashSet-ов «весят» 820 кБ.
И это 1 действие 1 пользователя…
* Накладные расходы памяти у коллекций https://habrahabr.ru/post/159557/
www.luxoft.com
Присмотримся внимательнее…и обнаружим, что по завершении цикла переменная drafts может иметь только 4 состояния:
• пустая коллекция
• коллекция, содержащая OLD_DRAFT
• коллекция, содержащая NEW_DRAFT
• коллекция, содержащая обе записи
www.luxoft.com
Перепишем определим все
возможные состояния
вместо добавления объектов
используем уже созданные коллекции
www.luxoft.com
6 ПРАВИЛО КЛУБА:
ЧИСТО НЕ ТАМ, ГДЕ УБИРАЮТ,А ТАМ, ГДЕ НЕ МУСОРЯТ.
Кэшируйте всё, что можно и не превращайте приложение в помойку.
www.luxoft.com
СПАСИБО ЗА ВНИМАНИЕ
И ДЕРЖИТЕ ПОРОХ СУХИМ БАЗУ ПРОГРЕТОЙ