Rails in production

What is rails?

Rails

  • Web MVC Framework
  • Convention over Configuration
  • Scaffolding
  • Ruby
  • Monkey Patching

Rack

  • Ruby Web Server Interface
  • HTTP Response code
  • Hash of headers
  • response body
#my_rack_app.rb
require 'rack'

app = Proc.new do |env|
  ['200', { 'Content-Type' => 'text/html' }, 
  ['Hello World']]
end

Rack::Handler::WEBRick.run app

#config.ru
run Proc.new { |env| ['200', { 'Content-Type' => 'text/html' }, 
                     ['Hello World']] }

Other Web Framework?

Web Framework

  • Sinatra
  • Padrino
  • Lotus
  • Volt
  • Grape

Rails compoenet

  • active model
  • active record
  • active job
  • active view
  • active support
  • action pack
  • action mailer
  • railties

Tool

  • Rails Generator
  • Rails Console
  • db migration
  • asset pipeline
  • Thor
  • Spring
  • Guard
  • xip.io
  • better erros
  • pry

Etc Tool

  • Pow
  • Foreman

Which Server do we have to use?

  • webrick
  • thin
  • unicorn
  • puma
  • passenger

Ruby Process Model

It depends on implementation!

Ruby Implementation

  • MRI CRuby
  • JRuby
  • Rubinius
  • RubyMotion
  • MacRuby

MRI CRuby

  • Most popular ruby implementation
  • MultiThread ( since 2.x ~)
  • JIT
  • But, still GIL limitation
  • multithread for I/O

JRuby

  • Based on jvm
  • JRuby9000 released(support ruby2.2)
  • true multithreaded implementation
  • invoke dynamic

Rubinius

  • ruby implementation based on LLVM
  • multithead implementation
  • performance penalty

Unicorn

  • Master and worker process model
  • slow client problem
  • nginx with unicorn
  • unix domain socket

Puma

  • multithread web server
  • recommended in the heroku
  • rails supports thread safe
  • hybrid model - multi process and multithread
  • apache / nginx module
  • support hybrid - multi process and multithread

unicorn

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.connection.disconnect!
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  defined?(ActiveRecord::Base) and
    ActiveRecord::Base.establish_connection
end

puma

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

environment management

  • .env
  • dotenv gem
  • config/environments/*

view

  • ERB
  • Haml
  • Slim

slim

  • more simple than Haml
  • It's like Jade
  • Fast

ERB

  • useful for custom view (json, yaml, config)

API

JSON View

  • Active Model Serializer
  • Rabl
  • Jbuilder

presenter / decorator

Authentication / authorization

  • Devise
  • Cancan
  • Omniauth

asset pipeline

  • coffeescript
  • sass / scss
  • compress / bundling
  • compass
  • s3 sync

Background Job

  • Sidekiq
  • Resque
  • Delayed Job

Resque

  • Process fork
  • heavy rather than sidekiq

Sidekiq

  • multithread background job
  • Redis is used for queue
  • open source / commercial
  • based on celluloid
  • provide job monitoring page
  • easy to use
  • best performance in the JRuby

Sidekiq

# config/initializers/sidekiq.rb
Sidekiq.configure_server do |config|
  database_url = ENV['DATABASE_URL']
  if database_url
    ENV['DATABASE_URL'] = "#{database_url}?pool=25"
    ActiveRecord::Base.establish_connection
  end
end

Resque

Resque.before_fork do
    defined?(ActiveRecord::Base) and
      ActiveRecord::Base.connection.disconnect!
  end

  Resque.after_fork do
    defined?(ActiveRecord::Base) and
      ActiveRecord::Base.establish_connection
  end

Test

  • Rspec
  • Factory Girl

deploy

  • Git
  • Heroku
  • Jenkins
  • AWS Opsworks (chef solo)

AWS OPSWORKS

Docker

Immutable Infrastructure

docker

  • slow build
  • fast deployment
  • docker registry sucks
  • AWS ECS
  • versioning - rollback is easy
  • docker image
  • log management (host option)
  • network (native mapping, dhcp)
  • cluster management

monitoring

  • new Relic
  • sentry

Log Management

  • ELK(Elastic Search + Logstash + Kibana)
  • FluentD

rails in production

By odyss

rails in production

  • 2,298