Skip to content

Warmed up cache slows the query #216

@heaven

Description

@heaven

The problem

Initial query on a cold cache executes faster than with a warmed one.

Reproduction

Here is the test I've been using

class TestDomain
  ROOT_NAMESERVERS = %w[
      a.root-servers.net
      b.root-servers.net
      c.root-servers.net
      d.root-servers.net
      e.root-servers.net
      f.root-servers.net
      g.root-servers.net
      h.root-servers.net
      i.root-servers.net
      j.root-servers.net
      k.root-servers.net
      l.root-servers.net
      m.root-servers.net
    ].freeze

  def name
    "example.com"
  end

  def recursive_query(type, ns: ROOT_NAMESERVERS)
    return [] unless ns.present?

    msg = nil
    puts "Time: #{Benchmark.realtime { msg = resolve_query(type, ns: ns, recurse: false, cache: ROOT_NAMESERVERS.intersect?(ns)) }}"
    return [] unless msg

    # The answer is received.
    return msg.answer.map { |rr| rr.rdata_to_string } if msg.answer.present?

    # Another layer of intermediaries.
    authority = msg.authority.
      find_all { |rr| rr.type == Dnsruby::Types.NS }.
      map(&:rdata).map(&:to_s).reject(&:blank?)
    return [] unless authority.present?

    recursive_query(type, ns: authority)
  end

  private

  def resolve_query(type, ns: nil, recurse: true, cache: true)
    puts "Caching: #{cache} | NS: #{ns.first}"

    resolver = Dnsruby::Resolver.
      new(recurse: recurse, do_caching: cache, retry_times: 2)

    resolver.nameserver = [ns].flatten.shift

    resolver.query(name, type)
  end
end

I tested this from a Rails console environment, and the numbers look strange:

Loading development environment (Rails 8.0.2)
3.4.2 :001 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.12582800001837313
Caching: false | NS: l.gtld-servers.net
Time: 0.12042500008828938
Caching: false | NS: a.iana-servers.net
Time: 0.12831000005826354
 => 0.3755820000078529

3.4.2 :002 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.21918399981223047
Caching: false | NS: l.gtld-servers.net
Time: 0.32541300007142127
Caching: false | NS: a.iana-servers.net
Time: 0.32564599998295307
 => 0.8710799999535084

3.4.2 :003 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.22562899999320507
Caching: false | NS: l.gtld-servers.net
Time: 0.3200809999834746
Caching: false | NS: a.iana-servers.net
Time: 0.3220410000067204
 => 0.8686989999841899

And even if you switch the caching to be always true, it is still kind of slow:

Loading development environment (Rails 8.0.2)
3.4.2 :001 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.1284089998807758
Caching: true | NS: l.gtld-servers.net
Time: 0.12005099980160594
Caching: true | NS: a.iana-servers.net
Time: 0.12974500004202127
 => 0.37913599982857704

3.4.2 :002 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.21118599991314113
 => 0.21136899990960956

3.4.2 :003 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.21160500007681549
 => 0.2118849998805672

I saw this once or twice, which seemed like the cache was hit, but in most cases, it doesn't seem to work.

3.4.2 :002 > Benchmark.realtime { TestDomain.new.recursive_query("NS") }
Caching: true | NS: a.root-servers.net
Time: 0.001236999873071909
 => 0.0012920000590384007

When the cache is cold, the query executed in 0.12582800001837313, with pre-warmed cache, the same query with do_cache: true took 0.21918399981223047 instead of 0.0012920000590384007 (which I saw when the cache actually hit). This is about 170 times slower than expected with a warmed cache.

The next queries also increased from 0.12042500008828938 to 0.32541300007142127, so also around 0.2 seconds slower. It feels that the existing cache adds around 0.2 seconds to each query, even those with do_cache: true.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions