Skip to content

Commit dcffe44

Browse files
author
Will Fitzgerald
committed
Remove host splitting from load balancer
1 parent a8691ac commit dcffe44

File tree

6 files changed

+165
-34
lines changed

6 files changed

+165
-34
lines changed

Gemfile.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ GEM
4141
rspec-expectations (2.8.0)
4242
diff-lcs (~> 1.1.2)
4343
rspec-mocks (2.8.0)
44+
ruby-prof (0.11.2)
4445
typhoeus (0.3.3)
4546
mime-types
4647
vcr (1.11.3)
@@ -56,6 +57,7 @@ DEPENDENCIES
5657
autotest-rails-pure
5758
rake
5859
rspec (~> 2.8.0)
60+
ruby-prof
5961
vcr (~> 1.11.3)
6062
webmock (>= 1.6.2)
6163
wordnik!

lib/wordnik/configuration.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ def base_url
6060
)
6161
end
6262

63+
def clear
64+
initialize
65+
end
66+
6367
def host
6468
@load_balancer ? @load_balancer.host : @host
6569
end

lib/wordnik/load_balancer.rb

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,45 @@ class LoadBalancer
1616
attr_reader :hosts
1717
attr_accessor :all_hosts
1818
attr_accessor :failed_hosts_table
19+
attr_accessor :current_host
20+
1921
def initialize(hosts)
2022
@all_hosts = hosts
2123
@hosts = @all_hosts
2224
@failed_hosts_table = {}
25+
@current_host = nil
2326
end
2427

2528
def host
26-
h = hosts.first
29+
@current_host = hosts.first
2730
@hosts.rotate!
2831
restore_failed_hosts_maybe
29-
h
32+
@current_host
3033
end
3134

32-
def inform_failure(host)
33-
#Wordnik.logger.debug "Informing failure about #{host}. table: #{@failed_hosts_table.inspect}"
34-
if @failed_hosts_table.include?(host)
35-
failures, failed_time = @failed_hosts_table[host]
36-
@failed_hosts_table[host] = [failures+1, failed_time]
35+
def inform_failure
36+
#Wordnik.logger.debug "Informing failure about #{@current_host}. table: #{@failed_hosts_table.inspect}"
37+
if @failed_hosts_table.include?(@current_host)
38+
failures, failed_time = @failed_hosts_table[@current_host]
39+
@failed_hosts_table[@current_host] = [failures+1, failed_time]
3740
else
38-
@failed_hosts_table[host] = [1, Time.now.to_f] # failure count, first failure time
41+
@failed_hosts_table[@current_host] = [1, Time.now.to_f] # failure count, first failure time
3942
end
40-
#Wordnik.logger.debug "Informed failure about #{host}. table now: #{@failed_hosts_table.inspect}"
41-
@hosts.delete(host)
42-
@hosts = [host] if @hosts.size == 0 # got to have something!
43+
#Wordnik.logger.debug "Informed failure about #{@current_host}. table now: #{@failed_hosts_table.inspect}"
44+
@hosts.delete(@current_host)
45+
@hosts = [@current_host] if @hosts.size == 0 # got to have something!
4346
end
4447

4548
# success here means just that a successful connection was made
4649
# and the website didn't time out.
47-
def inform_success(host)
48-
@failed_hosts_table.delete(host)
49-
@hosts << host unless @hosts.include? host
50+
def inform_success
51+
@failed_hosts_table.delete(@current_host)
52+
@hosts << @current_host unless @hosts.include? @current_host
5053
@hosts
5154
end
5255

5356
def restore_failed_hosts_maybe
57+
return if @failed_hosts_table.size == 0
5458
@failed_hosts_table.each do |host, pair|
5559
failures, failed_time = pair
5660
seconds_since_first_failure = (Time.now.to_f - failed_time)

lib/wordnik/request.rb

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -165,18 +165,16 @@ def make(attempt = 0)
165165
resp = request.response
166166

167167
if Wordnik.configuration.load_balancer
168-
_,_,host,port,_ = URI::split(u)
169-
host = "#{host}:#{port}" if port
170168
if (resp.timed_out? || resp.code == 0)
171-
# Wordnik.logger.debug "informing load balancer about failure at #{host}"
172-
Wordnik.configuration.load_balancer.inform_failure(host)
169+
# Wordnik.logger.debug "informing load balancer about failure"
170+
Wordnik.configuration.load_balancer.inform_failure
173171
if (attempt <= 3)
174172
# Wordnik.logger.debug "Trying again after failing #{attempt} times..."
175173
return make(attempt + 1) if attempt <= 3 # try three times to get a result...
176174
end
177175
else
178-
# Wordnik.logger.debug "informing load balancer about success at #{host}"
179-
Wordnik.configuration.load_balancer.inform_success(host)
176+
# Wordnik.logger.debug "informing load balancer about success"
177+
Wordnik.configuration.load_balancer.inform_success
180178
end
181179
end
182180

spec/performance.rb

Lines changed: 136 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,140 @@
11
require 'spec_helper'
2+
require 'ruby-prof'
23

3-
describe "Wordnik performance" do
4-
configure_wordnik
5-
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
6-
start_time = Time.now
7-
Wordnik.logger.debug "Starting at #{start_time}"
8-
found = 0
9-
defs = 0
10-
examples = 0
11-
words.each do |word|
12-
found += 1 if Wordnik.word.get_word(word)["id"]==0
13-
defs += Wordnik.word.get_definitions(word).size
14-
examples += Wordnik.word.get_examples(word).size
4+
describe "Load Balancer Performance" do
5+
6+
describe "With single host -- host performance" do
7+
Wordnik.configuration.clear
8+
Wordnik.configure do |config|
9+
config.api_key = CREDENTIALS[:api_key]
10+
config.username = CREDENTIALS[:username]
11+
config.password = CREDENTIALS[:password]
12+
config.logger = Logger.new('/dev/null')
13+
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
14+
config.hosts = []
15+
config.base_path = CREDENTIALS[:base_path] || '/v4'
16+
end
17+
start_time = Time.now
18+
RubyProf.start
19+
100000.times {|i| host = Wordnik.configuration.host}
20+
result = RubyProf.stop
21+
printer = RubyProf::FlatPrinter.new(result)
22+
printer.print(STDOUT)
23+
end
24+
25+
describe "With multiple hosts -- host performance" do
26+
Wordnik.configuration.clear
27+
Wordnik.configure do |config|
28+
config.api_key = CREDENTIALS[:api_key]
29+
config.username = CREDENTIALS[:username]
30+
config.password = CREDENTIALS[:password]
31+
config.logger = Logger.new('/dev/null')
32+
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
33+
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']
34+
config.base_path = CREDENTIALS[:base_path] || '/v4'
35+
end
36+
start_time = Time.now
37+
RubyProf.start
38+
100000.times {|i| host = Wordnik.configuration.host}
39+
result = RubyProf.stop
40+
printer = RubyProf::FlatPrinter.new(result)
41+
printer.print(STDOUT)
1542
end
16-
total = Time.now - start_time
17-
Wordnik.logger.debug "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} milliseconds"
43+
1844
end
45+
46+
describe "Wordnik GET performance" do
47+
48+
describe "With single host" do
49+
RubyProf.start
50+
Wordnik.configuration.clear
51+
Wordnik.configure do |config|
52+
config.api_key = CREDENTIALS[:api_key]
53+
config.username = CREDENTIALS[:username]
54+
config.password = CREDENTIALS[:password]
55+
config.logger = Logger.new('/dev/null')
56+
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
57+
config.hosts = []
58+
config.base_path = CREDENTIALS[:base_path] || '/v4'
59+
end
60+
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
61+
start_time = Time.now
62+
Wordnik.logger.debug "Starting at #{start_time}"
63+
found = 0
64+
defs = 0
65+
examples = 0
66+
words.each do |word|
67+
found += 1 if Wordnik.word.get_word(word)["id"]==0
68+
defs += Wordnik.word.get_definitions(word).size
69+
examples += Wordnik.word.get_examples(word).size
70+
end
71+
total = Time.now - start_time
72+
result = RubyProf.stop
73+
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
74+
printer = RubyProf::FlatPrinter.new(result)
75+
printer.print(STDOUT)
76+
end
77+
78+
describe "With two hosts" do
79+
RubyProf.start
80+
Wordnik.configuration.clear
81+
Wordnik.configure do |config|
82+
config.api_key = CREDENTIALS[:api_key]
83+
config.username = CREDENTIALS[:username]
84+
config.password = CREDENTIALS[:password]
85+
config.logger = Logger.new('/dev/null')
86+
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
87+
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']
88+
config.base_path = CREDENTIALS[:base_path] || '/v4'
89+
end
90+
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
91+
start_time = Time.now
92+
Wordnik.logger.debug "Starting at #{start_time}"
93+
found = 0
94+
defs = 0
95+
examples = 0
96+
words.each do |word|
97+
found += 1 if Wordnik.word.get_word(word)["id"]==0
98+
defs += Wordnik.word.get_definitions(word).size
99+
examples += Wordnik.word.get_examples(word).size
100+
end
101+
total = Time.now - start_time
102+
result = RubyProf.stop
103+
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
104+
printer = RubyProf::FlatPrinter.new(result)
105+
printer.print(STDOUT)
106+
end
107+
108+
describe "With three hosts -- one invalid" do
109+
RubyProf.start
110+
Wordnik.configuration.clear
111+
Wordnik.configure do |config|
112+
config.api_key = CREDENTIALS[:api_key]
113+
config.username = CREDENTIALS[:username]
114+
config.password = CREDENTIALS[:password]
115+
config.logger = Logger.new('/dev/null')
116+
config.host = CREDENTIALS[:host] = 'api.wordnik.com'
117+
config.hosts = CREDENTIALS[:hosts] || ['ec2-50-18-25-12.us-west-1.compute.amazonaws.com',
118+
'ec2-50-18-67-92.us-west-1.compute.amazonaws.com',
119+
'localhost']
120+
config.base_path = CREDENTIALS[:base_path] || '/v4'
121+
end
122+
words = File.open(File.dirname(__FILE__) + "/100words.txt").readlines.map{|w| w.strip}
123+
start_time = Time.now
124+
Wordnik.logger.debug "Starting at #{start_time}"
125+
found = 0
126+
defs = 0
127+
examples = 0
128+
words.each do |word|
129+
found += 1 if Wordnik.word.get_word(word)["id"]==0
130+
defs += Wordnik.word.get_definitions(word).size
131+
examples += Wordnik.word.get_examples(word).size
132+
end
133+
total = Time.now - start_time
134+
result = RubyProf.stop
135+
STDOUT.puts "Found #{found} words out of #{words.size}; #{defs} definitions; #{examples} examples in #{total} seconds"
136+
printer = RubyProf::FlatPrinter.new(result)
137+
printer.print(STDOUT)
138+
end
139+
140+
end

wordnik.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
2727
s.add_development_dependency 'autotest'
2828
s.add_development_dependency 'autotest-rails-pure'
2929
s.add_development_dependency 'rake'
30+
s.add_development_dependency 'ruby-prof'
3031

3132
s.files = [
3233
`git ls-files`,

0 commit comments

Comments
 (0)