.

Coffee Powered

code and content

MongoMapper, Development Mode, and Memory Leaks

If you’ve worked with MongoMapper for a while, you’ve probably noticed that in complex apps, there are horrific memory leaks in development that magically disappear in production mode. While this is all well and good, and it’s rather handy that things Just Work in production, don’t you wish you didn’t have to restart your app server every 15 requests in development?

I set out to track down the cause tonight, and have both fixed the problem and gotten some handy experience debugging Rails apps with gdb.

Read More »

WillPaginate and custom paging.

will_paginate is the de facto Rails paging plugin, and with good reason – it’s solid, fast, and reliable. Everyone I know uses it, but a lot of people don’t use it to its full power.

I recently discovered some very cool functionality it includes – the WillPaginate::Collection class can be used as a custom paginator for effectively any enumerable collection. It’s very simple, too. I recently used it to build pages of the most popular tags on posts in my database. My data store is MongoDB, and I’m fetching an array consisting of two-element arrays, [tag, tag_count]. To use will_paginate’s functionality with this, I just use the following:

tags = Post.tag_counts(nil, {:sort => ["value", "descending"]}) # Return an array of tag/count pairs. Custom function, so it can't leverage the finder on Post.
@topics = WillPaginate::Collection.create(current_page, 20, tags.length) do |pager|
	pager.replace(tags.slice(pager.offset, pager.offset + pager.per_page))
end

current_page is a helper that derives the current page from the request parameters. The rest of it is self-explanitory. I can now use @topics in my page just as I’d use a paginated result set from the database.

- @topics.each do |topic|
    # ...
=will_paginate @topics

Bam. Doesn’t get much easier than that. You can get exceptionally creative with it, too. Effectively, all you need to know is:

  • WillPaginate::Collection#new takes 3 parameters: the current page, the per-page count, and optionally, the total number of entries.
  • The pager block variable exposes offset and per_page properties, prime for passing into a DB query or slicing an enumerable with
  • Call pager.replace(sub-array) with the current page’s set of elements.

That’s literally all there is to it. Now you can have easy pagination on just about any collection you can conceive of. Let WillPaginate handle all the heavy lifting and such. If you’ve done enough pagination by hand, you’ll probably appreciate the easy beauty of this particular method.

Setting up replica sets with MongoDB 1.6

Introduction

MongoDB 1.6 was released today, and it includes, among other things it includes support for the incredible sexy replica sets feature – basically master/slave replication on crack with automatic failover and the like. I’m setting it up, and figured I’d document the pieces as I walk through them.

My test deploy is going to consist of two nodes and one arbiter; production will have several more potential nodes. We aren’t worrying about sharding at this point, but 1.6 brings automatic sharding with it, as well, so we can enable that at a later point if we need to.
Read More »

Click mapping with HTML5 and node.js

I was recently in need of a click mapping solution, and didn’t like most of the solutions I came across. They had huge dependency chains and were generally unwieldy, or they didn’t work that well, or they were external services that I had to pay for…until I ran across heatmapthing. Now we’re talking. Client-side rendering of JSON location data – we’re in business!

First things first. If this is TL;DR for you, here’s the demo, or click the “Click Heatmap” button in the corner of this page.

My first iteration was an endpoint in my current Rails app, which handled saving/sending of click data. That worked fine, but for something as lightweight and common as a click, I didn’t want to be invoking my full Rails stack. I’ve also been meaning to play with node.js…well hey, there’s an opportunity here!

First, I had to get the client code working. I modified the existing heatmap code into a jQuery plugin, which handled all the setup/transmission/rendering of data. This enables you to do something like so:

$("#body_wrapper").clickhax({ trigger: "#showHeatmap", endpoint: "/map" });

What that does is attach the handlers to your wrapper element, and sets up the HTML5 canvas to display over that. Events will be sent to /map (which, in this example, is ProxyPassed to my node.js daemon), and clicking an element with an id of showHeatmap causes the heatmap data to be fetched and rendered on the client. The client itself just takes a raw JSON dataset and performs smoothing and rendering with it. It’s fairly basic canvas work – the majority of the heavy lifting is non-graphical – but still, it’ll only work in browsers that support the canvas tag. Sorry, oldschool IE users.

Okay, great, that’s working, what about the backend now?

Node.js is remarkably easy to get up and running on, and with the addition of the Express package, it behaves an awful lot like Sinatra. I’m using MongoDB as my backend store for this, which is handy, since it natively speaks JSON, and there are client libraries for node. Using the npm utility, I quickly had them installed and was up and running.

You can see the code on GitHub, but I’ll touch on the key points here first.

The biggest gotcha I ran into this was in my treatment of the database connection handling. It took me a little while to recognize that the calls being made are asynchronous. This is important. This is very important. Rather than writing it top-down like a Ruby script, I had to, as you can see, use the provided callback chains. In particular, in my get(“/”) handler, I was performing the query and then immediately trying to iterate the cursor – this doesn’t work! You have to iterate in the callback. (In my defense, it was late and my brain was foggy!)

The code is pretty straightforward, though. When you post to your endpoint, it accepts x and y parameters and parses out the referring URL as the click target page. The plugin computes the click as an offset from the top left corner of your wrapped element, so if you have a fixed-width wrapper, your click data remains consistent even with differing monitor sizes. Data is quantitized to 5px before storage, and storage is done with upserts and MongoDB’s atomic increment; multiple clicks in the same 5px square will simply increment a counter in that record, rather than saving a record per click.

Positions are indicated by assuming a maximum width of 3000px. This allows us to store positions as single integers, rather than position pairs or strings. The client plugin is aware of this, and can reverse a given index into an x/y pair accordingly. The getter simply constructs a hash of {position: click_count} and sends that to the client. The client then applies a blur pattern on top of those points to generate a smoothed heightfield, and then normalizes that heightfield to the 0..255 range. Those heights are then mapped to colors and rendered onto the canvas. That’s all there is to it!

Quantitizing to 5px squares means that for my 600×400 demo, I have 9600 potential squares, and each square takes 6-11 bytes of JSON to represent. Thus, even for a fully saturated clickmap, I should only ever have to receive/compute/render 103kb worth of data. That number of obviously increases as you increase the size of the target area – 960×2000 would be a maximum of 825kb of data for a fully saturated clickmap. However, in practice, full saturation should be a non-concern. Your clicks will be focused around interactable elements, and due to the atomic increment counters, heatmaps should remain light and snappy both for inserts and fetches, regardless of the number of clicks in a page.

If you don’t already have node.js and mongodb, the setup may be a bit more involved, but you could use PHP/MySQL, or Rails with SQLite or whatever as your endpoint server. The front and back ends are relatively decoupled, and can be re-used independently of each other.

FlexAuth: Portable authentication for Battle.net

I’ve just released my first Android app, called FlexAuth. It’s mostly an excuse to learn Android development, but it does something useful, too – it serves as a souped-up mobile authenticator for Blizzard’s Battle.net login infrastructure. If you’d like the gory details, there’s a specification floating around on the internet that’ll help you understand the protocol.


Mobile authenticators work by transforming a seed value (called the “token secret”) + the current time into your 8-digit authentication code. FlexAuth lets you set up multiple authenticators by providing the secret, or will let you have Blizzard generate one for you.

Why would you need this?

  • You want to use a mobile authenticator, but don’t want to be locked out if you ever lose your phone (just setup a new token with your registered token secret).
  • You want to use multiple mechanisms to log in – maybe you need token authentication in a script, or you want to have the same authenticator values on multiple mobile phones.
  • You already have a token secret from another source and want to use it on your mobile phone.

Obviously, these won’t apply to most people, but some folks will definitely find it useful.



Using it:

  1. Menu -> Add Account
  2. Enter a name for this token/account. It can be whatever you’d like.
  3. Either enter a serial + secret, or you can use the already-provided one, or generate a new one.
  4. Save the token. You’ll notice that auth codes start generating right away.
  5. It is highly recommended that you back up your token secret. If you uninstall the app, wipe your phone, etc, then you will lose the secret, and consequently lose the ability to generate auth codes. To back up a code, click into the token’s details, and long press on the secret to copy it. You can then paste it into a note or email or whatnot. To restore a token, simply generate a new token and use your backed up secret. It will generate compatible auth codes.

All that said, a word of caution: Never ever ever run authenticator software on the same machine that you’re logging in on. It’s bad, it’s dumb, and you shouldn’t do it. Keep your authentication token generation on a separate device if you value your account.

If any particular same-machine authentication scheme gained any measure of popularity, it would be targeted by malware and your authenticator would be useless. Don’t do it.

Other than that, enjoy!

Serving files out of GridFS, part 2

Since my initial experiments with GridFS and nginx-gridfs, I discovered a rather downer of a dealbreaker: compiling Passenger and nginx-gridfs into the same nginx binary makes nginx very unhappy. It hard-freezes (as in, blocks forever) when you request a GridFS file with Passenger enabled. Oops.

So, I sat down and fixed gridfs-fuse. You can grab my branch at GitHub. I made a few changes that make it ideal for serving files out of a GridFS DB, with a few caveats.
Read More »

Serving files out of GridFS

GridFS is a nifty little feature in MongoDB that allows you to store files of all shapes and sizes in Mongo itself, getting the benefits of Mongo’s sharding and replication. However, since they’re in a database, and not on the filesystem directly, how do we serve them?

There are lots of benchmarks and numbers under the cut. Keep reading!

Read More »

counter_cache for MongoMapper

I’ve started playing with MongoMapper, and it’s quite excellent, but it does suffer very much from being young. There are lots of pieces missing that veterans of ActiveRecord will take for granted. I’ve been working around or patching them, for the most part, but I felt that my solution to `:counter_cache` deserved a post.

In short, I didn’t want to hack around with the MongoMapper associations code, so I just implemented my own little ride-along version.

module SecretProject
  module CounterCache
    module ClassMethods
      def counter_cache(field)
        class_eval <<-EOF
          after_create "increment_counter_for_#{field}"
          after_destroy "decrement_counter_for_#{field}"
        EOF
      end
    end

    module InstanceMethods
      def method_missing(method, *args)
        if matches = method.to_s.match(/^(in|de)crement_counter_for_(.*)$/) then
          dir = matches[1] == "in" ? 1 : -1
          parent_association = matches[2]
          if parent = self.send(parent_association) then
            name = "#{self.class.to_s.tableize}_count"
            if parent.respond_to?(name)
              parent.collection.update({:_id => parent._id}, {"$inc" => {name => dir}})
            end
          end
        else
          super
        end
      end
    end

    def self.included(receiver)
      receiver.extend         ClassMethods
      receiver.send :include, InstanceMethods
    end
  end
end

Throw that into your lib directory, load it with an initializer, and then you can use it something like so:

class Foo
  include MongoMapper::Document
  include SecretProject::CounterCache

  belongs_to :user
  counter_cache :user  # Will cause a foos_count field on the owning user to be maintained when a Foo is created or deleted.
end

This’ll only increment a counter if you’ve defined one on your parent object, via key :foos_count, Integer or similar, just so that it doesn’t go around updating every model you might associate it with.

Yay.

Safe action caching with Memcached

I’ve started using action caching more aggressively, to handle a large volume of not-signed-in search traffic. It composes a significant chunk of my site’s total traffic, but there’s no good reason to be recomputing full pages for all those long-tail hits. So, the obvious thing is to just implement a quick action cache.

# Controller
caches_action :show, :unless => :user?, :expires_in => 24.hours
# Sweeper
expire_action :controller => "nodes", :action => "show", :id => record.to_param

This all works dandy, but I generate pretty URLs, which means sometimes there are characters in the URL that Memcached doesn’t like. A few minutes after deploying my patch, I started getting IMs from my logger bot telling me things were unhappy.

blippr. com: [#1265856785] ArgumentError: illegal character in key "views/m.blippr.com/apps/346562-PicFo g.mobile"
blippr. com: [#1265857710] ArgumentError: illegal character in key "views/www.blippr.com/apps/336714-µTorrent  "
blippr. com: [#1265857897] ArgumentError: illegal character in key "views/www.blippr.com/apps/337076-ustre am"
blippr. com: [#1265857924] ArgumentError: illegal character in key "views/www.blippr.com/apps/336714-µTorrent  "

That’s memcached complaining about the hash keys we’re giving to it. This just won’t do. We could just regex out “bad” characters, but that means potential collisions, and potentially leaves edge cases. Why not just hash it instead?

A quick monkey patch later:

class ActionController::Caching::Actions::ActionCachePath
	def path
		@cached_path ||= Digest::SHA1.hexdigest(@path)
	end
end

And we’re all dandy. Now, rather than caching by path, the path is hashed, and the hash is used as the path key. Since hashes will always be hexadecimal characters, we know that it’ll never make memcached unhappy.

Path is blippr.com/movies/6696-The-Silence-of-the-Lambs...
Cached fragment hit: views/9111cdefca4a52cb0e3a5ebac4f618127a30efd0 (1.1ms)

There is an argument for not using this technique if you’re using file-based caching, since it means your cached bits won’t be segregated into directories, but memcached doesn’t support expiry by regex anyhow, so there’s no good reason to not use it in this case.

Enjoy!

Eight tips for getting the most out of your Rails app

Rails does an awful lot to optimize page generation, but there are a number of hacks, tweaks, and usage patterns you should be using to get the most out of your app.

Configuration tweaks

There’s a lot of the Rails stack that’s written in Ruby, which is great – it’s portable, it’s flexible, it works out of the box. Unfortunately, for some things, this also means it’s slow. Other times, pieces of the framework aren’t implemented as optimally as they could be. What if you could improve your app’s performance just by installing a few gems and tweaking a few config parameters? Good news – it’s not hard.

1. Replace REXML with LibXML

By default, Rails uses a Ruby-native XML library called REXML. REXML is slow. REXML is very slow. REXML is personally responsible for me almost entirely giving up on Ruby due to a bad encounter with it in my first Ruby project. Fortunately, Rails provides a very easy way to avoid using REXML.

gem install libxml-ruby

Then, in your app’s config/environment.rb

ActiveSupport::XmlMini.backend = 'LibXML'

That’s it. Now, Rails will use the very lean, very fast libxml to parse XML documents, rather than the very fat, very slow REXML. If you’re doing feed parsing, Hash.from_xml, or anything of that nature, this will save you massive amounts of pain.

2. slim_attributes

If you’re using MySQL, there’s no reason why you shouldn’t be using slim_attributes.

Slim Attributes boosts speed in Mysql/Rails ActiveRecord Models by avoiding instantiating Hashes for each result row, and lazily instantiating attributes as needed.

Pretty self-explanatory. Rather than creating massive hashes of everything the DB gives you, slim_attributes causes ActiveRecord to only create ruby objects when you actually ask for them in code. This can reduce both your app’s memory usage and time spent on database queries. It’s not a massive increase, but given that it takes exactly one line of code to add to your project, there’s no reason not to use it.

3. slim_scrooge

From the developers of slim_attributes comes another drop-in database optimization.

SlimScrooge is an optimization layer to ensure your application only fetches the database content needed to minimize wire traffic, excessive SQL queries and reduce conversion overheads to native Ruby types.

SlimScrooge implements inline query optimisation, automatically restricting the columns fetched based on what was used during previous passes through the same part of your code.

Make your ORM work for you! By only fetching the content you need from your database, you reduce over-the-wire overhead, CPU overtime due to type conversion, and other such niceties. Again, just install the gem, require it in your project, and you’re off to the races.

4. fast_xs

By default, string escaping in Rails happens in native Ruby code. This is slow. We don’t like slow. This is particularly prominent in areas like Builder::XmlMarkup, which you are using if you have any templates like foo.xml.builder lying around.

In modestly-sized document, this can result in pretty substantial slowdown in view construction. Rather than re-hashing what others have already done, I’ll point you at Speed up your feed generation in Rails for the long and short on it all. This can result in builder views running upwards of 10x as fast, and all you have to do is install the fast_xs gem – Rails will automatically detect and patch it in if it’s on the system.

5. Erubis

Erubis benchmarks Erubis is an ERB implementation written in C, rather than in Ruby. As a result, it parses ERB templates very, very quickly. In fact, the Erubis benchmarks up it at upwards of 3x faster than the native ERB implementation. Installation is easy – just check the using Erubis with Ruby on Rails guide and you’re off to the races.

Do note that if you’re entirely using Haml or similar, Erubis won’t do much for you. Erubis is much faster than Haml, but Haml is much prettier than ERB. What you end up using is up to you!

Reduce action runtimes

6. Use delayed_job

Sometimes in the course of any web service, you run into some action that takes a little while to process. This is generally a pain and causes a whole host of problems, including frustrated users clicking refresh and spawning a dozen instances of your app all running the same long-running request and tying up valuable request slots. Long-running jobs, or jobs that absolutely must succeed are something of a royal pain in the patootie to handle gracefully. Fortunately, there’s DelayedJob, which is much like a double shot of Codine to ease that terrible pain.

The concept is pretty simple – rather than immediately executing a long-running task, you create a “job” for it, then use an asynchronous daemon to run your job for you.

For example, let’s say that your app wants to post to Twitter when you accomplish some task. This is all well and good if Twitter is up (ha!) and fast and isn’t experiencing any technical issues and you aren’t having any issues on your end and you don’t have any exceptions. In short, it’s fine when things don’t break, but we all know that things break and go wrong and generally end up sideways when you’re ever dealing with any kind of I/O, particularly of the remote web service kind. Rather than trying to post to Twitter in-process, we’ll create a job whose task is to post to Twitter.

Install the delayed_job gem, create the delayed_jobs table as indicated in its documentation, and write your first worker.

module Jobs
	class PostToTwitter < Struct.new(:username, :password, :tweet)
		def perform
			auth = Twitter::HTTPAuth.new(username, password)
			client = Twitter::Base.new(auth)
			client.update(tweet)
		end
	end
end

Now, in your controller code, or after_create in your model, or where ever, rather than posting to Twitter directly, just enqueue a job:


Delayed::Job.enqueue Jobs::PostToTwitter.new(params[:username], params[:password], params[:tweet])

Finally, you’ll want to fire up a DelayedJob daemon. This is pretty easy to do under Rails.

Create a file called script/worker.rb and stick the following in it:

#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))

daemon_options = {
  :multiple =>; false,
  :dir_mode => :normal,
  :dir => File.join(dir, 'tmp', 'pids'),
  :backtrace => true
}

Daemons.run_proc('job_runner', daemon_options) do
  if ARGV.include?('--')
    ARGV.slice! 0..ARGV.index('--')
  else
    ARGV.clear
  end

  Dir.chdir dir
  RAILS_ENV = ARGV.first || ENV['RAILS_ENV'] || 'development'
  require File.join('config', 'environment')

  Delayed::Worker.new.start
end

Now, all you have to do is call script/worker start and you’re up and running. Jobs will automatically be processed as they’re added to the queue. If they fail, the reason why will be logged and the job will be scheduled to be retried in the future. You can correct any mistakes and re-run the job and watch it happily succeed. If the mistake is on the remote end, then the worker will keep retrying it until it succeeds, and your user doesn’t have to sit there and wait while your app continually receives the API equivalent of the failwhale. Everyone is happy (eventually!)

Once you start using DelayedJob, you’ll find that there are lots of things you can do with it to smooth out your app’s user-response speed. Processing user avatars or large file uploads, recomputing expensive queries (like a social graph update), talking to remote web services, or even sending emails can all be moved away from the realtime and into the background with total ease.

7. Use memcached

This should probably be tip #1. Good caching can make or break a project, and memcached is a fantastic method for managing your caching.

Memcached is an in-memory key-value store for small chunks of arbitrary data (strings, objects) from results of database calls, API calls, or page rendering.

By default, Rails writes page and fragment cache bits to disk. This is slow, is difficult to clean up after, adds a lot of wear-and-tear to your disk, and is generally undesirable. It’s used because it’s easy. Memcached is a far better solution – it is very much a “giant hash table in the sky”. Dump a value into memory, read it back out of memory later. It is extremely fast, and comes with some super dandy features like time-based expiration that disk caching just won’t get you.

Implementation in Rails is easy. First, install both the memcached daemon and the memcache client. Second, in your environment file, add something like so:

require_library_or_gem 'memcache'
config.cache_store = :mem_cache_store, ["localhost:11211"]

By default, memcached runs on port 11211. Point Rails at it with the above directives and restart your app and that’s it. You’re running on memcached. No more ugly disk sweeping, and you get some really nice features. You can add multiple servers to the :mem_cache_store, too, which is several flavors of awesome. The memcached client will do automatic cluster management and balancing, so you can share the same cache between any number of servers, rather than each server having to have its own copy of that cache. Sweet!

<% cache("my_custom_fragment_name:#{@record_id}", :raw => true, :expires_in => 1.hour) do %>
	<%=render :partial => "some_expensive_partial", :object => @record %>
<% end %>

This is your standard fragment cache, but the :raw and :expires_in parameters are new.

:raw tells the Ruby memcached client to not marshal the content before sticking it in memcached. Since you’re just storing a document fragment (that is, a string), marshaling a ruby string and then unmarshaling it when you want to read it back is both unnecessary and slow.

:expires_in sets a maximum lifetime for this fragment. If we generate a fragment, memcached will timestamp it, and then if we try to read it back, say, 90 minutes later, memcached will recognize “oh hey, this fragment is expired! Sorry, I don’t have anything for you!”. Our view will regenerate and re-cache that fragment, and for the next 60 minutes, rather than trying to regenerate that fragment any time that view is called, it’ll just pull the cached copy from memcached.

If you need to ever flush your cache, it’s as easy as just restarting memcached. That’s it, really. In one fell swoop, you get faster caching (yay!), easier cache management (yay!), and a cache that can scale across multiple servers (double yay!)

8. Use etags

etags are a nifty little feature that are woefully under-used by most web developers. You can think of them as a fingerprint for a given page. Consider the following process:

  1. I request a page for the first time. The app generates the page and sends me both a copy of the page and a small hash finger print.
  2. I request the page a second time, and send the fingerprint of my cached copy back to the server.
  3. The server compares the fingerprint I sent with the fingerprint of its latest copy of the page. If they match, it just sends back a 304 Not Modified header and stops rendering

Sounds handy, right? Sure, and it’s really easy to implement in Rails. Let’s assume you have a BlogController which has a show method for showing a given blog post. You could use the following to implement etags:

def show
	@post = BlogPost.find params[:id]
	@comments = @post.comments.paginate params[:page], 25
	return unless stale? :etag => [@post, @comments]
end

Wait, that’s it? Yes, actually! What’s happening there is Rails builds a fingerprint of the object(s) you the :etag parameter of the stale? method. If the objects don’t change, then the etag doesn’t change. This means that you would get different etags for the same blog post on a different page of comments (good!), or a different etag if a comment is added (good!) or a different etag if the post is edited (good!), but as long as those objects haven’t changed since the user’s last request of that action, the etag will be the same, and the action will stop running right there and tell the browser to just display its cached copy.

On heavily-trafficked pages that aren’t easily customized on a global scale (for example, if you have custom per-user bits on the page that mean that you can’t serve the same page to everyone), this is a really decent way to prevent excessive and wasteful application work. If you don’t use the stale? method, Rails always assumes that the page is stale, and thus needs to be regenerated.

On something of a tangent, can also use stale? :last_modified => @post.updated_at to determine if a page is fresh or stale. However, this does have the drawback of not being compatible with pagination, or sorted views, or anything of that nature. By using etags, you can ensure that each unique data set gets its own etag, and thus, doesn’t have cache collisions.