Upload
simon-bagreev
View
3.958
Download
1
Tags:
Embed Size (px)
Citation preview
Optimizing rails applications’ performance
w!"# A$$%" CDN &'( U'!)*r'
S!+*' B&,r%%v, @$"&"-$_200$b&,r%%v@,+&!..)*+
Friday, January 11, 13
Question
Does anyone know what
f5dd
is?
Friday, January 11, 13
What *is Preso is NOT
• not a coding demo or tutorial (strangely)
• not a best practices showcase
Friday, January 11, 13
What *is Preso IS
• tips and tricks on tuning rails application
• personal experience
Friday, January 11, 13
DisclaimerThere are many other ways to improve app’s performance:
•database performance (indexes, N+1, slow queries)•caching•background processing•changing interpreter, GC•conditional asset loading, etc•removing cruft!
Try them first!
Friday, January 11, 13
*is Presentation - Two Parts
• CDN Asset Host using aws*
• unicorn web server*
* Both approaches were tested on heroku, but must work with other hosting solutions
Friday, January 11, 13
Sample App
Friday, January 11, 13
NewRelic Monitoring
average load time for mobile traffic only, includes iframed ads
Friday, January 11, 13
Heroku Dyno Operation
Friday, January 11, 13
Step 1 - Rack::Cache
Serving assets from rack::cache is faster, and frees up app instance to serve more requests
Friday, January 11, 13
Static Asset Caching# Gemfilegem 'dalli'
# config/application.rbconfig.cache_store = :dalli_store
# config/environments/production.rbconfig.action_dispatch.rack_cache = { :metastore => Dalli::Client.new, :entitystore => 'file:tmp/cache/rack/body', :allow_reload => false}config.serve_static_assets = trueconfig.assets.digest = true
config.action_controller.perform_caching = true# provision Memcache addon on Heroku
Friday, January 11, 13
A2er Deploymentshould see entries like this in your log
cache: [GET /assets/application-c0747cab950350f59304a3815f980622.css] miss, storecache: [GET /assets/application-032691d4988a7003c42a10995819a0ce.js] miss, storecache: [GET /assets/s_code.js] miss, store
cache: [GET /assets/application-c0747cab950350f59304a3815f980622.css] freshcache: [GET /assets/application-032691d4988a7003c42a10995819a0ce.js] freshcache: [GET /assets/s_code.js] fresh
Friday, January 11, 13
Using Rack::Cache Effect
down from 4.91 / 201 / 2.29 before the change -- not bad for 8 lines of code!
Friday, January 11, 13
Step 2 - S3 bucket for assets
heroku instance has more time to serve application code because all assets are served from aws s3
Friday, January 11, 13
S3 Bucket for Assets# Gemfilegem "asset_sync" # will push compiled assets into CDN
# Command lineheroku config:add FOG_PROVIDER=AWS \ AWS_ACCESS_KEY_ID=xxx \ AWS_SECRET_ACCESS_KEY=yyy
heroku config:add FOG_DIRECTORY=yourappname-assets
# config/environments/production.rbconfig.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
# make sure to use AssetTagHelper methods (like image_tag)# to ensure assets are properly referenced
Friday, January 11, 13
Now, on git push heroku
assets are automatically synced to s3 anytime ON rake assets:precompile
Friday, January 11, 13
S3 Bucket effect
down from 4.45 / 179 / 2.43 before the change -- even better!
Friday, January 11, 13
Step 3 - AWS CloudFront
Friday, January 11, 13
CloudFront Effect
down from 3.85 / 179 / 2.19 before the change -- Awesome!
Friday, January 11, 13
Loading Single 5le$ time curl http://careersingear.mobi/assets/application-bdb77a926724ccc3c20b923ab168d89d.js
real 0m0.896suser 0m0.008ssys 0m0.016s
----------------
$ time curl http://d3kd72psxbec02.cloudfront.net/assets/application-bdb77a926724ccc3c20b923ab168d89d.js
real 0m0.293suser 0m0.006ssys 0m0.010s
getting a single application.js file from cloud front is 3x faster
Friday, January 11, 13
WebPageTest ResultsBefore
Friday, January 11, 13
WebPageTest Results A2er
Friday, January 11, 13
Meet Unicorn• HTTp server for Ruby
• Starts one master process
• forks worker processes
• workers handle requests
• master returns
• one port, several concurrent requests
Friday, January 11, 13
Server Setup
classic setup nginx -> smart balancer -> pool of mongrels
Unicorn setup nginx -> unix domain socket -> unicorn workers (os handles load balancing)
Friday, January 11, 13
Unicorn for Rails App# Gemfilegem 'unicorn'
# Procfileweb: bundle exec unicorn -p $PORT -c ./config/unicorn.rb
# config/application.rbconfig.logger = Logger.new(STDOUT)
# also, add config/unicorn.rb
Friday, January 11, 13
Unicorn for Rails App# config/unicorn.rbworker_processes 3timeout 30preload_app true before_fork do |server, worker| if defined?(ActiveRecord::Base) ActiveRecord::Base.connection.disconnect! Rails.logger.info('Disconnected from ActiveRecord') end
if defined?(Resque) Resque.redis.quit Rails.logger.info('Disconnected from Redis') end
end after_fork do |server, worker| if defined?(ActiveRecord::Base) ActiveRecord::Base.establish_connection Rails.logger.info('Connected to ActiveRecord') end if defined?(Resque) Resque.redis = ENV["REDISTOGO_URL"] Rails.logger.info('Connected to Redis') endend
Friday, January 11, 13
A2er Implementing Unicorn
down from 3.64 / 46.7 / 1.17 before the change -- good, but also...
Friday, January 11, 13
Better Concurrency Handlingrequire 'typhoeus'require "benchmark"
URL = "http://careersingear.mobi"HYDRA = Typhoeus::Hydra.new(max_concurrency: 20)
1000.times do request = Typhoeus::Request.new(URL, method: :get, timeout: 10000) request.on_complete do |response| puts response.code end HYDRA.queue(request)end
Benchmark.bm(7) do |x| x.report("first:") { HYDRA.run }end
# using thin# user system total real# 1.030000 0.380000 1.410000 ( 16.713791)
# using unicorn# user system total real# 1.050000 0.390000 1.440000 ( 7.843766)
Friday, January 11, 13
And ...
my app can process six concurrent requests on two heroku dynos
Friday, January 11, 13
Riding Unicorn
Friday, January 11, 13
To Conclude
• implemented asset cdn
• configured unicorn
• brought down average end user load time from almost 5 sec to 3.5 sec
• app can serve more requests faster and for less $$$
Friday, January 11, 13
Friday, January 11, 13
Creditsdefunkt, unicorn! https://github.com/blog/517-unicorn
heroku dev center, using rack::cache with memcached in rails 3.1+ https://devcenter.heroku.com/articles/
rack-cache-memcached-rails31
Rice, david, using a cdn asset host with rails 3.1 https://devcenter.heroku.com/articles/cdn-asset-
host-rails31
Sikkes, Michael, Complete Guide to serving your Rails assets over S3 with asset_sync http://blog.firmhouse.com/
complete-guide-to-serving-your-rails-assets-over-s3-with-asset_sync
van roijen, michael, more concurrency on a single heroku dyno with the new celadon cedar stack http://
michaelvanrooijen.com/articles/2011/06/01-more-concurrency-on-a-single-heroku-dyno-
with-the-new-celadon-cedar-stack/
Friday, January 11, 13
Q & AThis presentation can be found on github github.com/semmin/asset-cdn-and-unicorn-preso
twitter: @status_200
Email: [email protected]
Questions?
Friday, January 11, 13