Когда мы говорим о Ruby on Rails, мы имеем в виду основной MVC-фреймворк Ruby, который содержит все части полноценного приложения, как на front-end, так и на back-end.
Когда мы добавляем больше расширений или данных в наше приложение Rails, все начинает становиться немного более «трудоемким» для запуска, и с помощью гема, который мы рассмотрим сегодня, мы можем легко реализовать и заметить разницу в загрузке приложения Rails.
Итак, давайте воспользуемся расширением/гемой под названием Bootsnap, разработанным компанией Shopify.
Согласно некоторым тестам, гем обещает сделать запуск любого приложения Rails или Ruby на 50% быстрее, без ущерба для функциональности или активов внутри приложения Rails.
За кулисами гем делает то, что использует язык C для исправления файлов Ruby, и с помощью этого мы можем значительно уменьшить время загрузки приложения.
Итак, прежде чем мы углубимся в то, как улучшить производительность приложения, давайте по частям разберем, как работает инициализация.
Когда мы запускаем rails console
или rails server
для запуска приложения Rails, мы вызываем порядок, в котором пакеты, файлы и конфигурации запускаются в следующем порядке:
bin/rails → Gemfile → boot.rb → config/application.rb
→ На экране отображается сообщение об основном сервере
→ config/environments/development.rb
→ Файлы, находящиеся в папкеinitializer
.
→ config/routes.rb
→ config/environment.rb
→ config.ru (если есть)
Выше я вкратце описал процесс создания загрузочных файлов, если вы хотите глубже понять, что содержит каждый файл и как он работает, перейдите по этой ссылке из руководства Ruby on Rails Guide.
Сначала, когда выполнение попадает в Gemfile, Rails загружает все расширения, содержащиеся в этом файле, помимо своих собственных движков, а именно:
- Actioncable
- Actionmailer
- Actionpack
- Actionview
- Activejob
- Activemodel
- Activerecord
- Activestorage
- Активная поддержка
- Actionmailbox
- Actiontext
Чтобы загрузить эти и другие расширения, Rails как будто спрашивает компьютер, доступно ли требуемое расширение в определенном каталоге, если нет, то он продолжает обход каталогов и выполнение продолжается только тогда, когда каталог найден.
Важным изменением, которое гем Bootsnap включает в наше Rails-приложение, является создание кэша внутри каталога tmp/cache/
приложения, с файлом, содержащим все предварительно установленные пути, таким образом, когда мы инициализируем наше приложение, этот шаг по требованию всех файлов сразу является гораздо меньшей работой.
Чтобы использовать этот гем, нам сначала нужно объявить его в Gemfile##code>:
# Gemfile
gem 'bootsnap', require: false
После выполнения bundle install
нам нужно потребовать этот гем в файле config/boot.rb
сразу после require 'bundler/setup'
:
# ./config/boot.rb
ENV['BUNDLE_GEMFILE'] ||= File.expand.path('../Gemfile', __dir__)
require 'bundle/setup'
require 'bootsnap/setup'
И это все! Теперь приложение готово к повторному запуску.
Для сравнения я буду использовать в этом примере Rails-приложение, уже созданное в моей локальной среде, чтобы проиллюстрировать реальную разницу между приложением с загрузкой "по умолчанию" и затем, с использованием гема Bootsnap.
Проверка различий
Давайте приступим к тестированию, для этого сначала я создам файл типа Shell Script (.sh
), чтобы я мог вызвать вызов rails runner
с помощью команды терминала time
.
#!/usr/bin/env bash
rails runner "puts Tillage.count"
По сути, этот сценарий будет подсчитывать количество записей, поступающих из модели Tillage
моего приложения, поэтому сначала мы запустим этот сценарий без Bootsnap:
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 15855
1028
./test/script.sh 1.05s user 0.69s system 31% cpu 5.482 total
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 16135
1028
./test/script.sh 0.70s user 0.48s system 79% cpu 1.483 total
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 16416
1028
./test/script.sh 0.70s user 0.53s system 75% cpu 1.615 total
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 16695
1028
./test/script.sh 0.77s user 0.52s system 82% cpu 1.562 total
Мы можем заметить, что выполнение в среднем заняло 1,5 с (без учета первого запуска).
Теперь перейдем к тесту Bootsnap:
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 8567
28
./test/script.sh 0.66s user 0.44s system 81% cpu 1.360 total
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 8847
28
./test/script.sh 0.66s user 0.44s system 80% cpu 1.372 total
➜ solocamp-tech git:(master) ✗ time ./test/script.sh
Running via Spring preloader in process 9128
28
./test/script.sh 0.67s user 0.47s system 80% cpu 1.408 total
Мы видим, что время выполнения уменьшилось, в данном примере разница не очень большая, но нам удалось сохранить среднее значение в 1,3 с для каждого выполнения.
Если бы сценарий был больше, то есть если бы он включал больше подсчетов из других моделей, эта разница была бы намного больше!
Таким образом, мы можем заметить, что чем больше приложение Rails, тем больше разница между временем загрузки Bootsnap!