Slideshare.net (beta)

 
Post to TwitterPost to Twitter
Post: 
Myspace Hi5 Friendster Xanga LiveJournal Facebook Blogger Tagged Typepad Freewebs BlackPlanet gigya icons

All comments

Add a comment on Slide 1

If you have a SlideShare account, login to comment; else you can comment as a guest


Showing 1-50 of 12 (more)

A Small Talk on Getting Big

From britt, 2 years ago

8274 views  |  0 comments  |  10 favorites  |  247 downloads
 

Categories

Add Category
 
 

Tags

performance scaling rails railsconfeurope07 twitter scalability deployment britt app design

more

 
 

Groups / Events

 
Embed
options

More Info

This slideshow is Public
Total Views: 8274
on Slideshare: 8274
from embeds: 0

Slideshow transcript

Slide 1: A Small Talk on Getting Big. Scaling a Rails App & all that Jazz.

Slide 2: Good Dog Picture.

Slide 3: Medium Dog.

Slide 4: Bad Dog Picture.

Slide 5: How did this Happen?

Slide 6: Mongrel Picture.

Slide 7: Too Much Time in the Application. Too Much Time in the Database.

Slide 8: A Really Cool Trick class ApplicationController < ActionController:Base include ResponseManagementAdditions after_filter :show_runtimes around_filter { |controller, action| controller.total_runtime = Benchmark.measure(&action).real } end

Slide 9: A Really Cool Trick module ResponseManagementAdditions def show_runtimes return if response.headers['Status'] == '304 Not Modified' || ! (response.body && response.body.respond_to?(:sub!)) db_runtime = ((0 + (@db_rt_before_render || 0) + (@db_rt_after_render || 0)) * 1000).truncate rendering_runtime = ((@rendering_runtime || 0) * 1000).truncate total_runtime = ((@total_runtime || 0) * 1000).truncate response.body.gsub!(/<\\/body><\\/html>$/, \"<!-- served to you through a copper wire by #{HOSTNAME} at #{Time.now.to_s(:short)} in #{total_runtime} ms (d #{db_runtime} / r #{rendering_runtime}). thank you, come again. --> \\n</body></html>\") end end

Slide 10: Two Ways People Design Sites. Over-architect. Under-architect.

Slide 11: Move Fast. Scale Quickly.

Slide 12: Too Much Time in the Application.

Slide 13: Abstract Long Running Processes to Daemons.

Slide 14: An Ugly but Amazingly Simple Queuing System.

Slide 15: class FooDaemon < TwitterDaemon::Base before_startup :set_fugly_dist_idx def process unprocessed_content do |c| increment_counter(:total) # Do work ... break unless running? end end ...

Slide 16: ... def unprocessed_content(&block) loop do content = ContentModel.pending_content(\"substring(truncate(id, 0),-2,1) = #{@fugly_dist_idx}\") messages.each { |message| yield message } sleep 1 if messages.nil? || messages.empty? end end def set_fugly_dist_idx @fugly_dist_idx = ARGV.find { |v| v.match(/[0-9]/) } raise \"You need to specify a dist idx between 0 and 9.\" unless @fugly_dist_idx @fugly_dist_idx = @fugly_dist_idx.to_i end end

Slide 17: A Better Queuing System.

Slide 18: Starling.

Slide 19: Distributed Queuing. Transactional Playback. Fast. Simple. Speaks Memcache's Language. 100% Pure Ruby.

Slide 20: Not Open Source.

Slide 21: (yet ...)

Slide 22: Too Much Time in the Database.

Slide 23: The Basics. Database 101. (I shouldn't need this slide in here.)

Slide 24: Index everything you will query on. Avoid complex joins. Use joint indices when you must join tables. Avoid scanning large sets of data.

Slide 25: Cache.

Slide 26: Cache.

Slide 27: Cache.

Slide 28: CACHE!

Slide 29: But How? That Sounds Hard.

Slide 30: Turns Out it Isn't.

Slide 31: Serialize, Denormalize.

Slide 32: class User < ActiveRecord::Base serialize :following_ids def following_ids # this accessor is overwritten because we want to lazily set the # friends_ids column, rather than running a gigantic slow migration. RAILS_DEFAULT_LOGGER.debug \"loading following_ids\" ids = read_attribute(:following_ids) if ids.nil? || !ids.kind_of?(Array) ids = connection.select_values(\"SELECT DISTINCT followed_user_id FROM followed_users WHERE user_id = #{self.id}\").map(&:to_i).compact update_attribute(:following_ids, ids) end ids end ...

Slide 33: def following_ids_add(the_id) ids = self.following_ids.dup ids << the_id write_attribute(:following_ids, ids) end def following_ids_delete(the_id) ids = self.following_ids.dup ids.delete(the_id) write_attribute(:following_ids, ids) end end # End Class

Slide 34: Oh yeah, and Cheat. (It's ok!)

Slide 35: Thing about your application. How can you cheat and get away with it?

Slide 36: Is your data delivered in real time? Is your data static content? How do users interact?

Slide 37: Interestingness. (Little things that don't deserve other space.)

Slide 38: It's OK to use Monit to kill processes if they get too big.

Slide 39: Ensure you can deploy frequently.

Slide 40: Ensure you can roll back easily.

Slide 41: Scale where it matters.

Slide 42: Some code is ugly. It's OK. (who needs a hug?)

Slide 43: Ensure your users can give feedback easily.

Slide 44: Use the Community.

Slide 45: Make an API. (Scale your Developer-base.)

Slide 46: We run on Edge (but with Piston).

Slide 47: A Cool Trick. Gems in Vendor. Rails::Initializer.run do |config| # Load Gems from the /vendor/gems folder first, if they exist. config.load_paths += Dir[\"#{RAILS_ROOT}/vendor/gems/**\"].map do |dir| File.directory?(lib = \"#{dir}/lib\") ? lib : dir end ...

Slide 48: Personal Pet Peeve. It's 2007. Every spammer has your email address. Put it on your goddamn webpage so people can get ahold of you about interesting things.

Slide 49: Questions?

Slide 50: Britt Selvitelle IM & Email anotherbritt@gmail.com