Slideshare.net (beta)

 
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 10 (more)

A Small Talk on Getting Big

From britt, 9 months ago

6818 views  |  0 comments  |  8 favorites  |  235 downloads
 

Tags

performance scaling rails railsconfeurope07 twitter scalability britt app design rubyonrails

more

 
 
 
 

Privacy InfoNew!

This slideshow is Public

 
Embed in your blog
Embed (wordpress.com)
custom

Slideshow Statistics
Total Views: 6818
on Slideshare: 6818
from embeds: 0* * Views from embeds since 21 Aug, 07

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