Pull to refresh

Ruby on Rails на Windows с тестами производительности

Reading time 11 min
Views 16K
«Залог дружбы — это разность индивидуальностей» Юлиан Семенов.
Все больше и больше Windows-разработчики интересуются Ruby — динамическим высокоуровневым языком программирования. Не малую роль здесь сыграл фреймворк для создания веб-приолжений Ruby on Rails. Разработка на «рельсах» проста и увлекательна. Благодаря высокой динамике Ruby разработчику открываются множество вспомогательных средств, при сравнительно малом количестве кода вы получаете богатый функционал.

Эта статья хорошо подойдет для начинающих веб-программистов и тех кто задумывается начать работать с Ruby on Rails. В ней будут рассмотрены такие вопросы:
  • установка рабочего окружения;
  • написание простого приложения;
  • развертывание приложения на сервере.
В заключении вы найдете тесты, сравнивающие производительность различных вариантов выполнения Ruby-приложений на Windows и Ubuntu.

Установка рабочего окружения



Для начала необходимо скачать и установить Web Platform Installer, запустить его, кликнуть на «Options» и в поле «Display additional scenarios» добавить ссылку на Helicon Zoo Feed: http://www.helicontech.com/zoo/feed/



После этого в Web Platform Installer появится закладка Zoo, которая содержит секции «Applications», «Packages», «Modules», «Engines»:



Установка Ruby on Rails



В секции «Engines» вы можете поставить различные фреймворки, в том числе Ruby on Rails 3.1 и 2.3. Кроме того здесь же доступны Ruby 1.8 и 1.9. По умолчанию, при установке Rails 3 ставится Ruby 1.9 как зависимость. Для Rails 2 будет поставлен Ruby 1.8.

Для удобства в секции «Packages» предлагается пакет «Ruby Hosting Package», включающий следующие компоненты:
  • Ruby 1.8.7 и Ruby 1.9.3;
  • Rails 2.3.11, 3.0.10 и 3.1;
  • Ruby DevKit (для сборки C-расширений);
  • популярные джемы: mysql2, pg, sqlite3, mongo_mapper, tiny_tds, activerecord-sqlserver-adapter, devise, authlogic, jekyll, formtastic, will_paginate, sinatra, ramaze, camping-omnibus, thin, goliath.


Создание первого веб-сайта



Для создания нового веб-приложения удобно использовать WebMatrix и IIS Express. На вкладке «Zoo», в секции «Packages» есть пакет «WebMatrix Templates», предоставляющий различные шаблоны-заготовки, в том числе и для Ruby on Rails.

Если у вас еще нет WebMatrix, он будет автоматически установлен вместе с пакетом «WebMatrix Templates». Будьте готовы, что загрузка и установка всех пакетов может занять время.Установив шаблоны, запустите WebMatrix и на стартовой странице выберите «Site from template», а затем «Rails Site»:



После создания Rails Site, если перейти по указанному URL или нажать «Run», вы увидите страницу с инструкциями:



Шаблон рассчитан на создание Rails приложения ветки 2.3, 3.0 или 3.1. На данный момент в каталоге сайта никакого приложения еще нет, только заготовленные конфигурационные файлы. Давайте создадим его, вызвав следующую команду:

rails new .

Если в команде не указывать конкретную версию Rails, будет использована последняя доступная. В нашем случае мы воспользовались пакетом «Ruby Hosting Package», который содержит сразу три различных версии Rails, и самая свежая из них — 3.1. Поэтому команда создаст заготовку на основе Rails 3.1.

Теперь если обновить страницу, вы увидите стандартное приветствие Ruby on Rails:



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



Для правки кода вам потребуется редактор или среда разработки. Если вы предпочитаете функционал полноценной IDE, с отладчиком и средствами для рефакторинга, вы можете рассмотреть следующие программы:Каждая IDE предлагает массу возможностей для разработки и тестирования Ruby приложений, а также поддерживает системы контроля версий.

Для тех, кто привык использовать более простые решения, доступны:Для написания примера мы использовали Aptana:



MVC



Ruby on Rails базируется на архитектуре модель-представление-контроллер (model, view, controller — MVC). У такого подхода есть следующие преимущества:
  • изоляция бизнес-логики от интерфейса;
  • как можно меньше повторений кода (принцип DRY — don’t repeat yourself);
  • относительно простая разработка за счет строгого распределения кода по назначению (например код вывода HTML формы не смешивается с кодом обработки БД).
Модель описывает структуру базы данных в терминах объектно-ориентированого программирования. Так в Rails, модель – это обыкновенный класс, наследующий весь необходимый функционал от класса ActiveRecord::Base. Экземпляр (объект) такого класса описывает одну строку из соответствующей таблицы БД. Таким образом, модели скрывают от разработчика тонкости работы с конкретной СУБД.

Представление – это непосредственно интерфейс, который видит пользователь. На этом уровне разработчик делает шаблоны, преобразующиеся в HTML, CSS или JavaScript код.

Контроллер связывает модель и представление. Обычно именно в контроллере размещают основную логику. По сути, контроллеры – это Ruby классы. Каждый публичный метод контроллера называется действием. Если ваш контроллер называется Home и в нем есть публичный метод index, то обычно запросив в браузере /home/index вы вызовите действие index.

Когда в приложение приходит запрос, механизм маршрутизации (в файле config/routes.rb) определяет какой контроллер отвечает за такой вид запроса. Кроме непосредственно URL адреса может быть учтено множество условий, например можно использовать разные контроллеры для разных браузеров, для мобильных клиентов и т.п.

Итак, выбрав котроллер, определяется действие, которое обработает запрос. Здесь также можно применить массу условий. Непосредственно в действии происходят какие-то вычисления или работа с БД. Когда действие отработало, настает время представления. В шаблоны можно передать полученные из БД данные или какой-то результат. Из шаблонов будет сгенерирован обычный HTML (есть также шаблоны для JavaScript и CSS) и страница с ответом отправится пользователю.

Пишем приложение



Классическим примером для Rails обычно является создание простейшего блога. Не будем отступать от традиций. Итак, давайте удалим файл с приветствием — public/index.html и создадим контроллер Home с действием Index — это будет главная страничка блога. Для этого необходимо выполнить следующую команду, находясь в каталоге приложения:

rails g controller home index

Теперь если запросить /home/index, мы получим страничку из шаблона, созданного для действия index:



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

Чтобы создать модель, можно вызвать команду «rails g model Post...», однако давайте воспользуемся более удобным средством — скаффолдингом (scaffolding — строительне леса). Команда «rails g scaffold» создает кроме самого класса модели и тестов для нее, заготовки действий и шаблоны представлений для создания, редактирования и удаления объектов модели. Выполнив следующую команду:

rails g scaffold Post name:string title:string content:text

Мы получим модель Post в app\models\post.rb, контроллер Posts в app\controllers\posts_controller.rb, с действиями index, show, new, edit, update, create и destroy, а также сценарий миграции БД в каталоге db\migrate. Команда также создала заготовки тестов и HTML шаблоны. Важно заметить, что мы еще не писали никакого кода.

Вызовем команду, которая создаст БД (если ее еще нет), а также таблицу posts с полями name, title и context, как описано выше:

rake db:migrate

Команда миграции базы данных используется для создания или изменения структуры базы данных в соответствии с нашей объектной моделью. Ее нужно вызывать каждый раз, когда вы что-то поменяли в модели приложения. Вся магия по подгонке структуры БД к нашей модели происходит автоматически, а уже записанные данные в базе будут сохранены.

Заметим, что в конкретном примере используется Sqlite, в Rails это БД по умолчанию. Однако рельсы поддерживают массу других СУБД, скрывая при этом специфику работы с ними.

Действия контроллера Posts теперь доступны по адресу /posts/.



Нажав на ссылку «New Post» мы увидим форму:



Заполнив все поля, мы попадаем на страницу нового поста:



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

class Post < ActiveRecord::Base
  validates :name,  :presence => true
  validates :title, :presence => true,
                    :length => { :minimum => 5 }
end


Здесь мы указываем, что заполнение поля «name» и «title» является обязательным, причем поле «title» должно содержать не менее 5 символов. Миграцию применять не нужно т.к. валидаторы не связаны с базой непосредственно, проверка происходит на уровне руби кода.

Если теперь, например, не ввести поле «name», мы получим ошибку:



Усложним задачу и добавим комментарии. Создадим модель Comment следующей командой:

rails g model Comment commenter:string body:text post:references

Обратите внимание на параметр «post:references». Он связывает таблицу «comments» с таблицей «posts».

Обновим базу данных:

rake db:migrate

Теперь установим отношение «has many» для модели Post:

class Post < ActiveRecord::Base
  validates :name,  :presence => true
  validates :title, :presence => true,
                    :length => { :minimum => 5 }
 
  has_many :comments, :dependent => :destroy
end


Код интуитивно понятен. Получается, что каждый объект Post может иметь много комментариев. :dependent => :destroy указывает на то, что при удалении поста, его комментарии должны тоже удаляться.Поскольку в этот раз мы не использовали механизм скаффолдинга для создания модели комментариев, необходимо сгенерировать соответствующий контроллер:

rails g controller Comments

В файле config\routes.rb замените строку «resources :posts do» на:

resources :posts do
  resources :comments
end


Таким образом, мы указываем, как будет доступен контроллер с комментариями. В данном случае он вложен в «posts», т.е. ссылки будут иметь вид: http://localhost:41639/posts/1/comments/3

Дальше необходимо обновить шаблон app\views\posts\show.html.erb так, чтобы была возможность оставлять комментарии. После:

<p>
  <b>Content:</b>
  <%= @post.content %>
</p>


добавте:

<h2>Comments</h2>
<% @post.comments.each do |comment| %>
  <p>
    <b>Commenter:</b>
    <%= comment.commenter %>
  </p>
 
  <p>
    <b>Comment:</b>
    <%= comment.body %>
  </p>

<p>
  <%= link_to 'Destroy Comment', [comment.post, comment],
               :confirm => 'Are you sure?',
               :method => :delete %>
</p>

<% end %>


<h2>Add a comment:</h2>
<%= form_for([@post, @post.comments.build]) do |f| %>
  <div class="field">
    <%= f.label :commenter %><br />
    <%= f.text_field :commenter %>
  </div>
  <div class="field">
    <%= f.label :body %><br />
    <%= f.text_area :body %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>




Наконец опишем логику работы контроллера в app\controllers\comments_controller.rb

class CommentsController < ApplicationController
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.create(params[:comment])
    redirect_to post_path(@post)
  end

  def destroy
    @post = Post.find(params[:post_id])
    @comment = @post.comments.find(params[:id])
    @comment.destroy
    redirect_to post_path(@post)
  end
end


Теперь все готово и можно добавлять комментарии к посту:



Итак, основной функционал реализован. В качестве последнего шага, давайте защитим некоторые действия, чтобы посторонний не имел к ним доступа. Более правильный подход — использовать регистрацию, сессии, куки и т.п., но мы для простоты возьмем обычную Basic аутентификацию, тем более в Rails она добавляется одной строкой. В posts_controller.rb напишем:

http_basic_authenticate_with :name => "admin", :password => "123", :except => [:index, :show]

Здесь жестко указан логин и пароль. Параметр :except исключает действия :index и :show — для них аутентификация не требуется.



Развертывание на сервере



Итак, мы написали приложение и теперь хотим выложить его в сети. Для этого настроим Windows сервер для работы с Rails. Нам понадобиться повторить первые несколько шагов из начала статьи, которые мы делали для развертывания рабочего окружения. Нужно поставить Microsoft Web Platform Installer, добавить в него Helicon Zoo feed и установить Ruby Hosting Package из репозитория Zoo. Перед установкой следует убедиться, что в настройках Web Platfrom Installer указано устанавливать приложения под IIS, а не под IIS Express. Теперь сервер готов принять наше приложение. На текущий момент из серверных платформ поддерживаются Windows 2008 и 2008 R2, 32 и 64 битные версии.

Теперь создадим на сервере пустой веб сайт, используя обычные средства, такие как менеджер IIS или хостинг панель. Далее нужно загрузить наше приложение на сайт по FTP или WebDeploy. В случае с WebDeploy будут еще и розданы необходимые права на папки. Можно также использовать Git или другую систему контроля версий, но это выходит за рамки данной статьи.

Helicon Zoo Module изначально разрабатывался с расчетом конфигурирования хостинг решений. Так все приложения под ним разделены и не пересекаются. Сам модуль с настройками по умолчанию работает в автоматическом режиме, создавая один воркер (процесс-обработчик), когда нагрузка мала или добавляя воркеров вплоть до числа ядер, чтобы дать максимальную производительность, если нагрузка на приложение возрастает.

В Helicon Zoo используется концепция движков (engines) и приложений (applications). Так в движках определяется, что запускать и как, по какому протоколу и на каком порту, сколько минимально и максимально воркеров разрешено и подобные глобальные настройки, которые задаются глобально в файле applicationHost.config. Затем уже под сайтом можно создать приложение, использующее конкретный движок и передать ему необходимые параметры для работы этого приложения. Это позволяет отделить работу администратора хостинга от клиентов, а клиентов друг от друга.Более подробно о настройках Helicon Zoo Module можно почитать тут: http://www.helicontech.com/zoo/module.htm(англ.)

Обратите внимание на файл deploy.rb в корневой директории сайта, а также настройки DEPLOY_FILE и DEPLOY_LOG в web.config. Zoo модуль выполняет deploy.rb при каждом запуске IIS пула. Такой подход может пригодиться тем, кто не имеет административных привилегий на сервере. Ведь для развертывания, скорее всего, потребуется выполнить «bundle install» либо применить миграции БД. Для этого просто перезапустите ваше приложение на сервере и файл deploy.rb выполнится автоматически. Наиболее популярные команды уже прописаны в deploy.rb.

Стоит помнить также что deploy.rb скрипт выполняется тем же Windows пользователем, что запускает IIS пул. Как правило, он имеет весьма ограниченные права и это следует учитывать при написании своих команд. Например, обычный вызов «bundle install» может привести к ошибке, поскольку нет возможности писать в директорию установки Ruby непосредственно. Хорошее решение — предварительно сохранить все джемы под сайтом, в специальном каталоге vendor/cache, для чего нужно вызвать команду «bundle package» в директории вашего приложения перед отправкой его на сервер. А в deploy.rb стоит написать команду «bundle install --local --path vendor/gems».

Ошибки выполнения deploy-скрипта можно прочитать в файле, указанном в переменной DEPLOY_LOG.

Последнее на что хотелось бы обратить внимание при развертке – это переменная RACK_ENV в web.config. В том web.config, что ставится из шаблона WebMatrix переменная RACK_ENV указана со значением «development». Это включает соответствующий режим в Rails, более подходящий для разработки. На сервере же необходимо поменять значение на «production». Кстати именно «production» используется по умолчанию.

Тесты производительности



Тестовая машина в качестве сервера — Core 2 Quad 2.4 Ghz, 8 Gb RAM, гигабитная сеть. Для генерации нагрузки использовался более мощный компьютер и Apache Benchmark командой «ab.exe -n 100000 -c 100 –k». Для тестирования Apache и Nginx использовалась Ubuntu 11.04 Server x64. IIS 7 тесты работали на Windows Server 2008 R2. Никаких виртуалок — честное железо.

Было проведено три теста. В первом Rails приложение должно был просто выводить на страничке текущее время с высоким разрешением. Время нужно чтобы гарантировать что ответы не идут из кеша. Во втором тесте производилось чтение из базы данных MySQL, в третьем запись в базу данных.

Для тестов использовали Ruby 1.9.3, Rails 3.1.1 и MySQL 5.1.54. В случае с HTTP транспортом, в качестве бэкэнда использовался Thin. Ни Unicorn ни Passenger на Windows просто не работают. Итого в тесте участвовало три конфигурации: Windows + IIS 7.5 + Helicon Zoo + Thin, Ubuntu + Apache + Passanger, Ubuntu + Nginx + Thin.

Вот результаты (величина на графиках — запросы в секунду):



Также по первому тесту с выводом времени приведем более подробные графики ab:







Выводы



Ruby on Rails — отличный фреймворк, позволяющий быстро и легко создавать различные веб-приложения. Конечно мир Ruby им не ограничивается. В последующих статьях мы рассмотрим Goliath и Sinatra.

Хотелось бы отметить, что Windows — хорошая платформа как для разработки на Ruby так и для запуска приложений в продакшене. Если раньше разница в производительности Ruby на Linux и Windows системах была высока, то теперь производительность, а также удобство использование RoR на Windows сильно улучшились. Настолько, что теперь вопросом производительности при выборе платформы можно пренебречь на фоне других факторов.


PS: Соавтором этой статьи является Вячеслав Шинкаренко. Т.к. на хабр он не приглашен, то вот его Twitter: https://twitter.com/#!/vyaces
Tags:
Hubs:
+15
Comments 41
Comments Comments 41

Articles