Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Making Rails Not Slow

Dane Šoba
January 28, 2016

Making Rails Not Slow

Presented at Ruby Meetup Ljubljana on 28. Jan 2016

Dane Šoba

January 28, 2016
Tweet

More Decks by Dane Šoba

Other Decks in Programming

Transcript

  1. MAKING RAILS NOT SLOW WHY PERFORMANCE MATTERS? ▸ customer experience

    ▸ hosting costs ▸ SEO ranking ▸ developer experience
  2. HALF A SECOND DELAY CAUSED A 20% DROP IN TRAFFIC.

    Google research, 2004 MAKING RAILS NOT SLOW
  3. EVERY 100 MS OF LATENCY COST 1% IN SALES Amazon

    research, 2008 MAKING RAILS NOT SLOW
  4. MAKING RAILS NOT SLOW RESPONSE TIME USER PERCEPTION <100ms Instant

    200ms Fast 300ms Ok 500ms Sluggish 1s Frustrating 2s RAAGEEE
  5. MAKING RAILS NOT SLOW RESPONSE TIME REQUESTS / SECOND 100ms

    10 200ms 5 300ms 3 500ms 2 700ms 1 1s 1
  6. MAKING RAILS NOT SLOW RESPONSE TIME REQUESTS / INSTANCE (2

    PROCESS) 100ms 20 200ms 10 300ms 7 500ms 4 700ms 3 1s 2
  7. MAKING RAILS NOT SLOW RESPONSE TIME INSTANCES FOR 1000 RPM

    100ms 1 200ms 2 300ms 3 500ms 4 700ms 6 1s 8
  8. MAKING RAILS NOT SLOW RESPONSE TIME HEROKU COST 100ms $25

    200ms $50 300ms $75 500ms $125 700ms $175 1s $225
  9. MAKING RAILS NOT SLOW WHY IS RUBY SLOW? ▸ Single

    threaded / GIL ▸ Blocking ▸ Interpreted ▸ Very dynamic ▸ Garbage collected
  10. MAKING RAILS NOT SLOW DYNAMIC & INTERPRETED ▸Interpreting is slow

    ▸Dynamic code is hard to optimize ▸Improved in recent ruby versions
  11. MAKING RAILS NOT SLOW MEASURING PERFORMANCE ▸ rails timing logs

    ▸ benchmark helper ▸ ab - apache benchmark ▸ heroku database metrics ▸ new relic monitoring ▸ slow query logs
  12. MAKING RAILS NOT SLOW BENCHMARK HELPER <% benchmark "Process data

    files" do %> <%= expensive_files_operation %> <% end %> Process data files (345.2ms)
  13. MAKING RAILS NOT SLOW APACHE BENCH ab -n100 http://127.0.0.1:3000 Requests

    per second: 4.09 [#/sec] (mean) Time per request: 244.221 [ms] (mean) Percentage of the requests served within a certain time (ms) 50% 224 66% 231 75% 236 80% 246 90% 314 95% 388 98% 435 99% 3247 100% 3247 (longest request)
  14. MAKING RAILS NOT SLOW NEW RELIC ▸ cloud performance monitoring

    ▸ easy setup ▸ slow transaction breakdown
  15. MAKING RAILS NOT SLOW UPGRADE RUBY VERSION ▸ Improved performance

    in ruby >2.0 ▸ rbenv for version management
  16. MAKING RAILS NOT SLOW DISABLE ASSET DEBUG MODE config.assets.debug =

    false development.rb shortens every page load by anywhere from 300 - 1000 ms
  17. MAKING RAILS NOT SLOW DISABLE ASSET DEBUG MODE DON’T I

    NEED THIS? config.assets.debug = true config.assets.debug = false ▸ separate file for each JS & CSS ▸ 300-1000+ ms ▸ multiple files (1:1) ▸ multiple downloads ▸ Concat JS & CSS ▸ <100ms ▸ 1 file ▸ 1 download
  18. MAKING RAILS NOT SLOW AVOID N+1 QUERIES @comments = Comment.limit(20)

    <% @comments.each do |comment| %> <%= comment.author.name %> <% end %>
  19. MAKING RAILS NOT SLOW AVOID N+1 QUERIES @comments = Comment.limit(20)

    <% @comments.each do |comment| %> <%= comment.author.name %> <% end %> 1 query 20 queries lazy load Check generated SQL in logs!
  20. MAKING RAILS NOT SLOW AVOID N+1 QUERIES @comments = Comment.includes(:author).limit(20)

    <% @comments.each do |comment| %> <%= comment.author.name %> <% end %> 2 queries eager load
  21. MAKING RAILS NOT SLOW ADD SQL INDEXES ▸ indexes can

    make a huge difference ▸ index foreign keys ▸ index full text queries ▸ index popular SQL queries ▸ don’t index everything
  22. MAKING RAILS NOT SLOW AVOID EXPENSIVE SQL ▸ avoid many

    joins ▸ avoid outer joins ▸ use SQL aggregates instead of rails code (sum, group by, …) ▸ use Model.select for large models
  23. MAKING RAILS NOT SLOW VIEW CACHING ▸ Great for popular

    complex views ▸ Simple to use ▸ Refresh on model updated_at
  24. MAKING RAILS NOT SLOW VIEW CACHING <% cache product do

    %> <%= product.name %> <% end %> cache key: views/products/1-201505056193031061005000/bea67108094918eeba42cd4a6e786901
  25. MAKING RAILS NOT SLOW VIEW CACHING ▸ enable in-memory caching

    in development ▸ memcached in production ▸ distributed memcached for cloud hosting
  26. MAKING RAILS NOT SLOW AVOID TURBOLINKS ▸ hard to reason

    about ▸ two types of page load ▸ must include scripts in head ▸ breaks third-party scripts ▸ broken back button on error ▸ clashes with interactive pages
  27. MAKING RAILS NOT SLOW AVOID HAML ▸ up to 10x

    slower than ERB ▸ large overhead under 300ms ▸ causes random GC ▸ terrible hash syntax for attributes
  28. MAKING RAILS NOT SLOW HAML ALTERNATIVES ▸ fastest ▸ default,

    well known ▸ designer friendly ERB SLIM ▸ as fast as ERB ▸ HAML done right ▸ can use for XML FAML / HAMLIT ▸ high-performance HAML reimplementation ▸ legacy projects?
  29. MAKING RAILS NOT SLOW AVOID COFFEESCRIPT INTERPOLATION index.html.haml :javascript var

    data = #{@data.to_json}; :coffeescript data = #{@data.to_json}
  30. MAKING RAILS NOT SLOW AVOID COFFEESCRIPT INTERPOLATION index.html.haml :javascript var

    data = #{@data.to_json}; :coffeescript data = #{@data.to_json} <1 ms Interpolates text 300 ms Compiles JS Each request:
  31. MAKING RAILS NOT SLOW WEBRICK ▸ Not good for production

    traffic ▸ Single-threaded ▸ Blocked by slow clients ▸ Inefficient for serving assets
  32. MAKING RAILS NOT SLOW MULTI-PROCESS ▸ run several app processes

    ▸ better concurrency ▸ limited by memory
  33. MAKING RAILS NOT SLOW GZIP ▸ compress responses & assets

    ▸ up to 90% compression ▸ always enable
  34. MAKING RAILS NOT SLOW ASSET CACHE HEADERS ▸ enable long-term

    cache headers on assets ▸ asset hash fingerprints for invalidation ▸ no headers by default in rails ▸ could use CDN for assets (e.g. Amazon Cloudfront)
  35. MAKING RAILS NOT SLOW PHUSION PASSENGER ▸ NGINX or Apache

    server ▸ GZIP & asset caching ▸ simple setup ▸ processes shared memory ▸ out-of-band GC
  36. MAKING RAILS NOT SLOW FRONTEND OPTIMIZATIONS ▸ gzip ▸ cache

    headers ▸ script at end of body ▸ lazy-load images ▸ YSlow, Google Page Speed
  37. MAKING RAILS NOT SLOW SUMMARY ▸ Performance matters ▸ Time

    = money ▸ Why is ruby slow ▸ Measure, then optimise ▸ Optimisation techniques ▸ Production settings