Инфраструктура Ruby on Rails

8 Июл
2009

С Ruby on Rails в рунете сложилась непростая ситуация: вроде, есть блогеры, о нем пишущие, есть специализированные сайты, но почему-то людям, желающим попробовать рельсы и начинающим rails-разработчикам, найти полезную информацию по Rails крайне трудно.

Знаете, что происходит в итоге? Рождается масса заблуждений препятствующих распространению мощной технологии. Например:

  • «Гибкая разработка веб-приложений в среде Rails» — лучшая книга для любого Rails-разработчика» — бред собачий! Это книга «для чайников», не отражающая реалий rails-разработки.
  • «Rails — это вещь в себе» — еще больший бред. Rails, вообще-то, обладает мощной инфраструктурой, включающей множество сторонних сервисов и библиотек.

Тестирование и непрерывная интеграция, отладка и профилирование, автоматизация проверки качества кода, выполнение асинхронных задач, развертывание приложения на серверах и его мониторинг — все это примеры типичных задач в разработке и поддержке серьезых веб-приложений, которые в Rails обычно решаются отнюдь не штатными средствами, но мощными сторонними решениями, являющимися частями инфраструктуры Rails.
Давайте же рассмотрим инфраструктуру подробнее.

Развертывание приложения

В Ruby есть очень мощный инструмент для работы с удаленными unix-серверами — Capistrano. Он же является стандартом де-факто для развертывания рельсов на production/staging серверах.

Принцип работы Capistrano в контексте рельсов простой — разработчик с локальной машины запускает capistrano, который в свою очередь подсоединяется к удаленному серверу через SSH и выполняет ряд команд: вытягивает свежую версию приложения из репозитория, создает для нее отдельную директорию и устанавливает символические ссылки для директорий со статическим контентом, перегружает веб-сервер и другие сервера (например, сервер для полнотекстовой индексации и поиска данных). Большим плюсом Capistrano в сравнении с аналогичными инструментами является поддержка rollback'ов. То есть в случае неудачного развертывания проекта Capistrano откатит все в исходное состояние.

Выше описан простейший пример работы Capistrano, который обычно выполняется с помощью его стандартных рецептов (скриптов). Вообще же с помощью капистрано можно можно разворачивать приложения в нескольких окружениях, можно разворачивать приложения сразу на кластерах серверов, можно на этих кластерах удаленно чистить кеш и вообще выполнять любые команды, которые можно выполнить в консоли unix-сервера. Существуют отдельные наборы рецептов капистрано, например capistrano-ext, Dump или rubaidhstrano, позволяющие автоматизировать резервное копирование баз данных и синхронизировать статические файлы (как и базы данных) в локальном окружении разработчика с production'ом.

Кстати, capistrano совсем не обязательно использовать с рельсами, впервые я с ним столкнулся полтора года назад, тогда с помощью Capistrano мы разворачивали PHP(symfony)-приложения на кластерах серверов.

Нет предела совершенству. В след за Capistrano появились проекты Shadow Puppet и Moonshine. Shadow Puppet — это инструмент для автоматизации настройки самих unix-серверов, с его помощью можно автоматизировать установку всего софта, библиотек, создание пользователей, настройки безопасности — очень полезный инструмент системного администратора. Moonshine представляет собо надстройку над Capistrano и Shadow puppet, позволяющую автоматически настроить «голый» удаленный сервер и развернуть на нем Rails-приложение, имея на удаленном сервере всего лишь пользователя с sudo-правами. К сожалению, в настоящий момент Moonshine поддерживает только Ubuntu Server 8.10 и Git-репозитории.

Существует альтернатива Capistrano — Vlad the Deployer, он проще в использовании, но на фоне Capistrano функционал Влада кажется скудным.

Профилирование, мониторинг производительности, слежение за ошибками

Представим, что вы запустили свой rails-проект. Он оказался настолько удачным, что новость о нем появилась на главной странице Wired или Digg. После чего проект в лучшем случае стал работать очень-очень медленно, в худшем же просто повалился нахуй. После этого работа резко принимает авральный характер, вы анализируете тонны логов, заново прогоняете стресс-тесты и прочими способами пытаетесь найти узкие места в системе и устранить проблемы.

Задачу профилирования и мониторинга производительности решают такие сервисы, как Five Runs, New Relic и Scout. Функциональность у всех трех похожа, потому расскажу о таких средствах на примере NewRelic'а, являющегося лидером тройки.

Когда приложение развернуто в production-окружении, начинает работать специальный rails-плагин NewRelic RPM. Он собирает информацию о каждом запросе к приложению, о каждом запросе к базе данных, времени выполнения этих запросов (и, соответственно, времени загрузки страниц), нагрузке на процессор, вызванной этими запросами. Время от времени эти данные отправляются на сервер NewRelic фоновым процессом. После этого на сайте NewRelic'а можно посмотреть множество отчетов, показывающих, например, самые медленные контроллеры, самые медленные SQL-запросы и отдельные транзакции, причем, легко можно посмотреть использование индексов в запросах. Кроме того, NewRelic хранит статистику, потому можно отслеживать динамику нагрузок, удобно сгруппированные отчеты об ошибках (мы же не хотим читать длинные логи?) и многое другое.

Естественно, можно использовать NewRelic и в development-окружении, в этом случае он является больше инструментом профилирования, нежели мониторинга и статистики.

Для тех, кому не нужна настолько подробная (и дорогая) статистика, которую дает NewRelic, но нужно удобно отслеживать ошибки, происходящие на production-серверах, есть простой сервис — HopToad. Можно, конечно, для этой цели пользоваться rails-плагином с говорящим именем «Exception Notifier», но он может в определенных ситуациях может неприятно заспамить ваш почтовый ящик.

Тестирование, проверка качества кода

Честно говоря, автоматическое тестирование — один из моих любимых аспектов Rails, такое обилие разнообразных крутых инструментов тестирования я видел, пожалуй, только в Java.

По умолчанию рельсы используют стандартный рубишный Test::Unit в качестве тест-фреймворка. Однако, в последнее время все более модным становится т.н. Behavior Driven Development, и в руби появился свой BDD-фреймворк — RSpec, который плотно интегрируется с рельсами. Судя по коду разных современных проектов, RSpec в ruby-мире сейчас даже более популярен, чем Test::Unit.

В RSpec входит собственное средство для создания mock-объектов (необходимых, например, при тестировании контроллеров), однако вместо него можно использовать более развитые Mocha и Flex Mock.

С целью минимизации времени, затрачиваемого на рутинное написание тестов, был разработан Shoulda — набор макросов для совместного использования Rails и Test::Unit. Посмотрите, насколько более простым и читабельным он делает код тестов.
Специально для людей, предпочитающих RSpec был выпущен аналог Shoulda под названием Remarkable.

Для заполнения приложения тестовыми данными в рельсах по умолчанию применяется механизм fixtures, однако это не всегда удобно, например, в случаях, когда нужно сгенерировать много сущностей, — в таких случаях на помощь приходит генерация через фабрики объектов, наиболее известным средством для этого в рельсах является factory_girl.

Хотите «настоящего» BDD, чтобы можно было описывать требования к будущему функционалу простым языком и в итоге превращать их в функциональные/интеграционные тесты? — попробуйте Cucumber.
Если вам, как и мне, Cucumber кажется излишеством, существует другой мощный инструмент — WebRat. Задача «крысы» — интеграционное тестирование, то есть пройтись по страницам сайта, прокликать формы, убедиться в том, что сервер вернул ожидаемый результат. Сценарии WebRat писать очень просто и он интегрируется с любыми тест-фреймворками для Ruby. В обычном режиме работы WebRat'у даже не нужен броузер для прогона тестов. Однако бывают ситуации, когда нам необходимо тестировать операции, выполняемые JavaScript'ом, в этом случае WebRat можно запустить в другом режиме работы: он будет использовать Selenium(который, в свою очередь, использует броузер) для прогона тестов. Поддерживать же подобные webrat-тесты ощутимо проще, чем чистые Selenium-тесты.

Специально для проверки уровня покрытия кода тестами существует инструмент RCov. Кроме RCov, существуют инструменты для автоматической проверки сложности кода и просто «детекторы говнокода». Их можно запускать по отдельности, а можно воспользоваться metric_fu, включающим в себя все эти проверки вместе с rcov.

Непрерывная интеграция

При работе над масштабным проектом, или просто в случае распределенной разработки часто возникают проблемы из серии «Петя, после твоего коммита опять сломался билд, срочно чини!» или более характерное для славянских программистов «Ебаный в рот! Кто сломал билд?». Одним из очевидных спобов решения таких проблем является «непрерывная интеграция». Для Ruby в целом и рельсов в частности существует своя версия известного CI-средства — CruiseControl.rb.
Существует также альтернатива — Integrity, но ее я ни разу не пробовал.

Сервера приложений

Стандартным сервером приложений Rails является однопоточный Mongrel. Как правило, его запускают кластером из нескольких серверов, после чего балансируют нагрузку между ними при помощи apache или nginx. Такой способ запуска Rails-приложений является наименее эффективным (с точки зрения потребления ресурсов) из всех возможных.

Лучшим решением запуска rails-приложений является Phusion Passenger (также известный как mod_rack и mod_rails). Passenger встраивается модулем в веб-серверы Apache и Nginx и динамически выделяет ресурсы рельсам, подобно mod_wsgi для python и mod_php для PHP. Естественно, это позволяет экономнее расходовать ресурсы сервера и упрощает развертывание приложений.

Для полноты картины стоит отметить Thin. Это сервер, работающий аналогично Mongrel'у, но быстрее и потребляя при этом меньше ресурсов.

Асинхронное выполнение задач

Существует ряд задач, которые выполняются сравнительно долго, например, конвертация видео или загрузка файлов на Amazon S3. Такие задачи желательно (а во многих случаях — обязательно) выполнять в фоне. Долгое время наиболее распространенным инструментом асинхронного выполнения задач в рельсах был BackgroundRB, однако brb потребляет неприлично-много ресурсов, потому рекомендую альтернативный инструмент — Workling.

По умолчанию Workling работает в паре с message queue сервером Starling, разработаным изначально для Twitter'а, однако не советую использовать Starling в production'е. Вместо старлинга можно использовать любой amqp-совместимый сервер, например, RabbitMQ или ActiveMQ.

Мониторинг процессов

Одним из главных недостатков Ruby являются утечки памяти. В Ruby Enterprise Edition и Ruby 1.9 эту проблему частично решили. Но в суровые времена, когда все гоняли рельсы сугубо на Mongrel'ах и Ruby 1.8.6, проблема стояла значительно серьезнее, чем сейчас, потому необходимым было средство, которое следило бы за процессами Mongrel'а и перегружало его при достижении лимита потребляемой памяти. Чаще всего для этих целей использовали совсем не рубишный Monit и его Ruby-аналог — God (который, на мой взгляд, значительно удобней и гибче в конфигурации). Доходило даже до того, что все процессы мониторили God'ом, а сам God — Monit'ом.

К счастью, ситуация стала лучше, но God и Monit (который использовался и используется для мониторинга баз данных, веб-серверов и многих других вещей в unix-системах) все еще остаются простыми и удобными средствами мониторинга процессов, сфера применения которых выходит далеко за рамки перегрузки Mongrel'а при достижении лимита памяти.

Запуск консольных команд

Давно уже для Ruby разработали Rake — инструмент для автоматизации сборки программного кода по типу GNU Make или Apache ANT. Но, в отличие от Make и ANT, Rake-скрипты пишутся на самом Ruby, что сделало их легко расширяемыми и более удобными в написании. В итоге в Rails стали использовать Rake для выполнениях любых консольных команд, например, для запуска тестов, миграций или обновления Rails.

Также существуют дополнительные наборы Rake-задач, выполняющие рутинные операции, например: создание резервных копий базы данных и статических файлов rails-приложения, отображение информации о внешних ключах в базе данных, для которых нет индексов, и многие другие. Отличные примеры дополнительных rake-задач для Rails — limerick_rake и dump.

Визуализация объектной модели

В данном случае лучше один раз увидеть. RailRoad рисует диаграммы объектной модели ваших Rails-приложений. Посмотрите примеры моделей и контроллеров.

Специализированый хостинг

Большинство коммерческих Rails-проектов хостятся на VPS'ах, выделенных серверах и cloud-хостингах вроде Amazon EC2. Однако существуют и специализированные Rails-хостинги (большая их часть — это все те же VPS'ы и надстройки над EC2, куда уже установлены популярные ruby/rails библиотеки, apache с passenger'ом и.т.п.).

Среды разработки

Существует стереотип, будто все rails-разработчики используют для разработки либо TextMate на маке, либо юниксовые vim/emacs/gedit, и для Ruby/Rails нет «взрослых» IDE.

Отчасти это правда, действительно подавляющее большинство Rails-разработчиков не пользуются IDE, но далеко не все! Качественные IDE для Ruby существуют: Aptana RadRails на основе Eclipse, JetBrains RubyMine на основе IntelliJ Idea, NetBeans (который мне не удалось запустить на маке). Лично я предпочитаю RubyMine за его отслеживание ошибок в коде, автодополнение, удобный поиск внутри проекта, отладку кода прямо в IDE и автоматизацию рефакторинга.

В целом, как мне кажется, ситуация с IDE для Ruby хуже чем у Java и .NET, но лучше, чем у Python и PHP.

Вместо заключения

При желании о каждом из описанных выше инструментов можно написать отдельную статью, как и о преимуществах и недостатках Rails. Целью же этой статьи было показать, что Rails и его инфраструктура развиты гораздо сильней, чем кажется на первый взгляд. Надеюсь, у меня получилось.

Статья написана для сайта developers.org.ua


  • в избранное

Наверх