Skip to content

Latest commit

 

History

History
79 lines (57 loc) · 6.84 KB

File metadata and controls

79 lines (57 loc) · 6.84 KB

Case-study оптимизации

Актуальная проблема

В нашем проекте возникла серьёзная проблема.

Необходимо было обработать файл с данными, чуть больше ста мегабайт.

У нас уже была программа на ruby, которая умела делать нужную обработку.

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

Я решил исправить эту проблему, оптимизировав эту программу.

Формирование метрики

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

Гарантия корректности работы оптимизированной программы

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

Feedback-Loop

Для того, чтобы иметь возможность быстро проверять гипотезы я выстроил эффективный feedback-loop, который позволил мне получать обратную связь по эффективности сделанных изменений за время, которое у вас получилось

Вот как я построил feedback_loop: как вы построили feedback_loop

Вникаем в детали системы, чтобы найти главные точки роста

Для того, чтобы найти "точки роста" для оптимизации я воспользовался инструментами, которыми вы воспользовались:

  • добавил прогрессбар, понять, что нет смысла ждать, когда доедет до конца
  • добавил ассерты, по которым принял решение, что будут укладываться по времени в нужный нам бюджет
  • Добавил ruby-prof и на основе мини файла проверил, как распределяется нагрузка у программы

Вот какие проблемы удалось найти и решить

Ваша находка №1

  • parser_progressbar, показал что огромную часть времени занимает парсинг строк (более 10 минут, хотя должно быть менее 30 секунд)
  • вместо сложения массивов использовал Array#push элемента в существующий массив
  • уменьшил с >10 мин до 70с
  • перестала быть главной точкой роста ибо у users.each (прогрессбар показывает более 4 дней выполнения)

Ваша находка №2

  • Подсчёт количества уникальных браузеров занимает времени больше чем 30с, значит в любом случае нужно оптимизировать
  • сгруппировать по ключу "браузер" и взять только ключи
  • 30c изменилось на моментальную

  • перестала быть главной точкой роста

Ваша находка №3

  • Сбор браузеров занимает около 1.5 минуты
  • использовать результат полученный ранее и вывести в строку
  • 1.5мин изменилось на моментальную

  • перестала быть главной точкой роста

Ваша находка №4

  • users.each (прогрессбар показывает более 4 дней выполнения)

  • сгруппировал сессии по user_id вне массива, чтоб не заниматься этим каждый раз, по мимо этого изменил формат добавления в user_objects использую оператор "<<" вместо сложения сумм массивов

  • изменилась с >4 дней до 52c (Группировка сессий - 43c, Сбор cтатистики по пользователям - 9c)

  • перестала быть точкой роста

    Ваша находка №5

    • парсинг строк (file_lines.each) показал что работа составляет около 1 минуты и 4с что больше чем 30с
    • вместо сложения массивов использовал Array#push элемента в существующий массив
    • уменьшил с >10 мин до 7c
    • перестала быть главной точкой роста

    Ваша находка №6

    • метод collect_stats_from_users на данный момент занимает около 33с работы от 41с вообщем
    • добавил предварительные вычисления, теперь все данные для пользователя собираются в одном хеше и сразу обновляют соответствующую запись
    • уменьшил с 33с до 15.30c
    • перестала быть главной точкой роста

Результаты

В результате проделанной оптимизации наконец удалось обработать файл с данными. Удалось улучшить метрику системы с так называемой бесконечности(не смог дождаться завершения) до 17-18 секунд и уложиться в заданный бюджет.

Какими ещё результами можете поделиться

Защита от регрессии производительности

Для защиты от потери достигнутого прогресса при дальнейших изменениях программы добавлен тест о том, что он должен выполняться быстрее 30с