Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions case-study-template.md

This file was deleted.

65 changes: 65 additions & 0 deletions case-study.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Case-study оптимизации

## Актуальная проблема
В нашем проекте возникла проблема. Для создания отчета по пользовательским сессиям, было необходимо обработать файл большого размера (> 100 Mb). Существовал черновой вариант обработки файла на `ruby`, который работал при небольшом объеме информации, но не мог быстро (за время, которое бы команда могла дождаться) обработать целевой файл.
Было принято решение об оптимизации программы с использованием специальных инструментов и метрик.

## Формирование метрики
Для того, чтобы понимать, дают ли мои изменения положительный эффект на быстродействие программы я решил использовать такую метрику: время выполнения программы и объем потребляемой процессом памяти (и allocated objects - memory_profiler)

## Гарантия корректности работы оптимизированной программы
Программа поставлялась с тестом. Выполнение этого теста позволяет не допустить изменения логики программы при оптимизации.

## Feedback-Loop
Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный `feedback-loop`, который позволил мне получать обратную связь по эффективности сделанных изменений за несколько секунд - пару минут в зависимости от файла (некоторые файлы получились слишком большого объема, поэтому их пришлось сократить).

Вот как я построил `feedback_loop`:
- произвел небольшой рефакторинг скрипта (разбил на классы, вынес методы)
- сделал несколько файлов с разным объемом информации (разное число пользователей с их сессиями)
- прогонял скрипт, используя разные инструменты (StackProfiler, MemoryProfiler, Benchmark), вносил изменения, проверял, получилось ли оптимизировать согласно выбранным метрикам.

## Вникаем в детали системы, чтобы найти 20% точек роста
Для того, чтобы найти "точки роста" для оптимизации я воспользовался StackProfiler, MemoryProfiler, Benchmark.
Следующие проблемы удалось найти и решить:

№1
Использование bang методов вместо обычных для сокращения аллоцированной памяти и числа объектов. Другие небольшие поправки в виде frozen objects, изменения существующих строк, а не создание новых, убрал парсинг дат и т.д.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Этому описанию не хватает конкретных цифр, значений метрики до и после оптимизации.
С цифрами было бы более информативно, и понятно, какой эффект имела та или иная оптимизация.
Группировка нескольких правок в один пункт ещё сильнее смешивает оптимизации и не даёт понять эффект каждой отдельной.


№2
Обновление версии Ruby до 2.6.1 для использования метода split без инициализации дополнительного массива в памяти при парсинге пользователей и сессий.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Насколько помогло обновление версии Ruby?


user.delete_prefix!(USER_PREFIX).split(COMMA_SEPARATOR) do |atrribute|
result[USER_ATTRIBUTES[index]] = atrribute
index += 1
end

№3
Создание спарсеных пользователей и сессий и подсчет их количества во время считывания файла (избавления от времязатратного метода select при поиске связанных сессий)

File.open(file_name) do |f|
user = nil
f.each_line do |line|
if line.start_with?('user')
users_count += 1
users << user = User.new(attributes: Parser.parse_user(line))
else
parsed_session = Parser.parse_session(line)
user.sessions << parsed_session
sessions << parsed_session
sessions_count += 1
end
end
end

## Результаты
В результате проделанной оптимизации наконец удалось обработать файл с данными. Обработать целевой файл удалось за 34 с (самый быстрый прогон).
Удалось улучшить метрику системы для файлов с 4000 пользователями и 10000 пользователями с:
bench_report 16.701798 101.941843
до: 0.194868 0.448938

Число аллоцированных объектов также сократилось на сотни тысяч, объем RSS сократился примерно в 2.5 раза (для 10000 пользователей).

RSS для целевого файла колеблется в пределах 2.6-2.9 Gb.

## Защита от регресса производительности
Для защиты от потери достигнутого прогресса при дальнейших изменениях программы были добавлены тесты Minitest::Benchmark
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

18 changes: 18 additions & 0 deletions data2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
user,0,Leida,Cira,0
session,0,0,Safari 29,87,2016-10-23
session,0,1,Firefox 12,118,2017-02-27
session,0,2,Internet Explorer 28,31,2017-03-28
session,0,3,Internet Explorer 28,109,2016-09-15
session,0,4,Safari 39,104,2017-09-27
session,0,5,Internet Explorer 35,6,2016-09-01
user,1,Palmer,Katrina,65
session,1,0,Safari 17,12,2016-10-21
session,1,1,Firefox 32,3,2016-12-20
session,1,2,Chrome 6,59,2016-11-11
session,1,3,Internet Explorer 10,28,2017-04-29
session,1,4,Chrome 13,116,2016-12-28
user,2,Gregory,Santos,86
session,2,0,Chrome 35,6,2018-09-21
session,2,1,Safari 49,85,2017-05-22
session,2,2,Firefox 47,17,2018-02-02
session,2,3,Chrome 20,84,2016-11-25
Loading