Put Down the Hammer

On using the right tool for the job.

Tyler McMullen

Put Down the Hammer

Case Study: Tag Autocompleter

Tyler McMullen

Put Down the Hammer

The Naïve Solution

Tyler McMullen

Put Down the Hammer

The Naïve Solution

•Tag.find
:conditions
=>
[‘text
LIKE
?’,
...]

Tyler McMullen

Put Down the Hammer

The Naïve Solution

•Tag.find
:conditions
=>
[‘text
LIKE
?’,
...] •TagController#autocomplete

Tyler McMullen

Put Down the Hammer

That’s not so bad, is it?

Tyler McMullen

Put Down the Hammer

What is important for an autocompleter?

Tyler McMullen

Put Down the Hammer

SPEED

Tyler McMullen

Put Down the Hammer

Let’s enumerate the steps to get the tags.

Tyler McMullen

Put Down the Hammer

Ajax Call

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects Render JSON/HTML

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects Render JSON/HTML Respond
Unnecessary steps that take up most of the time!
Tyler McMullen

Put Down the Hammer

How can we do this more efficiently?

Tyler McMullen

Put Down the Hammer

First, ditch the database.

Tyler McMullen

Put Down the Hammer

ActiveRecord and MySQL are overkill.

Tyler McMullen

Put Down the Hammer

Use a Trie.

Tyler McMullen

Put Down the Hammer

Use a Trie.
(Shameless Plug: http://github.com/tyler/trie)

Tyler McMullen

Put Down the Hammer

B

E

E

Tyler McMullen

Put Down the Hammer

A B E E

R

Tyler McMullen

Put Down the Hammer

A

R

T

B

E

A

R

E

Tyler McMullen

Put Down the Hammer

Use the right data structure for the job.

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Tag.find MySQL full table scan Map rows to ActiveRecord objects Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Trie#children(prefix) Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Trie#children(prefix) Render JSON/HTML Respond
Our next victims!

Tyler McMullen

Put Down the Hammer

Next step is to sidestep the Rails app altogether.

Tyler McMullen

Put Down the Hammer

If not Rails... then what?!

Tyler McMullen

Put Down the Hammer

Tyler McMullen

Put Down the Hammer

Rack is awesome for little web services.

Tyler McMullen

Put Down the Hammer

•Fast

Tyler McMullen

Put Down the Hammer

•Fast •Low Memory Usage

Tyler McMullen

Put Down the Hammer

•Fast •Low Memory Usage •Easy

Tyler McMullen

Put Down the Hammer

class
Autocompleter 

def
initialize 



@trie
=
Trie.load_file(file,
/(\w+)\|(\d+)/) 

end 

def
call(env) 



req
=
Rack::Request.new(env) 



words
=
@trie.children(req.params['query'])[0,5] 



[
200, 





{
"Content‐Type"
=>
"text/html"
}, 





[words.to_json]
] 

end end

Tyler McMullen

Put Down the Hammer

What about routing?

Tyler McMullen

Put Down the Hammer

location
/autocomplete
{ proxy_pass
http://autocompleter;
 
 }

Tyler McMullen

Put Down the Hammer

location
/autocomplete
{ proxy_pass
http://autocompleter;
 
 }
(You are using Nginx, right?)

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Router Action Trie#children(prefix) Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Ajax Call Nginx Rack Service Trie#children(prefix) Render JSON/HTML Respond

Tyler McMullen

Put Down the Hammer

Does it really matter?

Tyler McMullen

Put Down the Hammer

It’s handling 200 requests per second.

Tyler McMullen

Put Down the Hammer

It’s handling 200 requests per second. On a single Thin instance.

Tyler McMullen

Put Down the Hammer

It’s handling 200 requests per second. On a single Thin instance. With a response time of 0.006s.

Tyler McMullen

Put Down the Hammer

It’s handling 200 requests per second. On a single Thin instance. With a response time of 0.006s. Takes up 18mb of ram.

Tyler McMullen

Put Down the Hammer

It’s handling 200 requests per second. On a single Thin instance. With a response time of 0.006s. Takes up 18mb of ram. And <1% cpu usage.

Tyler McMullen

Put Down the Hammer

It’s good for your users and your budget.

Tyler McMullen

Put Down the Hammer

Questions?

Tyler McMullen

Sign up to vote on this title
UsefulNot useful