Fast & Scalable

Fast & Scalable

This is a presentation I gave at Hungry Academy on making a Rails App fast & scalable. Covers the Front and backend and talks about speed and throughput optimizations.

Db953d125f5cc49756edb6149f1b813e?s=128

Richard Schneeman

July 16, 2012
Tweet

Transcript

  1. FAST Adjunct Professor: Richard Schneeman @schneems

  2. Hello

  3. $ whoami schneems

  4. Mechanical Engineer

  5. I Code

  6. Sextant Gem

  7. Wicked ‘ ‘ Gem

  8. None
  9. Adjunct Professor

  10. Good News Everyone!

  11. I <3 Tacos

  12. Speed Vs Throughput

  13. Speed

  14. Throughput

  15. Both Are Important

  16. 2 common Patterns

  17. Optimize & Cache for speed

  18. Optimization: Search for slow

  19. Optimization: Make it fast

  20. Caching: Search for expensive

  21. Caching: Make it cheap

  22. Add capacity for throughput

  23. Speed helps throughput

  24. Speed First

  25. Client Side vs Server Side

  26. Page Load Cycle } Server Side

  27. Back End Speed

  28. Measure

  29. Potential Causes of slow

  30. Inefficient Code

  31. Slow IO (database)

  32. Maybe it’s the language

  33. Tweak GC

  34. How do we find our problem?

  35. Look for N+1 Queries

  36. Use Logs

  37. Problem @products = Product.all # ... <% @products.each do |product|

    %> <li><%= product.name %></li> <li>$<%= product.price %></li> <li><%= product.user.name %></li> ...
  38. Problem

  39. Fix With Eager Loading

  40. Solved @products = Product.includes(:user).all # ... <% @products.each do |product|

    %> <li><%= product.name %></li> <li>$<%= product.price %></li> <li><%= product.user.name %></li> ...
  41. Solved

  42. Look for Queries not Using an index

  43. Use Logs

  44. config/production.rb config. active_record. auto_explain_threshold_in_seconds = 1

  45. Add Indexes

  46. Use A Monitoring Software

  47. New Relic

  48. Scout etc.

  49. Cache Expensive Queries

  50. Expensive Query Benchmark.measure do User.some_expensive_query end.real => 20s

  51. Use Memcache & Rails.cache

  52. Cache Query Benchmark.measure do Rails.cache.fetch(“cache_key”) do User.some_expensive_query end end.real =>

    20.5s Slower first time
  53. Cache Query Benchmark.measure do Rails.cache.fetch(“cache_key”) do User.some_expensive_query end end.real =>

    0.00001s Crazy fast after that
  54. Naming things & cache invalidation

  55. Method Cacheable gem

  56. Cache Query User.cache.some_expensive_query => 20.5s Slower first time

  57. Cache Query User.cache.some_expensive_query => 0.00001s Crazy fast after that

  58. Throughput

  59. Compounding Traffic writes on. Wikipedia

  60. Compounding Traffic edits on. Wikipedia

  61. View Caching

  62. Never worked well for me

  63. View Fragment Caching

  64. Nested View Fragment Caching

  65. cache_digests gem

  66. Split up Web/ Workers/ Datastores

  67. Web Runs Ruby code & handles requests

  68. Datastores run separately

  69. Workers handle non request processing

  70. Workers: Run resque, send email, etc.

  71. I ran out of capacity, now what?

  72. Scale UP

  73. None
  74. Scale OUT

  75. None
  76. Scaling up is Easy but limited

  77. Scaling out is hard but unlimited

  78. Ephemeral Web Machines

  79. Heroku $ heroku ps:scale web=4

  80. Amazon (AWS) Provision instances & use chef or other tools

    to install proper software, and then connect to a load balancer
  81. Code Code Code Code Code

  82. Don’t store state on server

  83. Store in database

  84. Session

  85. S3 etc.

  86. Workers: Headless data crunchers

  87. Workers run: Resque

  88. How do we scale data storage?

  89. Master DB Slave DB Slave DB Slave DB Slave DB

    Write Copy Read Master/Slave
  90. Users in USA Read Sharding Write Users in Europe Users

    in Asia Users in Africa
  91. cannot join against sharded data

  92. Facebook shards mysql

  93. Instagram shards postgresql

  94. postgresql better than mysql IMHO

  95. NoSQL

  96. Not a magic bullet

  97. Key Value Example > redis = Redis.new > redis.set(“foo”, “bar”)

  98. Key Value Example > redis = Redis.new > redis.set(“foo”, “bar”)

    > redis.get(“foo”)
  99. Key Value Example > redis = Redis.new > redis.set(“foo”, “bar”)

    > redis.get(“foo”) => “bar”
  100. Every datastore will punch you in the face “ -Adam

    Keys
  101. Key/Value Stores

  102. Shard on Key

  103. Consistent Hashing

  104. Memcache Distributed B C A

  105. Memcache Distributed B C A Easily add more nodes D

  106. CAP Theorem

  107. Pick Two: Consistency Availability Partition- Tolerance

  108. Riak Distributed B C A Eventual Consistency D Data In

    Copied To Extra Nodes ... Eventually
  109. RIAK has configurable CAP

  110. Client Side Speed

  111. Page Load Cycle } Client Side

  112. Front End Assets

  113. Loading Assets: Slow

  114. Decrease Size

  115. GZIP

  116. CDN

  117. Speed = Distance/ Time

  118. Distance Matters

  119. Shorter Distance = faster

  120. Your Server User

  121. None
  122. What if We could...

  123. None
  124. CDN

  125. CDN Content Distribution Network

  126. CDN CDN CDN

  127. CDN Serves Images CSS Javascript

  128. Akamai Cloudfront

  129. config/production.rb config.action_controller.asset_host = ENV["cloudfront_url"]

  130. Browser Caching

  131. Load on: First Request

  132. Store it

  133. Use local copy on future requests

  134. Expires Headers

  135. config/production.rb config.static_cache_control = "public, max-age=2592000"

  136. Wait, what happens if we make changes?

  137. Turn on Rails Asset fingerprints

  138. config/production.rb config.assets.digest = true

  139. HASH a file to take it’s “fingerprint”

  140. MD5 is an algorithm to fingerprint files

  141. headers.css 908e25f4bf641868d86 83022a5b62f54 Run MD5 on this: Produces this:

  142. When file changes, so does fingerprint

  143. headers.css headers- 908e25f4bf641868d86 83022a5b62f54.css File w/o fingerprint File with fingerprint:

  144. Measure to Optimize

  145. Use YSlow

  146. None
  147. Compress Assets

  148. Serve Using CDN

  149. Async Script Loading

  150. <script async src="siteScript.js"> </script>

  151. <script defer src="siteScript.js"> </script>

  152. defer guarantees order

  153. defer has IE support

  154. Don’t block page parsing

  155. Measure Everything

  156. Scale out with more machines

  157. Speed up your datastore or add caching

  158. (jobs.heroku.com)

  159. None
  160. Questions?