147
zero downtime deploys for Rails photo by Chris http://www.flickr.com/people/chrisinplymouth/

Zero downtime deploys for Rails apps

Embed Size (px)

DESCRIPTION

 

Citation preview

Page 1: Zero downtime deploys for Rails apps

zerodowntime

deploysfor Rails

photo by Chrishttpwwwflickrcompeoplechrisinplymouth

class ApparentlyHarmlessMigration lt ActiveRecordMigration def selfup remove_column users notes endend

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

PGError ERROR column notes does not exist

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 2: Zero downtime deploys for Rails apps

class ApparentlyHarmlessMigration lt ActiveRecordMigration def selfup remove_column users notes endend

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

PGError ERROR column notes does not exist

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 3: Zero downtime deploys for Rails apps

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

PGError ERROR column notes does not exist

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 4: Zero downtime deploys for Rails apps

class CompletelySafeMigration lt ActiveRecordMigration def selfup remove_column users notes end

def selfdown add_column users notes text endend

PGError ERROR column notes does not exist

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 5: Zero downtime deploys for Rails apps

PGError ERROR column notes does not exist

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 6: Zero downtime deploys for Rails apps

INSERT INTO users(email password notes)

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 7: Zero downtime deploys for Rails apps

Zero downtime

Challenge accepted

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 8: Zero downtime deploys for Rails apps

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 9: Zero downtime deploys for Rails apps

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 10: Zero downtime deploys for Rails apps

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 11: Zero downtime deploys for Rails apps

Testable code +Test coverage

TDD

Easy maintenance DRY

Zero downtime deploys Hot compatibility

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 12: Zero downtime deploys for Rails apps

Hot compatibility

bull Run concurrent versions of your application

bull That are compatible between each other

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 13: Zero downtime deploys for Rails apps

Hot compatibility

v1 v2

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 14: Zero downtime deploys for Rails apps

Hot compatibility

v1 v2

writes to `notes` drop column `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 15: Zero downtime deploys for Rails apps

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 16: Zero downtime deploys for Rails apps

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 17: Zero downtime deploys for Rails apps

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 18: Zero downtime deploys for Rails apps

Hot compatibility

v1 v1rsquo v2

writes to `notes` drop column `notes`stop writing to `notes`

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 19: Zero downtime deploys for Rails apps

Hot compatibility

v1 v1rsquo v2

class User def selfcolumns superreject |c| cname == notes endend

writes to `notes` drop column `notes`stop writing to `notes`

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 20: Zero downtime deploys for Rails apps

Self dependency

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 21: Zero downtime deploys for Rails apps

Self dependency

user loads form

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 22: Zero downtime deploys for Rails apps

Self dependency

new form is deployed

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 23: Zero downtime deploys for Rails apps

Self dependency

user submits the form

POST loginusername=billmicrosoftcomamppassword=q1w2e3

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 24: Zero downtime deploys for Rails apps

Self dependency

server blows up

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 25: Zero downtime deploys for Rails apps

Self dependency

bull Make controllers compatible

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 26: Zero downtime deploys for Rails apps

Self dependency

bull Make controllers compatible

class AuthController lt ApplicationController

protected

def filtered_params paramsduptap do |p| pmerge(email =gt pdelete(username)) end endend

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 27: Zero downtime deploys for Rails apps

Assets - Rails 2

Server 1

GET dashboard

GET stylesheetsalljs

200

200

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 28: Zero downtime deploys for Rails apps

Assets - Rails 2

Server 1 Server 2

GET dashboard

GET stylesheetsalljs

200

404

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 29: Zero downtime deploys for Rails apps

Assets - Rails 2

bull httpsgithubcomddollarasset-resource

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 30: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

v1

GET dashboard

GET assetsapplication-v1js

200

200

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 31: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

GET dashboard

GET assetsapplication-v1js

200

404

v1 v2

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 32: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 33: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 34: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 35: Zero downtime deploys for Rails apps

Asset pipeline - Rails 3

bull When updating assets keep the existing version around

bull Wersquore still in need of tooling to help cleaning up old assets

rake assetscleanoutdated

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 36: Zero downtime deploys for Rails apps

Migration strategies

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 37: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 38: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

class Role lt ActiveRecordBase def readonly true endend

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 39: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

bull Ignore cached columns

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 40: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

bull Ignore cached columns

class User def selfcolumns superreject |c| cname == notes endend

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 41: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 42: Zero downtime deploys for Rails apps

Migration strategies

bull Read-only models

bull Ignore cached columns

bull Know your database

bull Beware of O(n) db locks

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 43: Zero downtime deploys for Rails apps

MyISAM

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 44: Zero downtime deploys for Rails apps

MyISAM

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 45: Zero downtime deploys for Rails apps

InnoDB

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 46: Zero downtime deploys for Rails apps

InnoDB

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 47: Zero downtime deploys for Rails apps

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 48: Zero downtime deploys for Rails apps

InnoDB

1 Create a new table with the same structure

2 Apply changes to new table

3 Copy data over

4 Acquire lock on original table

5 Sync newupdateddeleted rows

6 Swap tables

7 Release lock

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 49: Zero downtime deploys for Rails apps

InnoDBhttpsgithubcomfreelstable_migrator

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 50: Zero downtime deploys for Rails apps

InnoDBhttpsgithubcomfreelstable_migrator

class AddStuffToMyBigTable lt TableMigration

migrates users

change_table do |t| tinteger foo null =gt false default =gt 0 tstring bar tindex foo name =gt index_for_foo endend

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 51: Zero downtime deploys for Rails apps

InnoDBhttpsgithubcomfreelstable_migrator

bull Requires acts_as_paranoid

bull Pretty oldstale codebase

bull Check forks for Rails 3 compatibility

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 52: Zero downtime deploys for Rails apps

Postgres

bull Table locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 53: Zero downtime deploys for Rails apps

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 54: Zero downtime deploys for Rails apps

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time if you avoid default values and constraints

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 55: Zero downtime deploys for Rails apps

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 56: Zero downtime deploys for Rails apps

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

can be done without any locking

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 57: Zero downtime deploys for Rails apps

Postgres

bull O(n) locks on

bull Adding updating or removing columns

bull Adding or removing indexes

constant time

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 58: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 59: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

before_save assign_defaults

def assign_defaults selfadmin ||= falseend

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 60: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 61: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

CREATE INDEX CONCURRENTLY users_email_index ON users(email)

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 62: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 63: Zero downtime deploys for Rails apps

Postgres

bull Adding fields with defaults

bull Create indexes concurrently

bull Outside a transaction

class AddIndexToUsers lt ActiveRecordMigration def selfup return if indexes(users)map(ampname)include(users_email_index) add_index users email name =gt users_email_index end

def selfdown remove_index users name =gt users_email_index endend

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 64: Zero downtime deploys for Rails apps

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 65: Zero downtime deploys for Rails apps

What about renaming

v1 v2

reads and writes to `foo`

reads and writes to `bar`

v1rsquo

add column `bar`+

reads from `foo`writes to both`foo` and `bar`

v1rsquorsquo

populate `bar`where needed

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 66: Zero downtime deploys for Rails apps

What about renaming

v2

reads and writes to `bar`

v2rsquo

ignore `foo`

v3

drop column `foo`

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 67: Zero downtime deploys for Rails apps

NoSQL

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 68: Zero downtime deploys for Rails apps

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 69: Zero downtime deploys for Rails apps

NoSQL

bull Schema migrations O(n) locks are just part of hot compatibility

bull You still need to put effort into data migration

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 70: Zero downtime deploys for Rails apps

Workflow

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 71: Zero downtime deploys for Rails apps

Workflow

bull Make sure pull requests are addressing hot compatibility

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 72: Zero downtime deploys for Rails apps

Workflow

bull Make sure pull requests are addressing hot compatibility

bull Work after code is merged

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 73: Zero downtime deploys for Rails apps

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 74: Zero downtime deploys for Rails apps

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 75: Zero downtime deploys for Rails apps

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 76: Zero downtime deploys for Rails apps

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 77: Zero downtime deploys for Rails apps

Meanwhile in production$ thin -C configserveryml restartStopping server on 00005000 Sending QUIT signal to process 3463 Stopping server on 00005001 Sending QUIT signal to process 3464 Stopping server on 00005002 Sending QUIT signal to process 3465 Starting server on 00005000 Starting server on 00005001 Starting server on 00005002

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 78: Zero downtime deploys for Rails apps

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 79: Zero downtime deploys for Rails apps

Production

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 80: Zero downtime deploys for Rails apps

Production

bull Run multiple server processes

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 81: Zero downtime deploys for Rails apps

Production

bull Run multiple server processes

bull Cycle them individually or in batches

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 82: Zero downtime deploys for Rails apps

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 83: Zero downtime deploys for Rails apps

Production

bull Run multiple server processes

bull Cycle them individually or in batches

bull Watch out for capacity

bull Cycle them gracefully

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 84: Zero downtime deploys for Rails apps

Cycling techniques

bull Above the stack

bull Within the stack

bull Platform

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 85: Zero downtime deploys for Rails apps

Above the stack

bull Use your favorite web server

bull Setup a load balancer above them route around servers that are cycling

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 86: Zero downtime deploys for Rails apps

Above the stack

bull PROTIP default setup wonrsquot work

bull Configure load balancer to poll for your application health

class HealthController lt ApplicationController def index if Fileexists(Railsrootjoin(MAINTENANCE)) render text =gt Forget me status =gt 503 else render text =gt Im alive end endend

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 87: Zero downtime deploys for Rails apps

Cycling + Load balancer

bounce serversrm MAINTENANCE

remove server from rotation

touch MAINTENANCE

new servers come online

add server to rotation

Server Load balancer

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 88: Zero downtime deploys for Rails apps

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 89: Zero downtime deploys for Rails apps

HAProxy

tell HAProxy where to check for the health

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 90: Zero downtime deploys for Rails apps

HAProxy

do not let your web server queue requests

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 91: Zero downtime deploys for Rails apps

HAProxy

tell HAProxy to run the health check specified above

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 92: Zero downtime deploys for Rails apps

HAProxy

every 2s

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 93: Zero downtime deploys for Rails apps

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

stop routing to it once the health check failed once

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 94: Zero downtime deploys for Rails apps

HAProxy

option httpchk GET health

listen myapp 9000 server myapp-1 10015000 maxconn 1 check inter 2000 fall 1 rise 1 server myapp-2 10025000 maxconn 1 check inter 2000 fall 1 rise 1

and bring it back once it worked once

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 95: Zero downtime deploys for Rails apps

ELB

$ elb-configure-healthcheck MyLoadBalancer --target HTTP5000health --interval 2 --unhealthy-threshold 1 --healthy-threshold 1

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 96: Zero downtime deploys for Rails apps

Above the stack

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 97: Zero downtime deploys for Rails apps

Above the stackbull Minimal impact

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 98: Zero downtime deploys for Rails apps

Above the stackbull Minimal impact

bull Extended availability comes for free

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 99: Zero downtime deploys for Rails apps

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 100: Zero downtime deploys for Rails apps

Above the stackbull Minimal impact

bull Extended availability comes for free

bull Complicated setup

bull Another component you have to track and maintain

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 101: Zero downtime deploys for Rails apps

Within the stack

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 102: Zero downtime deploys for Rails apps

Within the stack

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 103: Zero downtime deploys for Rails apps

Unicorn

bull Replaces your web server

bull Bounces gracefully

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 104: Zero downtime deploys for Rails apps

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 105: Zero downtime deploys for Rails apps

Unicorn

63480 00 14 2549796 unicorn_rails master -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 106: Zero downtime deploys for Rails apps

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -USR2 63480

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 107: Zero downtime deploys for Rails apps

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 108: Zero downtime deploys for Rails apps

Unicorn

63480 00 14 2549796 unicorn_rails master (old) -c configunicornrb 63489 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63490 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63491 00 02 2549796 unicorn_rails worker[2] -c configunicornrb 63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 109: Zero downtime deploys for Rails apps

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

$ kill -QUIT 63480

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 110: Zero downtime deploys for Rails apps

Unicorn

63521 00 14 2549796 unicorn_rails master -c configunicornrb 63535 00 02 2549796 unicorn_rails worker[0] -c configunicornrb 63536 00 02 2549796 unicorn_rails worker[1] -c configunicornrb 63537 00 02 2549796 unicorn_rails worker[2] -c configunicornrb

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 111: Zero downtime deploys for Rails apps

Within the stack

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 112: Zero downtime deploys for Rails apps

Within the stackbull Easy to setup and deploy

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 113: Zero downtime deploys for Rails apps

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 114: Zero downtime deploys for Rails apps

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 115: Zero downtime deploys for Rails apps

Within the stackbull Easy to setup and deploy

bull Optimal performance to cycle the server

bull Changes your application stack

bull Doesnrsquot address availability issues

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 116: Zero downtime deploys for Rails apps

Platform

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 117: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 118: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 119: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 1s bundle exec thin start -p $PORT

$ git push heroku master

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 120: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 starting for 5s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 121: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 1s bundle exec thin start -p $PORT

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 122: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 123: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ heroku labsenable preboot

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 124: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 125: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 126: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 starting for 5s bundle exec thin start -p $PORT

$ git push heroku master

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 127: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 10h bundle exec thin start -p $PORTweb1 up for 1s bundle exec thin start -p $PORT

BETA

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 128: Zero downtime deploys for Rails apps

Heroku

Process State Command ------- --------------- -------------------------------web1 up for 5s bundle exec thin start -p $PORT

BETA

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 129: Zero downtime deploys for Rails apps

Heroku

bull Migrations

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 130: Zero downtime deploys for Rails apps

Heroku

bull Migrations

$ git push pre-production master$ heroku run rake dbmigrate --remote pre-production$ git push production master

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 131: Zero downtime deploys for Rails apps

Agenda

bull Introduction

bull Development practices

bull Production environment setup

bull Future

bull Conclusion

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 132: Zero downtime deploys for Rails apps

Future

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 133: Zero downtime deploys for Rails apps

Future

bull Asset pipeline

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 134: Zero downtime deploys for Rails apps

Future

bull Asset pipeline

bull Mysql tooling

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 135: Zero downtime deploys for Rails apps

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 136: Zero downtime deploys for Rails apps

Future

bull Asset pipeline

bull Mysql tooling

bull Can Rails help making the development of hot compatible applications easier

bull Can databases

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 137: Zero downtime deploys for Rails apps

Future

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 138: Zero downtime deploys for Rails apps

Future

bull Hot compatibility beyond zero downtime deploys

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 139: Zero downtime deploys for Rails apps

Conclusion

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 140: Zero downtime deploys for Rails apps

Conclusion

bull Zero downtime is a pain in the ass

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 141: Zero downtime deploys for Rails apps

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 142: Zero downtime deploys for Rails apps

Conclusion

bull Zero downtime is a pain in the ass

bull Hot compatibility to the rescue

bull Make sure your production env is ready

Thank youhttppedroherokucom

ped

Page 143: Zero downtime deploys for Rails apps

Thank youhttppedroherokucom

ped