Skip to content

Commit

Permalink
Remove host splitting from load balancer
Browse files Browse the repository at this point in the history
  • Loading branch information
Will Fitzgerald committed Oct 29, 2012
1 parent a8691ac commit dcffe44
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 34 deletions.
2 changes: 2 additions & 0 deletions Gemfile.lock
Expand Up @@ -41,6 +41,7 @@ GEM
rspec-expectations (2.8.0)
diff-lcs (~> 1.1.2)
rspec-mocks (2.8.0)
ruby-prof (0.11.2)
typhoeus (0.3.3)
mime-types
vcr (1.11.3)
Expand All @@ -56,6 +57,7 @@ DEPENDENCIES
autotest-rails-pure
rake
rspec (~> 2.8.0)
ruby-prof
vcr (~> 1.11.3)
webmock (>= 1.6.2)
wordnik!
4 changes: 4 additions & 0 deletions lib/wordnik/configuration.rb
Expand Up @@ -60,6 +60,10 @@ def base_url
)
end

def clear
initialize
end

def host
@load_balancer ? @load_balancer.host : @host
end
Expand Down
32 changes: 18 additions & 14 deletions lib/wordnik/load_balancer.rb
Expand Up @@ -16,41 +16,45 @@ class LoadBalancer
attr_reader :hosts
attr_accessor :all_hosts
attr_accessor :failed_hosts_table
attr_accessor :current_host

def initialize(hosts)
@all_hosts = hosts
@hosts = @all_hosts
@failed_hosts_table = {}
@current_host = nil
end

def host
h = hosts.first
@current_host = hosts.first
@hosts.rotate!
restore_failed_hosts_maybe
h
@current_host
end

def inform_failure(host)
#Wordnik.logger.debug "Informing failure about #{host}. table: #{@failed_hosts_table.inspect}"
if @failed_hosts_table.include?(host)
failures, failed_time = @failed_hosts_table[host]
@failed_hosts_table[host] = [failures+1, failed_time]
def inform_failure
#Wordnik.logger.debug "Informing failure about #{@current_host}. table: #{@failed_hosts_table.inspect}"
if @failed_hosts_table.include?(@current_host)
failures, failed_time = @failed_hosts_table[@current_host]
@failed_hosts_table[@current_host] = [failures+1, failed_time]
else
@failed_hosts_table[host] = [1, Time.now.to_f] # failure count, first failure time
@failed_hosts_table[@current_host] = [1, Time.now.to_f] # failure count, first failure time
end
#Wordnik.logger.debug "Informed failure about #{host}. table now: #{@failed_hosts_table.inspect}"
@hosts.delete(host)
@hosts = [host] if @hosts.size == 0 # got to have something!
#Wordnik.logger.debug "Informed failure about #{@current_host}. table now: #{@failed_hosts_table.inspect}"
@hosts.delete(@current_host)
@hosts = [@current_host] if @hosts.size == 0 # got to have something!
end

# success here means just that a successful connection was made
# and the website didn't time out.
def inform_success(host)
@failed_hosts_table.delete(host)
@hosts << host unless @hosts.include? host
def inform_success
@failed_hosts_table.delete(@current_host)
@hosts << @current_host unless @hosts.include? @current_host
@hosts
end

def restore_failed_hosts_maybe
return if @failed_hosts_table.size == 0
@failed_hosts_table.each do |host, pair|
failures, failed_time = pair
seconds_since_first_failure = (Time.now.to_f - failed_time)
Expand Down
10 changes: 4 additions & 6 deletions lib/wordnik/request.rb
Expand Up @@ -165,18 +165,16 @@ def make(attempt = 0)
resp = request.response

if Wordnik.configuration.load_balancer
_,_,host,port,_ = URI::split(u)
host = "#{host}:#{port}" if port
if (resp.timed_out? || resp.code == 0)
# Wordnik.logger.debug "informing load balancer about failure at #{host}"
Wordnik.configuration.load_balancer.inform_failure(host)
# Wordnik.logger.debug "informing load balancer about failure"
Wordnik.configuration.load_balancer.inform_failure
if (attempt <= 3)
# Wordnik.logger.debug "Trying again after failing #{attempt} times..."
return make(attempt + 1) if attempt <= 3 # try three times to get a result...
end
else
# Wordnik.logger.debug "informing load balancer about success at #{host}"
Wordnik.configuration.load_balancer.inform_success(host)
# Wordnik.logger.debug "informing load balancer about success"
Wordnik.configuration.load_balancer.inform_success
end
end

Expand Down
150 changes: 136 additions & 14 deletions spec/performance.rb
@@ -1,18 +1,140 @@
require 'spec_helper'
require 'ruby-prof'

describe "Wordnik performance" do
configure_wordnik
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
start_time = Time.now
Wordnik.logger.debug "Starting at #{start_time}"
found = 0
defs = 0
examples = 0
words.each do |word|
found += 1 if Wordnik.word.get_word(word)["id"]==0
defs += Wordnik.word.get_definitions(word).size
examples += Wordnik.word.get_examples(word).size
describe "Load Balancer Performance" do

describe "With single host -- host performance" do
Wordnik.configuration.clear
Wordnik.configure do |config|
config.api_key = CREDENTIALS[:api_key]
config.username = CREDENTIALS[:username]
config.password = CREDENTIALS[:password]
config.logger = Logger.new('/dev/null')
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
config.hosts = []
config.base_path = CREDENTIALS[:base_path] || '/v4'
end
start_time = Time.now
RubyProf.start
100000.times {|i| host = Wordnik.configuration.host}
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
end

describe "With multiple hosts -- host performance" do
Wordnik.configuration.clear
Wordnik.configure do |config|
config.api_key = CREDENTIALS[:api_key]
config.username = CREDENTIALS[:username]
config.password = CREDENTIALS[:password]
config.logger = Logger.new('/dev/null')
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
config.hosts = CREDENTIALS[:hosts] || ['ec2-50-18-25-12.us-west-1.compute.amazonaws.com',' ec2-50-18-67-92.us-west-1.compute.amazonaws.com']
config.base_path = CREDENTIALS[:base_path] || '/v4'
end
start_time = Time.now
RubyProf.start
100000.times {|i| host = Wordnik.configuration.host}
result = RubyProf.stop
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
end
total = Time.now - start_time
Wordnik.logger.debug "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} milliseconds"

end

describe "Wordnik GET performance" do

describe "With single host" do
RubyProf.start
Wordnik.configuration.clear
Wordnik.configure do |config|
config.api_key = CREDENTIALS[:api_key]
config.username = CREDENTIALS[:username]
config.password = CREDENTIALS[:password]
config.logger = Logger.new('/dev/null')
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
config.hosts = []
config.base_path = CREDENTIALS[:base_path] || '/v4'
end
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
start_time = Time.now
Wordnik.logger.debug "Starting at #{start_time}"
found = 0
defs = 0
examples = 0
words.each do |word|
found += 1 if Wordnik.word.get_word(word)["id"]==0
defs += Wordnik.word.get_definitions(word).size
examples += Wordnik.word.get_examples(word).size
end
total = Time.now - start_time
result = RubyProf.stop
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
end

describe "With two hosts" do
RubyProf.start
Wordnik.configuration.clear
Wordnik.configure do |config|
config.api_key = CREDENTIALS[:api_key]
config.username = CREDENTIALS[:username]
config.password = CREDENTIALS[:password]
config.logger = Logger.new('/dev/null')
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
config.hosts = CREDENTIALS[:hosts] || ['ec2-50-18-25-12.us-west-1.compute.amazonaws.com',' ec2-50-18-67-92.us-west-1.compute.amazonaws.com']
config.base_path = CREDENTIALS[:base_path] || '/v4'
end
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
start_time = Time.now
Wordnik.logger.debug "Starting at #{start_time}"
found = 0
defs = 0
examples = 0
words.each do |word|
found += 1 if Wordnik.word.get_word(word)["id"]==0
defs += Wordnik.word.get_definitions(word).size
examples += Wordnik.word.get_examples(word).size
end
total = Time.now - start_time
result = RubyProf.stop
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
end

describe "With three hosts -- one invalid" do
RubyProf.start
Wordnik.configuration.clear
Wordnik.configure do |config|
config.api_key = CREDENTIALS[:api_key]
config.username = CREDENTIALS[:username]
config.password = CREDENTIALS[:password]
config.logger = Logger.new('/dev/null')
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
config.hosts = CREDENTIALS[:hosts] || ['ec2-50-18-25-12.us-west-1.compute.amazonaws.com',
'ec2-50-18-67-92.us-west-1.compute.amazonaws.com',
'localhost']
config.base_path = CREDENTIALS[:base_path] || '/v4'
end
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
start_time = Time.now
Wordnik.logger.debug "Starting at #{start_time}"
found = 0
defs = 0
examples = 0
words.each do |word|
found += 1 if Wordnik.word.get_word(word)["id"]==0
defs += Wordnik.word.get_definitions(word).size
examples += Wordnik.word.get_examples(word).size
end
total = Time.now - start_time
result = RubyProf.stop
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
end

end
1 change: 1 addition & 0 deletions wordnik.gemspec
Expand Up @@ -27,6 +27,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'autotest'
s.add_development_dependency 'autotest-rails-pure'
s.add_development_dependency 'rake'
s.add_development_dependency 'ruby-prof'

s.files = [
`git ls-files`,
Expand Down

0 comments on commit dcffe44

Please sign in to comment.