We are using the rest-client gem in Ruby for automated testing of our REST API. However I noticed that on every single request it makes, it also does a DNS lookup for the host name. On the local environment if "localhost" is used the tests run fast, but if the proper hostname is used they take 2.5x the time, performing a huge number of DNS lookups.
I believe this issue is not related to rest-client in particular, but the base Ruby networking. I tried requiring 'resolv' and 'resolv-replace' but they did not help. 'dig' reports that the DNS query has a TTL of 1 hour.
Is there a way to make Ruby cache DNS requests? I could change the code to explicitly use the IP address, but that's the wrong place to fix the issue.
I'm running Ubuntu 12.04 and Ruby 1.9.3.
On Linux, there is no OS-level DNS caching unless a caching service such as Systemd-Resolved, DNSMasq, or Nscd is installed and running. The process of clearing the DNS cache is different depending on the Linux distribution and the caching service you're using.
Show activity on this post. If you are using nscd , you can view the contents (and possibly some other garbage), by showing the ASCII strings from the binary cache file. In Debian/Ubuntu, that file is /var/cache/nscd/hosts for the hosts/DNS cache, so you can run strings /var/cache/nscd/hosts to see the hosts in cache.
Disable DNS CacheLog in to your system with the user has sudo privileges and Edit NetworkManager configuration file in your favorite text editor. Now comment the following entry by added # symbol to start of line like below. Save the configuration file. Vi users use ESC + :wq to save file and quit.
You can use the dnsruby gem to resolve the name to an address, and then use the address in your calls.
#! /usr/bin/env ruby
# Gets the IP address of a host.
require 'dnsruby' # gem install dnsruby first, of course
def hostname_to_ip_addr(host_name)
query = Dnsruby::Message.new(host_name)
response = Dnsruby::Resolver.new.send_message(query)
response.answer[1].address
end
host_name = 'cnn.com'
ip_addr = hostname_to_ip_addr(host_name)
puts("Host name: #{host_name}, IP address: #{ip_addr}")
original code from this Gist
I got to this question looking for ruby dns caching and how resolv.rb
might use the TTL to cache dns requests.
Discovering the TTL of a dns record is a bit hidden in the api of resolv.rb
but it looks a little something like this:
def get_ip(hostname)
dns = Resolv.new
redis = Redis.new # storing in redis
ip = redis.get("ip:#{hostname}")
return ip unless ip.nil?
begin
resource = dns.getresource(hostname, Resolv::DNS::Resource::IN::A)
rescue Resolv::ResolvError
return false
end
# storing in redis for only as long as the TTL allows
redis.setex("ip:#{hostname}", resource.address.ttl, resource.address.to_s)
resource.address.to_s # IP address as string
end
Gist
Note: uses Redis as the cache.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With